ABOUT ME

생각하는 그것이 미래다

Today
Yesterday
Total
  • [내배캠] tkinter 모듈을 통한 계산기 만들기(Python)
    내일배움캠프/과제 2022. 8. 8. 18:23

     

    에러사항

    더보기

     

    색, 디스플레이바(StringVar) 등이 보이지 않음.

    tkinter의 화면이 고르지 않고 배경과 글자색 등, 설정 값이 mac환경에서 제대로 되지는 않는 것 같았지만 계산기 로직의 흐름을 중점으로 공부하였습니다.

    StringVar가 보이지 않아 결과 값을 print로 찍어가며 확인하여, 번거로움이 있었다

    [DEPRECATION WARNING: The system version of Tk is deprecated and may be removed in a future release. Please don't rely on it. Set TK_SILENCE_DEPRECATION=1 to suppress this warning.]

    TK_SILENCE_DEPRECATION=1 를 추가해주라는 경고가 나와서 구글링을 통해 해결하려 여러 시도를 했으나, 해결이 되지 않았음

     

    (추가)

    -해결 방법-

    python 버전을 낮추면 됩니다.

     

    가상환경에서 바꾸기

    conda create -n 파일이름 python=원하는버전
    conda activate 파일이름

    계산기 코드

    import tkinter as tk
    
    disValue = 0
    operator = {'+':1, '-':2, '/':3, '*':4, 'C':5, '=':6}
    stoValue = 0
    opPre = 0
    
    
    def number_click(value):
        global disValue
        disValue = disValue*10 + value
        str_value.set(disValue)
    
    
    def clear():
        global disValue,stoValue,opPre
        disValue=0
        stoValue=0
        opPre=0
        str_value.set(disValue)
    
    def operator_click(value):
        global disValue,operator,stoValue,opPre
        op = operator[value]
        if op == 5:
            clear()
        elif disValue == 0: #처음 값이 0인 상태에서 op가 들어올 때
            opPre = 0
        elif opPre == 0: #두번째 조건에서 걸리지 않았다면 이전 값이 있음
            opPre = op
            stoValue = disValue
            disValue = 0
            str_value.set(str(disValue))
        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(disValue)
            opPre = 0
            stoValue = 0
            disValue = 0
        else:
            clear()
    
    def button_click(value):
        try:
            value = int(value)
            number_click(value)
        except:
            operator_click(value)
    
    
    win = tk.Tk()
    win.title('계산기')
    
    str_value = tk.StringVar()
    #set 자동으로 업데이트
    str_value.set(str(disValue))
    #그 숫자를 어디에 배치할거냐 justify
    dis = tk.Entry(win, textvariable=str_value, justify='right')
    dis.grid(column=0 , row=0, columnspan = 4, ipadx=80, ipady=30)
    
    
    
    li = '1234567890+-/*C='
    for idx in range(16):
        if li[idx] in '+-/*C=':
            color = 'red'
        else:
            color = 'green'
        btn = tk.Button(win, 
                text=li[idx],
                width=10,
                height=5,
                bg= color,
                padx=10,
                pady=10,
                command= lambda cmd = li[idx] :  button_click(cmd)
                )
        btn.grid(column=idx%4, row = idx//4+1)
    
    win.mainloop()

    계산기의 Button을 만들 때 for문을 살짝 바꿔보았습니다.

    #기존코드
    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))
            
            
    #바꾼코드
    li = '1234567890+-/*C='
    for idx in range(16):
        if li[idx] in '+-/*C=':
            color = 'red'
        else:
            color = 'green'
        btn = tk.Button(win, 
                text=li[idx],
                width=10,
                height=5,
                bg= color,
                padx=10,
                pady=10,
                command= lambda cmd = li[idx] :  button_click(cmd)
                )
                #열은 4로 나눈 나머지 값, 행은 4로 나눈 몫의 값 + 1
        btn.grid(column=idx%4, row = idx//4+1)
    
    win.mainloop()

    기존 코드의 불만 사항:

    1. a+b=c 등 의 단순 계산(a!=0,b!=0)

    2. 계산식에 0이 들어오면 원하는 값이 나오지 않는다.

     

    개산 방안:

    1. a+b-c/s-,,,,(앞에서 부터 순차적으로 계산)

      -연산자 또는 등호를 기준으로 값을 저장, 계산한다.

       1) 이전 연산자가 없고 연산자가 들어왔을 때(처음 연산자가 들어왔을 때)

          이전 값은 0이므로 이전 값에 현재 값을 대입하고, 이전 연산자에 현재 연산자를 대입한다.

       2) 이전 연산자가 있고 연산자가 들어왔을 때

           이전 값과 현재 값을 이전 연산자로 계산, 이전 연산자에 현재 연산자를 대입한다.

       3) 이전 연산자가 없고 등호가 들어왔을 때 (ex - 5 클릭 후 = 클릭)

           현재 값을 출력, 이전 값, 현재 값, 이전 연산자를 초기화

       4) 이전 연산자가 있고 등호가 들어왔을 때

           이전 값과 현재 값을 이전 연산자로 계산, 이전 값, 현재 값, 이전 연산자를 초기화

    2. 0이 들어올 경우 수정

       - 1번 사항에 대부분 포함 된다.

       - 0으로 나눴을 경우 처리

     

    import tkinter as tk
    import operator
    
    
    now_value = 0
    pre_value = 0
    #이전연산자
    op = ''
    ops = {'+':operator.add, '-':operator.sub, '/': operator.truediv,'*': operator.mul}
    #operator.add(a,b) >>> return a+b
    
    def clear():
        global now_value, pre_value, op
        now_value = 0
        pre_value = 0
        op = ''
    
    
    def num_click(value):
        global now_value
        now_value = now_value*10 + value
        display_value.set(now_value)
        print(now_value)
    
    
    def op_click(value):
    
        global now_value, op, pre_value
    
        if value == 'C':
            clear()
    
        if now_value == 0 and op =='/': #0으로 나눌때 에러출력 후 리셋 
            display_value.set('cannot div by 0') 
            now_value = 0
            pre_value = 0
            op = ''
        elif value in '+-/*':
            if op != '': #이전 연산자가 있으면 현재의 값과 이전 값 계산
                now_value = ops[op](pre_value, now_value)
                pre_value = now_value
                op = value
                display_value.set(pre_value)
                now_value = 0
            else: #이전 연산자가 없으면 현재 값을 이전으로 지정 후 리셋, 이전 연산자를 현재 들어온 값으로 지정
                pre_value = now_value
                op = value
                now_value = 0
                display_value.set(now_value)
        elif value == '=':
            if op != '': # 마지막 출력(이전 연산자o)
                now_value = ops[op](pre_value, now_value)
                display_value.set(now_value)
            else: # 이전 연산자 없이 숫자 입력 후 '=' 입력 
                display_value.set(now_value)
            #초기화
            op = ''
            now_value = 0
            pre_value = 0
        #예상하지 못 한 경우의 수에 대한 대비
        else:
            clear()
    
    def button_click(value):
        try:
            value = int(value)
            num_click(value)
        except:
            op_click(value)
        
    
    mac = tk.Tk()
    mac.title('계산기')
    display_value = tk.StringVar()
    display_value.set(now_value)
    display = tk.Entry(mac, textvariable=display_value, justify='right')
    display.grid(column=0 , row=0, columnspan = 4, ipadx=80, ipady=30)
    
    
    li = '1234567890+-/*C='
    for idx in range(16):
        if li[idx] in '+-/*C=':
            color = 'red'
        else:
            color = 'green'
        btn = tk.Button(mac, 
                text=li[idx],
                width=10,
                height=5,
                bg= color,
                padx=10,
                pady=10,
                command= lambda cmd = li[idx] :  button_click(cmd)
                )
        btn.grid(column=idx%4, row = idx//4+1)
    
    
    mac.mainloop()

    출처 

    https://blog.naver.com/cflab/221965735770

     

    파이썬 기초 GUI 계산기 만들기 :: tkinter

    [프로그래밍언어] 파이썬 기초 GUI 계산기 만들기 :: tkinter 20년 개발 경력자의 블로그 입니다. #파이...

    blog.naver.com

     

    댓글

Designed by Tistory.