[코딩나우]계산기 만들기

2022. 8. 19. 11:09ㆍ코딩나우[파이썬]/계산기만들기

1.목표 : 파이썬문법으로 GUI계산기를 만들어 보자.

 

2.기본 세팅

test.py에서 만들기(vscode이용)

 

3.코딩

1)import tkinker(파이선에서 기본으로 제공하는 것 사용)

★code

import tkinker as tk

win = tk.Tk()

win.title(‘계산기’)

 

win.mainloop()

tk는 tk라는 함수를 가지고옴. 이렇게 되면 class가 자동으로 생성됨. 받아온 변수에 title을 넣음.

위의 code를 실행하면, 계산기라는 작은 창이 뜸.

2)계산기를 만들기 위해 숫자 버튼이 필요. 숫자는 버튼 형태이기 때문에

★code

tk.Button(win, text=’1‘, width=10, height=5)

btn.pack()

하면 버튼이 형성됨. 근데 우리는 버튼을 계산기 모양으로 배치해야하기 때문에 pack이 아니라 grid를 사용.

★code

tk.Button(win, text=’1‘, width=10, height=5)

btn.grid(column=0,row=1)

를 해줘야하는데 몇 개를 더 만들어 줌.

tk.Button(win, text=’1‘, width=10, height=5)

btn.grid(column=0,row=1)

tk.Button(win, text=’2‘, width=10, height=5)

btn.grid(column=1,row=1)

tk.Button(win, text=’3‘, width=10, height=5)

btn.grid(column=2,row=1)

tk.Button(win, text=’4‘, width=10, height=5)

btn.grid(column=4,row=1)

하면 1줄로로 1,2,3,4 버튼이 만들어짐.

+)grid는 한줄 띄우고 아래에 btn.grid(column=0,row=1)적는 대신에

tk.Button(win, text=’1‘, width=10, height=5).grid(column=0,row=1)로 해줘도 잘 작동됨.

3)4*4짜리 계산기 모양틀 만들기 시작.

★code

import tkinter as tk

 

win = tk.Tk()

win.title('계산기')

 

tk.Button(win, text='1', width=10, height=5).grid(column=0, row=1)

tk.Button(win, text='2', width=10, height=5).grid(column=1, row=1)

tk.Button(win, text='3', width=10, height=5).grid(column=2, row=1)

tk.Button(win, text='4', width=10, height=5).grid(column=3, row=1)

 

 

tk.Button(win, text='5', width=10, height=5).grid(column=0, row=2)

tk.Button(win, text='6', width=10, height=5).grid(column=1, row=2)

tk.Button(win, text='7', width=10, height=5).grid(column=2, row=2)

tk.Button(win, text='8', width=10, height=5).grid(column=3, row=2)

 

 

tk.Button(win, text='9', width=10, height=5).grid(column=0, row=3)

tk.Button(win, text='0', width=10, height=5).grid(column=1, row=3)

tk.Button(win, text='+', width=10, height=5).grid(column=2, row=3)

tk.Button(win, text='-', width=10, height=5).grid(column=3, row=3)

 

tk.Button(win, text='/', width=10, height=5).grid(column=0, row=4)

tk.Button(win, text='*', width=10, height=5).grid(column=1, row=4)

tk.Button(win, text='C', width=10, height=5).grid(column=2, row=4)

tk.Button(win, text='=', width=10, height=5).grid(column=3, row=4)

 

 

win.mainloop()

하면 4*4 사이즈의 계산기 모양이 완성됨.

4)창의 맨 위에 edit창을 넣기.edit창은 계산기 버튼 만들어 놓은 위에 버튼을 눌러서 입력한 것을 출력하는 창이라고 생각하면 됨.  edit창은 entry를 사용. tk.Entry(win, textvariable=) 어떤 값을 넣는건데 결과값이 계속 변화가 되어야함. 수를 누르면 숫자, =을 누르면 결과 등이 나와야함.

★code

disValue = 0

str_Value= tk.StringVar()

str_Value.set(str(disValue))

tk.Entry(win, textvariable=str_value, justify=’right‘)

-disValue = 0 결과에 대해서 변수를 0으로 받아 주겠다는 것임. 결과는 문자로 반환해줘야 함.

-str_value =tk.StiringVar() 으로 받아주겠음.

-str_value.set(str(disValue))는 tk에 stirngVar()라는 것을 생성했고, 거기에 값을 넣어주면 disValue은 정수인데 이것을 문자로 변환(str)해서 set을 해주면 이것을 textvariable=뒤에 넣어줌. 그러면 edit창에 자동으로 업데이트가 됨.

