Develop Knowledge/Python GUI by 나도코딩

T-kinter를 이용한 Python GUI 프로그래밍 기초 개념

정수열 2023. 2. 19. 17:50

본 글은 인프런에 있는 "나도코딩" 님의 "파이썬 무료 강의 (활용편2) - GUI 프로그래밍 (4시간)" 글에서 설명한 내용을 간단히 개념만 정리한 글입니다.

무료로 강의를 볼 수 있으니, 동영상으로 보실분들은 이걸로 보시면 되겠습니다.

다만, 템포가 조금 빠릅니다..

https://www.inflearn.com/course/%EB%82%98%EB%8F%84%EC%BD%94%EB%94%A9-%ED%8C%8C%EC%9D%B4%EC%8D%AC-%ED%99%9C%EC%9A%A9%ED%8E%B8-2/dashboard

 

[무료] 파이썬 무료 강의 (활용편2) - GUI 프로그래밍 (4시간) - 인프런 | 강의

파이썬을 활용하여 GUI 프로그래밍을 배우고 여러 이미지를 합치는 유용한 프로그램을 함께 만듭니다., - 강의 소개 | 인프런

www.inflearn.com

 

 

- Tkinter란?

Tkinter는 파이썬 표준 라이브러리중 하나로, 간단한 GUI 프로그래밍을 해주는 역할을 합니다.

본 글에서는 위의 영상에서 작성한 코드를 여기에 나열하는 방식으로 진행합니다.

이 글은 강의를 다 들은 후에 참고용으로만 사용해주시길 바라며, 학습을 위해서는 동영상을 보시면서 공부하시는걸 추천드립니다.

 

- 1. 창 생성

from tkinter import *

# 인스턴스(?) 생성
root = Tk()

# 프레임 관련 설정
root.title("Nado GUI") # 제목
root.geometry("640x480") # 크기
#root.geometry("640x480+300+100") # 크기 + x좌표 + y좌표
root.resizable(False, False) # x, y 창 크기 변경을 불가시킨다.

# 창 실행
root.mainloop() # 창이 닫히지 않도록 해주는 역할을 해준다.

 

- 2. 버튼 생성

from tkinter import *

root = Tk()
root.title("Nado GUI")

# 버튼(위젯) 관련 설정

# 버튼 생성
btn1 = Button(root, text="버튼1")
btn1.pack()

# 내부 크기 설정
btn2 = Button(root, padx=5, pady=10, text="버튼2")
btn2.pack()
btn3 = Button(root, padx=10, pady=5, text="버튼3")
btn3.pack()

# 외부 크기 설정
btn4 = Button(root, width=10, height=3, text="버튼4")
btn4.pack()

# 글자 색상, 버튼 색상
btn5 = Button(root, fg="red", bg="yellow", text="버튼5")
btn5.pack()

# 이미지를 버튼으로 사용하기
photo = PhotoImage(file="image.png")
btn6 = Button(root, image=photo)
btn6.pack()

# 특정 함수 실행하기
def btncmd():
    print("버튼이 클릭되었어요.")
btn7 = Button(root, text="동작하는 버튼", command=btncmd)
btn7.pack()

root.mainloop()

 

- 3. 레이블 생성

레이블은 텍스트와 그림을 띄우는 것을 의미한다.

from tkinter import *

root = Tk()
root.title("Nado GUI")

# 레이블 설정
# 레이블 : 글자나 그림을 보여주는 기능

# 글자 보여주기
label1 = Label(root, text="안녕하세요")
label1.pack()

# 그림 보여주기
photo = PhotoImage(file="image.png")
label2 = Label(root, image=photo)
label2.pack()

# 버튼을 눌렀을 떄 레이블을 바꿔보기
def change():
    # 텍스트
    label1.config(text="또 만나요") #config는 바꿀 것을 정한다.

    #이미지
    global photo2 #garbage collection 떄문에 반드시 전역변수로 만들어줄것!!
    photo2 = PhotoImage(file="image2.png")
    label2.config(image=photo2)

