INJE BLOG

WASTING YOUR TIME

SINCE 2017

파이썬 GUI 계산기

INJE KIM code/python | 2017. 5. 26. 13:24

제목에서 보시다시피 이번엔 Tkinter 를 이용한 gui 계산기를 만들어 보겠습니다.

일단 작동 화면부터 보고 시작해 볼까요?




자, 이제 본격적으로 시작해 봅시다.


저는 이 프로그램을 3 파트로 나누어 작성했는데요.


다른 클래스들을 불러와 실행시키는 Main, gui 를 담당하는 Graphic_Interface

그리고 계산 부분을 담당하는 Calculator 클래스 이렇게 나누어 작성하였습니다.


Main 클래스는 크게 중요한 역할이 없으니 재쳐두고,

Graphic_Interface 클래스 부터 한번 살펴봅시다.


Graphic_Interface 클래스는 layout 함수 하나로만 구성되어 있는데요.

예상 하셨겠지만 layout 함수는 gui 형태를 구성하는 역할을 합니다.


한번 보실까요?

class Graphic_Interface:
    def layout(self):
        # values
        self.button_width=3 # width of buttons
 
        # display
        self.display=Entry(justify="right", width=17)
        self.display.grid(row=0, column=0, columnspan=3)
 
        # AC button
        self.button_ac=Button(
        text="AC",
        width=self.button_width,
        command=self.reset)
        self.button_ac.grid(row=0, column=3)

(너무 길어서 전부 가져오진 않았습니다...)


다 아시겠지만, 몇몇 옵션들만 짚어 보자면

justify="right"

는 Entry 의 텍스트를 오른쪽 정렬 해주는 옵션이고

columnspan=3

는 grid 에서 가로로 3 칸을 차지하게 해주는 옵션입니다.

(위에 작동화면을 보시면 이해가 빠르실 겁니다.)



자, 이제 제일 중요한 부분인 Calculator 클래스를 볼까요?

Calculator 클래스는 init 함수를 포함해 7개의 함수로 구성되어 있는데요.


함수들을 보기 전에 작동 순서부터 살펴봅시다.

이해가 되시나요?


두 갈래로 갈라지는 이유는 계산 후 '=' 이 아니라 다른 계산 부호를 눌러도,

계속 계산이 되도록 하기 위해서 입니다.


자, 이제 함수 한개를 예시로 볼까요?

def clear_display(self):
    # clear display
    self.display.delete(0, 'end')

보시면 Graphic_Interface 클래스에 있는 display 변수를 사용하는 것을 알 수 있는데요.

이것은 Calculator 클래스가 Graphic_Interface 클래스를 상속받기 때문에 가능합니다.


어떻게 상속받는지 한번 볼까요?

class Calculator(Graphic_Interface):
    def __init__(self):
        self.layout()
        self.refresh_display('0')
 
        # values
        self.first=1 # indecates first input
        self.symbol="" # current calculating symbol

이렇게, 클래스 이름 옆에 괄호로 상속받을 클래스를 입력해 상속받습니다.

이런식으로 상속을 받게 되면 그 클래스 안에 메소드와 변수들을 이용할 수 있게 됩니다.


이제 전체 코드와 계산 순서별 사용되는 함수를 알려드리고 마치도록 하겠습니다.


# 숫자입력 - add_to_display()

# 부호선택 - pre_calculate()

# "=" 선택 - post_calculate()

# "AC" 선택 -  reset()



#/////////////////////////////////////////////////////////////////////////
#TKalc Copyright (c) 2017 Copyright Inje Kim All Rights Reserved.
#/////////////////////////////////////////////////////////////////////////

from tkinter import *

# Main Class
class Main:
    def __init__(self, master):
        self.calc=Calculator()