-justify는 그 숫자를 어디에 배치할 것인지 결정하는 것. 마찬가지로 마지막에 dis로 받아야 하고 dis.grid(column=0, row=0)과 같이 어디에 들어갈지 정해줘야함.

그러면 첫 번째 열이 정형화되지 않은채로 출력됨. 결과값이 도출되는 곳이 간격이 좀 넓어져서 첫 번째 열과 옆에 간격이 벌어짐. 해결하기 위해서는 columnspan을 사용. 이것은 column의 사이즈를 몇 개를 가져 갈건지 쓰는 것. 그럼 이 칸이 4개의 열을 사용해준다고 치면 맨위 네 개열 만큼의 길이로 창이 형성됨. ->dis.grid(column=0, row=0, columnspan=4)

그런데 너무 작고 가운데 있으니 이 크기를 조정하려면 dis.grid(column=0, row=0, columnspan=4, ipadx=80, ipady=30)해주면 결과 나오는 창이 커짐.

5)for loof 사용(코드를 간단하게 나타내기)

이 코드 전체를 보면 너무 김(tk부분이 같은 부분이 많고 계속 반복됨). 그래서 우리는 for loop를 사용

for loop를 사용하기 위해서 먼저 레이블을 배열형태로 만들어 볼 것. caItem 이라는 변수를 선언

calItem = [[‘1’,‘2’,‘3’,‘4’]

                 [‘5’,‘6’,‘7’,‘8’]

                 [‘9’,‘0’,‘+’,‘-’]

                  [‘/’,‘*’,‘C’,‘=’]]

for i, items in enumerate(calItem):

으로 해주면 calitem의 인덱스가 번호로 들어가주고, 하나의 리스트가 item에 들어가줌.

다중 for 문을 이용해서 for k, time in enumerate(Items):

bt라는 변수에 다른 것을 선언

bt=tk.Button(win, text=item, width=10, height=5)

bt.grid(column=k, row=(i+1))

근데 I가 맨위에 edit창이 있기 때문에 row에서는 0부터가 아니라 i+1을 해주고 밑에 복잡하게 중복되는 부분은 주석처리하면 동일하게 작동. 이러면 매우 간결하게 표현되고 작업하기가 수월한 상태가 됨.

*주석달기 : 'ctrl + /' 인데 안될경우, 'ctrl+shift'해서  

6)색 넣기

★code

for i, items in enumerate(calItem):

for k, item in enumerate(items):

bt = tk.Button(win,

text=item,

width=10,

height=5)

bt.grid(column=k, row=(i+1))

이렇게 따로 구분되게 써준 후 height 아래에 bg= ‘black’ 써주면 배경색, fg='green'해주면 폰트색이 변경됨. 여기에 entry도 색을 바꿔줄 수 있음.

dis = tk.Entry(win, textvariable=str_value, justify='right', fg=’red‘)하면 폰트색이 변경됨(bg할 경우도 색 변함) 그런데 우리는 여기서 숫자와 연산을 다르게 넣고 싶을 때 약간의 꼼수를 사용해야함.

★code

import tkinter as tk

 

win = tk.Tk()

win.title('계산기')

 

disValue = 0

str_value = tk.StringVar()

str_value.set(str(disValue))

dis = tk.Entry(win, textvariable=str_value, justify='right', fg='red')

dis.grid(column=0, row=0, columnspan=4, ipadx=80, ipady=30)

 

calItem = [['1','2','3','4'],

['5','6','7','8'],

['9','0','+','-'],

['/','*','C','=']]

 

for i, items in enumerate(calItem):

for k, item in enumerate(items):

 

try :

color = int(item)

color = ‘black’

except:

color = ‘green’

 

bt = tk.Button(win,

text=item,

width=10,

height=5,

bg = 'color',

fg='green'

)

bt.grid(column=k, row=(i+1))

try 이용해서 bg에  color를 주고 fg는 whtie로 줌. 이때 try 이하 color는 약간의 꼼수인데 color=int(item)해주면 정수일경우는 color가 black으로 나오고 그게 아닐 경우는 green으로 표현한다는 식으로 해석하면 됨. 여기서 bt로가서 bg를 color로 지정해주면 정수부분은 검은색, 나머지는 초록색임을 확인 할 수 있음. 그러면 GUI 형태는 구성됨.

7)누를 때 연산을 해주고 결과를 출력해주게끔 해보기.

-먼저 버튼을 누를 때 액션을 처리해줌. 버튼 클릭에 대한 변수를 만들어줌. 변수는 맨 위로 올려서 다 쓸거니까 정리. 함수를 만들어야하니까