btn = Button(root, text="클릭", command=change)
btn.pack()

root.mainloop()

 

- 4. 텍스트 여러줄 입력, 텍스트 한 줄(엔트리) 입력

from tkinter import *

root = Tk()
root.title("Nado GUI")

# 텍스트 위젯 관련 설정
# 여러줄의 텍스트를 입력받을 수 있다.
txt = Text(root, width=30, height=5)
txt.pack()

# 텍스트 입력
# insert(글자를 입력할 줄 수.글자 입력할 문자 위치, "입력값")
# insert(END, "입력값") 은 자동으로 마지막에 입력값을 넣어준다.
txt.insert(END, "글자를 입력하세요")

# 엔트리 관련 설정
# 한 줄의 텍스트를 입력받을 수 있다.
e = Entry(root, width=30)
e.pack()
e.insert(0, "한 줄만 입력하세요")

# ----------------------------
# 텍스트 위젯과 엔트리 다뤄보기
def btncmd():
    # 텍스트를 가져오기
    # 1.0 : 첫번째 라인의 0번째 인덱스
    # END : 끝의 인덱스.
    print(txt.get("1.0", END))

    # 엔트리를 가져오기
    print(e.get())

    # 텍스트와 엔트리 내용 삭제해보기
    txt.delete("1.0", END)
    e.delete(0, END)


btn = Button(root, text="클릭", command=btncmd)
btn.pack()

root.mainloop()

 

- 5. 리스트박스

from tkinter import *

root = Tk()
root.title("Nado GUI")

# 리스트 박스
listbox = Listbox(root, selectmode="extended", height=0)
listbox.insert(0, "사과")
listbox.insert(1, "딸기")
listbox.insert(2, "바나나")
listbox.insert(END, "수박")
listbox.insert(END, "포도")
listbox.pack()

def btncmd():
    # 삭제
    #listbox.delete(0)

    # 개수 확인
    #print("리스트에는", listbox.size(), "개가 있습니다.")

    # 항목 확인
    #print("1번째부터 3번째까지의 항목 : ", listbox.get(0, 2))

    # 선택된 항목을 인덱스로 확인
    print("선택된 항목 : ", listbox.curselection())

btn = Button(root, text="클릭", command=btncmd)
btn.pack()

root.mainloop()

 

- 6. 체크박스

from tkinter import *

root = Tk()
root.title("Nado GUI")

# 체크박스 관련 설정
#chkvar 에 int 형으로 값을 저장한다.
chkvar = IntVar()
#chkbox 위젯. variable은 결과값을 나타낼 자료형을 나타낸다.
chkbox = Checkbutton(root, text="오늘 하루 보지 않기", variable=chkvar)
# chkbox.select() # 자동 선택 처리
# chkbox.deselect() # 선택 해제 처리
chkbox.pack()

chkvar2 = IntVar()
chkbox2 = Checkbutton(root, text="일주일동안 보지 않기", variable=chkvar2)
chkbox2.pack()

def btncmd():
    print(chkvar.get()) # 0 : 체크 헤제, 1 : 체크
    print(chkvar2.get())

btn = Button(root, text="클릭", command=btncmd)
btn.pack()

root.mainloop()

 

- 7. 라디오 버튼

from tkinter import *

root = Tk()
root.title("Nado GUI")

# radiobutton 관련 설정
# 여러개 중에서 한개를 선택하는 위젯이다.
Label(root, text="메뉴를 선택하세요").pack()

burger_var = IntVar() # 여기에 int 형으로 값을 저장한다.
btn_burger1 = Radiobutton(root, text="햄버거", value=1, variable=burger_var)
btn_burger1.select() # 기본값 선택
btn_burger2 = Radiobutton(root, text="치즈버거", value=2, variable=burger_var)
btn_burger3 = Radiobutton(root, text="치킨버거", value=3, variable=burger_var)
btn_burger1.pack()
btn_burger2.pack()
btn_burger3.pack()