# Graphic_Interface class
class Graphic_Interface:
    def layout(self):
        # values
        self.button_width=3 # width of buttons

        # display
        self.display=Entry(justify="right", width=17)
        self.display.grid(row=0, column=0, columnspan=3)

        # AC button
        self.button_ac=Button(
        text="AC",
        width=self.button_width,
        command=self.reset)
        self.button_ac.grid(row=0, column=3)
        # 7 button
        self.button_7=Button(
        text="7",
        width=self.button_width,
        command=lambda:self.add_to_display("7"))
        self.button_7.grid(row=1, column=0)
        # 8 button
        self.button_8=Button(
        text="8",
        width=self.button_width,
        command=lambda:self.add_to_display("8"))
        self.button_8.grid(row=1, column=1)
        # 9 button
        self.button_9=Button(
        text="9",
        width=self.button_width,
        command=lambda:self.add_to_display("9"))
        self.button_9.grid(row=1, column=2)
        # \ button
        self.button_d=Button(
        text="/",
        width=self.button_width,
        command=lambda:self.pre_calculate("/"))
        self.button_d.grid(row=1, column=3)
        # 4 button
        self.button_4=Button(
        text="4",
        width=self.button_width,
        command=lambda:self.add_to_display("4"))
        self.button_4.grid(row=2, column=0)
        # 5 button
        self.button_5=Button(
        text="5",
        width=self.button_width,
        command=lambda:self.add_to_display("5"))
        self.button_5.grid(row=2, column=1)
        # 6 button
        self.button_6=Button(
        text="6",
        width=self.button_width,
        command=lambda:self.add_to_display("6"))
        self.button_6.grid(row=2, column=2)
        # * button
        self.button_t=Button(
        text="*",
        width=self.button_width,
        command=lambda:self.pre_calculate("*"))
        self.button_t.grid(row=2, column=3)
        # 1 button
        self.button_1=Button(
        text="1",
        width=self.button_width,
        command=lambda:self.add_to_display("1"))
        self.button_1.grid(row=3, column=0)
        # 2 button
        self.button_2=Button(
        text="2",
        width=self.button_width,
        command=lambda:self.add_to_display("2"))
        self.button_2.grid(row=3, column=1)
        # 3 button
        self.button_3=Button(
        text="3",
        width=self.button_width,
        command=lambda:self.add_to_display("3"))
        self.button_3.grid(row=3, column=2)
        # - button
        self.button_m=Button(
        text="-",
        width=self.button_width,
        command=lambda:self.pre_calculate("-"))
        self.button_m.grid(row=3, column=3)
        # 0 button
        self.button_0=Button(
        text="0",
        width=self.button_width,
        command=lambda:self.add_to_display("0"))
        self.button_0.grid(row=4, column=0)
        # . button
        self.button_dot=Button(
        text=".",
        width=self.button_width,
        command=lambda:self.add_to_display("."))
        self.button_dot.grid(row=4, column=1)
        # = button
        self.button_e=Button(
        text="=",
        width=self.button_width,
        command=self.post_calculate)
        self.button_e.grid(row=4, column=2)
        # + button
        self.button_p=Button(
        text="+",
        width=self.button_width,
        command=lambda:self.pre_calculate("+"))
        self.button_p.grid(row=4, column=3)

# Calculator class
class Calculator(Graphic_Interface):
    def __init__(self):
        self.layout()
        self.refresh_display('0')

        # values
        self.first=1 # indecates first input
        self.symbol="" # current calculating symbol

    # clear display
    def clear_display(self):
        self.display.delete(0, 'end') # clear display

    # replace text on display
    def refresh_display(self, text):
        self.clear_display() # clear display
        self.display.insert(0, text) # add text to display

    # reset display
    def reset(self):
        if self.display.get()=="0": # AC
            self.symbol=""
        self.refresh_display("0") # replace text in display to 0
        self.button_ac["text"]="AC" # replace text in button_ac to AC

    # add to existing text in display
    def add_to_display(self, text):
        current=self.display.get() # get text from display
        if current=="0" and text!=".": # remove 0 when adding numbers
            current=""
        if "." in current and text==".": # prevent more then one dots
            text=""
        if self.first==0: # initial input
            self.first=1
            self.refresh_display(text)
        else: # after the initial input
            self.refresh_display(current+text)
        self.button_ac["text"]="C"

    # after pressing symbol keys
    def pre_calculate(self, symbol):
        if self.symbol!="": # continuous calculation
            self.pre=self.post_calculate()
        else: # initial calculation
            self.pre=float(self.display.get())
        self.first=0
        self.symbol = symbol

    # after pressing equals key
    def post_calculate(self):
        if self.symbol!="":
            self.post=float(self.display.get())
            result = { # calculation cases
            '/': lambda : self.pre/self.post,
            '*': lambda : self.pre*self.post,
            '+': lambda : self.pre+self.post,
            '-': lambda : self.pre-self.post
            }[self.symbol]()
            if result%1==0: # remove .0
                result=int(result)
            self.refresh_display(result)
            self.symbol=""
            self.first=0 # reverts indicator
            return result

# Initialize Tkinter
root = Tk()
root.title("TKalc ver 1.2")
root.configure(padx=5, pady=5)
Main(root)
root.mainloop()

gui_calc.py


유용하셨으면 공감버튼 부탁드려요!