★code

def button_click(value):

print(value)

그러면 버튼이 눌릴때마다 작동해야하니까 bt.tk(fg)밑에 command=button_click()이라는 함수를 넣어주면 버튼이 호출됨. 이때 터미널창을 보면 버튼이 호출되어야하는데 우리가 인자를 안넣어줬음. 그래서 인자가 필요 없는 경우에는 value이라는 값이 계속 출력되는 것을 확인할 수 있음. 우리는 def button에 어떤 것이 눌렸다는 것을 알아야하니, command=button_click을 좀더 수정을 함. 파이선에서 사용하는 lambda라는 것이 있는데

command =lambda cmd=item: button_click(cmd)라고 해주면 됨.  lambda라고 간이함수를 item이라고 받아온 것에 cmd라는 변수에 넣고 변수를 button에 인자로 넣어주는 것임. 누를 때 터미널 확인하면 버튼이 출력되는 것을 확인할 수 있음. 그럼 입력까지 됐고 다음으로 출력하면 됨. 여기서 숫자와 연산을 나눠야하니까 try를 활용

try:

value = int(value)

number_click(value)

except:

operator_click(value)

이때 숫자일 경우 number이라는 함수를 정의하고 숫자일 경우 number함수를 받도록 해줌.

★code

def number_click(value):

print(‘숫자’,value)

밑에 연산은 def operator_click(value):

print(‘명령’,value)

하면 각자 숫자 1 / 명령 + 같은 방식으로 찍힘.

이제 global 해서 변수를 가지고옴.

global disValue

disValue = (disValue*10) + value

str_value.set(disValue)

해주면 찍을때마다 10을 곱해주는 거라고 생각해서 1다음 2클릭하면 1에 10을 곱하고 2를 더한다고 생각하면 되고, 123이면 1다음 10을 곱한것에 또 10을 곱해주고 2에도 10을 곱하고 3을 더한다 이런식으로 생각해주면 됨. 10을 12345569 차례대로 하나씩 올라가지는 것을 확인할 수 있음.

이제 명령을 처리. 현재 눌린 것과 이전에 눌린 명령이 무엇인지 알아야 계산을 할 수 있음. 변수가 필요함.

disValue = 0

operator ={‘+’:1,‘-’:2,‘/’:3,‘*’:4,‘C’:5,‘=’:6}

stoValue = 0

opPre = 0

dis밑에 operator ={‘+’:1,‘-’:2,‘/’:3,‘*’:4,‘C’:5,‘=’:6}과 같이 명령을 정수로 치환. 그다음 숫자로 들어온 값과 연산을 더하기를 할 것인지 빼기를 할 것인지 확인하기 위해 변수를 하나 더 줌. stoValue =0해주고 마지막으로 opPre = 0 이라고해서 이전 연산이 무엇인지 보기 위해 변수를 하나 더 선언.

operator 함수에 위에 정의한 것들을 다 가져옴.

★code

def operator_click(value)

#print(‘명령’, value)

global disValue, operator, stoValue, opPre

op = operator[value]

if op == 5: # C

 

opPre = op

*5를 쓴 이유는 c값을 위에서 5로 지정해줬기 때문에

8)C버튼 코딩(다 지우기)

★code

def clear():

stoValue = 0

opPre = 0

disValue = 0

str_value.set(disValue)

하면 다 지워짐. 지워지긴 하는데 다시 다른 수 누르면 남아있는 것을 확인할 수 있음. 전역변수를 갖다쓴 것이 아니라 함수 내 변수를 새로 선언해서 쓴것이라 전역변수를 넣어줘야함. 'def clear():'의 아랫줄에 global disValue, operator, stoValue, opPre 넣어주면 아예 리셋되는 것을 알 수 있음.

아무것도 누르지 않았을 경우

★code

def operator_click(value)

#print(‘명령’, value)

global disValue, operator, stoValue, opPre

op = operator[value]

if op == 5: # C

clear()

elif disValue == 0:

opPre = 0

elif opPre ==0:

stoValue = disValue

disValue = 0

str_value.set(str(disValue))

하면 연산할 때 edit창에는 0으로 출력은 되는데 이때 이전에 입력했던 숫자값은 저장이 됨. 그리고 연산을 해야함. 6은 =을 눌렀을 때임을 표현하기 때문에 밑에 이어서

★code

elif op == 6: #=

if opPre == 1:

disValue = stoValue + disValue

 

str_value.set(str(disValue))

 

opPre = op