Label(root, text="음료를 선택하세요").pack()

drink_var = StringVar()
btn_drink1 = Radiobutton(root, text="콜라", value="콜라", variable=drink_var)
btn_drink1.select()
btn_drink2 = Radiobutton(root, text="사이다", value="사이다", variable=drink_var)
btn_drink1.pack()
btn_drink2.pack()

def btncmd():
    print(burger_var.get()) # 햄버거 중 선택된 라디오 항목의 값(value)
    print(drink_var.get()) # 음료 중 선택된 값을 출력

btn = Button(root, text="주문", command=btncmd)
btn.pack()

root.mainloop()

 

- 8. 콤보박스

import tkinter.ttk as ttk # 주의!!
from tkinter import *

root = Tk()
root.title("Nado GUI")

# combobox 관련 설정
# 목록을 펼치고, 그중에서 하나를 선택하는 방식이다.
values = [str(i) + "일" for i in range(1, 32)] # 1 ~ 31일
combobox = ttk.Combobox(root, height=5, values=values)
combobox.pack()
combobox.set("카드 결제일") # 최초 목록 제목 설정

readonly_combobox = ttk.Combobox(root, height=5, values=values, state="readonly")
readonly_combobox.current(0) # 0번째 인덱스를 제목으로 설정
readonly_combobox.pack()

def btncmd():
    print(combobox.get()) #선택된 값 표시
    print(readonly_combobox.get())

btn = Button(root, text="선택", command=btncmd)
btn.pack()

root.mainloop()

 

- 9. 진행 창

import tkinter.ttk as ttk # 주의!!
from tkinter import *

import time

root = Tk()
root.title("Nado GUI")

# progressbar 관련 설정
#progressbar = ttk.Progressbar(root, maximum=100, mode="indeterminate") #미결정 모드
# progressbar = ttk.Progressbar(root, maximum=100, mode="determinate") #결정 모드
# progressbar.start(10) # 10ms마다 움직임.
# progressbar.pack()
#
#
# def btncmd():
#     progressbar.stop()
#
# btn = Button(root, text="중지", command=btncmd)
# btn.pack()

p_var2 = DoubleVar()
progressbar2 = ttk.Progressbar(root, maximum=100, length=150, variable=p_var2)
progressbar2.pack()

def btncmd2():
    for i in range(1, 101):
        time.sleep(0.01)

        p_var2.set(i) # progress bar의 값 설정
        progressbar2.update() # UI 업데이트
        print(p_var2.get())

btn = Button(root, text="시작", command=btncmd2)
btn.pack()

root.mainloop()

 

- 10. 메뉴

from tkinter import *

root = Tk()
root.title("Nado GUI")

# 함수 모음
def create_new_file():
    print("새 파일을 만듭니다.")
# menu 관련 설정
# 메뉴 대항목 만들기
menu = Menu(root)

# File 메뉴
menu_file = Menu(menu, tearoff=0) # 메뉴 하위 목록 생성
menu_file.add_command(label="New File", command=create_new_file)
menu_file.add_command(label="New Window")
menu_file.add_separator()
menu_file.add_command(label="Open File...")
menu_file.add_separator()
menu_file.add_command(label="Save All", state="disable") #비활성화
menu_file.add_separator()
menu_file.add_command(label="Exit", command=root.quit)
menu.add_cascade(label="File", menu=menu_file) # 메뉴 생성

# Edit 메뉴 (빈 값)
menu.add_cascade(label="Edit") # 메뉴 생성

# Language 메뉴 추가 (radio 버튼을 통해서 택1)
menu_lang = Menu(menu, tearoff=0) # 메뉴 하위 목록 생성
menu_lang.add_radiobutton(label="Python")
menu_lang.add_radiobutton(label="Java")
menu_lang.add_radiobutton(label="C++")
menu.add_cascade(label="Lnaguage", menu=menu_lang) # 메뉴 생성

# View 메뉴
menu_view = Menu(menu, tearoff=0)
menu_view.add_checkbutton(label="Show Minimap")
menu.add_cascade(label="View", menu=menu_view)

root.config(menu=menu) # 메뉴 보여주기
root.mainloop()

 

- 11. 메시지박스

import tkinter.messagebox as msgbox # 주의!!
from tkinter import *

root = Tk()
root.title("Nado GUI")

# 메시지 박스 관련 설정

# 예제 : 기차 예매 시스템
def info():
    msgbox.showinfo("알림", "정상적으로 예매 완료되었습니다.")

def warn():
    msgbox.showwarning("경고", "해당 좌석은 매진되었습니다.")

def error():
    msgbox.showerror("에러", "결제 오류가 발생했습니다.")

def okcancel():
    msgbox.askokcancel("확인 / 취소", "해당 좌석은 유아동반석입니다. 예매하시겠습니까?")

def retrycancel():
    msgbox.askretrycancel("재시도 / 취소", "일시적인 오류입니다. 다시 시도하시겠습니까?")

def yesno():
    msgbox.askyesno("예 / 아니오", "해당 좌석은 역방향입니다. 예매하시겠습니까?")

def yesnocancel():
    response = msgbox.askyesnocancel(title=None, message="예메 내역이 저장되지 않았습니다.\n저장 후 프로그램을 종료하시겠습니까?")
    # 네 : 저장 후 종료
    # 아니오 : 저장하지 않고 종료
    # 취소 : 프로그램 종료 취소 (현재 화면에서 계속 작업)
    print("응답 : ", response) # True, False, None -> 예 1, 아니오 0, 그 외
    if response == 1:
        print("예")
    elif response == 0:
        print("아니오")
    else:
        print("취소")

Button(root, command=info, text="알림").pack()
Button(root, command=warn, text="경고").pack()
Button(root, command=error, text="에러").pack()

Button(root, command=okcancel, text="확인 취소").pack()
Button(root, command=retrycancel, text="재시도 취소").pack()
Button(root, command=yesno, text="예 아니오").pack()
Button(root, command=yesnocancel, text="예 아니오 취소").pack()

root.mainloop()

 

- 12. 프레임

from tkinter import *

root = Tk()
root.title("Nado GUI")

# 프레임 관련 설정
Label(root, text="메뉴를 선택하세요").pack(side="top")
Button(root, text="주문하기").pack(side="bottom")

# relief는 테두리 모양, bd는 외곽선 픽셀
frame_burger = Frame(root, relief="solid", bd=1)
frame_burger.pack(side="left", fill="both", expand=True)
Button(frame_burger, text="햄버거").pack()
Button(frame_burger, text="치즈버거").pack()
Button(frame_burger, text="치킨버거").pack()

frame_drink = LabelFrame(root, text="음료")
frame_drink.pack(side="right", fill="both", expand=True)
Button(frame_drink, text="콜라").pack()
Button(frame_drink, text="사이다").pack()


root.mainloop()

 

- 13. 스크롤바

from tkinter import *

root = Tk()
root.title("Nado GUI")

# 스크롤바 관련 설정
frame = Frame(root)
frame.pack()

scrollbar = Scrollbar(frame)
scrollbar.pack(side="right", fill="y")

# set이 없으면 스크롤을 내려도 다시 올라온다.
listbox = Listbox(frame, selectmode="extended", height=10, yscrollcommand = scrollbar.set)
for i in range(1, 32): #1 ~ 31 숫자
    listbox.insert(END, str(i) + "일") #1일, 2일, ...
listbox.pack(side="left")

scrollbar.config(command=listbox.yview) # 스크롤바와 리스트박스의 y좌표와 매핑을 해준다.

root.mainloop()

 

- 14. 그리드 기초

from tkinter import *

root = Tk()
root.title("Nado GUI")

# grid 기본 사용법
btn1 = Button(root, text="버튼1")
btn2 = Button(root, text="버튼2")