해준다. 만약 더하기 일 때 앞에 저장한 값과 현재 입력한 값을 더해서 나온 값을 출력해준다고 이해하면됨. 그러면 그 밑에 이어서 나머지 연산들도 적용해주면 끝.

if opPre == 1:

disValue = stoValue + disValue

if opPre == 2:

disValue = stoValue - disValue

if opPre == 3:

disValue = stoValue / disValue

if opPre == 4:

disValue = stoValue * disValue

적용하면 잘 작동됨. 그런데 결과값이 3이 나온 후 다음 계산을 위해 2를 입력하면 32 이렇게 출력됨. 이것을 초기화 해주어야 하는데 입력값, 저장됐던 값을 다 0으로 만들어줌.

if opPre == 1:

disValue = stoValue + disValue

if opPre == 2:

disValue = stoValue - disValue

if opPre == 3:

disValue = stoValue / disValue

if opPre == 4:

disValue = stoValue * disValue

의 밑에

str_value.set(str(disValue))

disvalue = 0

stoValue = 0

해주면 되는데, 이렇게 해도 안 됨. 밑에 opPre =op 때문에. 그래서 이것을 elif disValue ==0: 밑으로 보내준 후 opPre = 0으로 바꿔줘야 함. 그리고 맨 밑에 opPre = 0을 추가해줌. 그리고 이상 동작이 있을 경우 맨 밑에

else:

clear()를 넣어주면 끝.

 

★최종 소스 code

import tkinter as tk

 

disValue = 0

operator = {'+':1, '-':2, '/':3, '*':4, 'C':5, '=':6}

stoValue = 0 opPre = 0 ### 0~9까지의 숫자를 클릭했을때

 

def number_click(value): # print('숫자 ',value)

global disValue disValue = (disValue*10) + value #숫자를 클릭할때마다 10의 자리씩 이동한다.

str_value.set(disValue) #화면에 숫자를 나타낸다. ### C를 클릭하여 clear할때

 

def clear(): global disValue, stoValue, opPre #주요 변수 초기화

stoValue = 0

opPre = 0

disValue = 0

str_value.set(str(disValue)) #화면을 지운다.

 

### + ~ = 연산자를 클릭했을때 def oprator_click(value): # print('명령 ', value)

global disValue, operator, stoValue, opPre #value의 값에 따라 숫자로 연산자를 변경한다.(+는 1로, -는 2로..)

op = operator[value] if op == 5: # C (clear)

clear() elif disValue == 0: #현재 화면에 출력된 값이 0일때

opPre = 0 elif opPre == 0: #연산자가 한번도 클릭되지 않았을때

opPre = op #현재 눌린 연산자가 있으면 저장

stoValue = disValue #현재까지의 숫자를 저장

disValue = 0 #연산자 이후의 숫자를 받기 위해 초기화

str_value.set(str(disValue)) #0으로 다음 숫자를 받을 준비

 

elif op == 6: #'= 결과를 계산하고 출력한다.

if opPre == 1: # +

disValue = stoValue + disValue

if opPre == 2: # - disValue = stoValue - disValue

if opPre == 3: # / disValue = stoValue / disValue

if opPre == 4: # * disValue = stoValue * disValue str_value.set(str(disValue)) #최종 결과 값을 출력한다.

disValue = 0

stoValue = 0

opPre = 0

else: clear()

 

def button_click(value): # print(value) try: value = int(value) #정수로 변환한다. #정수가 아닌 경우 except가 발생하여 아래 except로 이동한다.

number_click(value) #정수인 경우 number_click( )를 호출

except: oprator_click(value) #정수가 아닌 연산자인 경우 여기로!!

 

win = tk.Tk() win.title('계산시') str_value = tk.StringVar() str_value.set(str(disValue))

dis = tk.Entry(win, textvariable=str_value, justify='right', bg = 'white',fg='red') dis.grid(column=0, row=0, columnspan=4, ipadx=80, ipady=30)

calItem = [['1','2','3','4'], ['5', '6', '7', '8'], ['9', '0', '+', '-'], ['/', '*', 'C', '=']]

for i,items in enumerate(calItem): for k,item in enumerate(items):

try: color = int(item) color = 'black' except: color = 'green'

bt = tk.Button(win, text=item, width=10, height=5, bg=color, fg = 'white', command = lambda cmd=item: button_click(cmd) ) bt.grid(column=k, row=(i+1))

 

win.mainloop()

 

 

 

+)파이썬 sytax오류 해결

터미널에서 >>> 아래에 exit() 또는 crtrl+z하고 엔터하면 해결됨.