btn1.grid(row=0, column=0)
btn2.grid(row=1, column=1)

root.mainloop()

 

- 15. 그리드 응용 (애플패드 키 만들기)

from tkinter import *

root = Tk()
root.title("Nado GUI")

# grid 예제 : 애플 키패드 구현
btn_f16 = Button(root, text="F16", width=5, height=2)
btn_f17 = Button(root, text="F17", width=5, height=2)
btn_f18 = Button(root, text="F18", width=5, height=2)
btn_f19 = Button(root, text="F19", width=5, height=2)

btn_f16.grid(row=0, column=0, sticky=N+E+W+S, padx=3, pady=3)
btn_f17.grid(row=0, column=1, sticky=N+E+W+S, padx=3, pady=3)
btn_f18.grid(row=0, column=2, sticky=N+E+W+S, padx=3, pady=3)
btn_f19.grid(row=0, column=3, sticky=N+E+W+S, padx=3, pady=3)

btn_clear = Button(root, text="clear", width=5, height=2)
btn_equal = Button(root, text="=", width=5, height=2)
btn_div = Button(root, text="/", width=5, height=2)
btn_mul = Button(root, text="*", width=5, height=2)

btn_clear.grid(row=1, column=0, sticky=N+E+W+S, padx=3, pady=3)
btn_equal.grid(row=1, column=1, sticky=N+E+W+S, padx=3, pady=3)
btn_div.grid(row=1, column=2, sticky=N+E+W+S, padx=3, pady=3)
btn_mul.grid(row=1, column=3, sticky=N+E+W+S, padx=3, pady=3)

btn_7 = Button(root, text="7", width=5, height=2)
btn_8 = Button(root, text="8", width=5, height=2)
btn_9 = Button(root, text="9", width=5, height=2)
btn_sub = Button(root, text="-", width=5, height=2)

btn_7.grid(row=2, column=0, sticky=N+E+W+S, padx=3, pady=3)
btn_8.grid(row=2, column=1, sticky=N+E+W+S, padx=3, pady=3)
btn_9.grid(row=2, column=2, sticky=N+E+W+S, padx=3, pady=3)
btn_sub.grid(row=2, column=3, sticky=N+E+W+S, padx=3, pady=3)

btn_4 = Button(root, text="4", width=5, height=2)
btn_5 = Button(root, text="5", width=5, height=2)
btn_6 = Button(root, text="6", width=5, height=2)
btn_add = Button(root, text="+", width=5, height=2)

btn_4.grid(row=3, column=0, sticky=N+E+W+S, padx=3, pady=3)
btn_5.grid(row=3, column=1, sticky=N+E+W+S, padx=3, pady=3)
btn_6.grid(row=3, column=2, sticky=N+E+W+S, padx=3, pady=3)
btn_add.grid(row=3, column=3, sticky=N+E+W+S, padx=3, pady=3)

btn_1 = Button(root, text="1", width=5, height=2)
btn_2 = Button(root, text="2", width=5, height=2)
btn_3 = Button(root, text="3", width=5, height=2)
btn_enter = Button(root, text="enter", width=5, height=2) # 세로로 합쳐져야 함

btn_1.grid(row=4, column=0, sticky=N+E+W+S, padx=3, pady=3)
btn_2.grid(row=4, column=1, sticky=N+E+W+S, padx=3, pady=3)
btn_3.grid(row=4, column=2, sticky=N+E+W+S, padx=3, pady=3)
btn_enter.grid(row=4, column=3, rowspan=2, sticky=N+E+W+S, padx=3, pady=3)

btn_0 = Button(root, text="0", width=5, height=2) # 가로로 합쳐져야 함.
btn_point = Button(root, text=".", width=5, height=2)

btn_0.grid(row=5, column=0, columnspan=2, sticky=N+E+W+S, padx=3, pady=3)
btn_point.grid(row=5, column=2, sticky=N+E+W+S, padx=3, pady=3)


root.mainloop()