기본기

jurin·2020년 9월 25일
0

##################################################################
나도 코딩 강의를 듣고 정리한 내용입니다.
출처 : 나도코딩 https://www.youtube.com/channel/UC7iAOLiALt2rtMVAWWl4pnw
##################################################################

기본 프레임

  • tkinter는 GUI에 대한 표준 Python 인터페이스이며 Window 창을 생성할 수 있다.
from tkinter import *

root = Tk()
root.title("Ju GUI")
root.geometry("640x480") # 가로 x 세로
# root.geometry("640x480+500+300")  # 가로 x 세로 + x좌표 + y좌표

# x(너비), y(높이) 값 변경 불가 (창 크기 변경 불가)
root.resizable(False, False) 

root.mainloop()

버튼 위젯

  • 위젯이란 버튼이나 체크박스, 텍스트 박스와 같은 것을 뜻한다.
btn1 = Button(root, text="버튼1")
btn1.pack() # 실제로 main 윈도우에 노출시켜줌

# padx : 글씨 좌우 공간 확보 pady : 글씨 상하 공간 확보
btn2 = Button(root, padx=5, pady=10, text="버튼2222222")
btn2.pack()

btn3 = Button(root, padx=10, pady=5, text="버튼2")
btn3.pack()

# width, height는 길이 정해놓기 (고정 크기) 
btn4 = Button(root, width=10, height=3, text="버튼4444444")
btn4.pack()

btn5 = Button(root, fg="red", bg="yellow", text="버튼5")
btn5.pack()

  • 이미지 버튼
# 그림판 이미지로 버튼 만들기
photo = PhotoImage(file="gui_basic/img.png")
btn6 = Button(root, image=photo)
btn6.pack()

  • 동작하는 버튼
def btncmd():
    print("버튼이 클릭되었어요")
    
btn7 = Button(root, text="동작하는 버튼", command=btncmd)
btn7.pack()


누르면 콘솔창에 출력된다.

label

  • label은 글자와 이미지를 보여준다.
label1 = Label(root, text="안녕하세요")
label1.pack()

photo = PhotoImage(file="gui_basic/img.png")
label2 = Label(root, image=photo)
label2.pack()

def change():
    label1.config(text="또 만나요") # 텍스트 재지정

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


클릭하면

  • 클릭했을 때 이미지도 바꾸기
def change():
    label1.config(text="또 만나요") # 텍스트 재지정
    # change를 했을 때 이미지 바꾸기
    photo2 = PhotoImage(file="gui_basic/img2.png")
    label2.config(image=photo2)

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

이렇게 한 후 클릭을 하면 img는 사라지는데 img2가 적용되지 않는다. 그 이유는 garbage collection(불필요한 메모리 공간 해제)이 돌아다니면서 쓰레기를 줍기 때문이다. 전역변수로 만들어야 쓰레기 처리를 하지 않는다. 따라서 photo2를 global을 통해 전역변수로 선언해야 한다.

def change():
    label1.config(text="또 만나요") # 텍스트 재지정
    
    # change를 했을 때 이미지 바꾸기
    global photo2
    photo2 = PhotoImage(file="gui_basic/img2.png")
    label2.config(image=photo2)

클릭하면

text & entry

# 텍스트 위젯
txt = Text(root, width=30, height=5)
txt.pack()
txt.insert(END, "글자를 입력하세요")

# 엔트리 위젯
# 한줄로 입력 받을 때 사용. 엔터 안됨.
e = Entry(root, width=30)
e.pack()
e.insert(0, "한 줄만 입력해요") # 현재는 값이 비어 있으므로 END를 써도 동일

def btncmd():
    # 처음부터 끝까지 모든 텍스트 내용 가져오기
    print(txt.get("1.0", END)) # 1 : 첫번째 라인, 0 : 0번째 column 위치
    print(e.get())

    # 내용 삭제
    txt.delete("1.0", END)
    e.delete(0, END)

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

리스트 박스

  • 여러 줄에 걸쳐서 여러 목록을 관리
listbox = Listbox(root, selectmode="extended", height=0) # 여러개 선택 가능
# listbox = Listbox(root, selectmode="single", height=0) # 하나만 선택 가능
# height는 보이는 목록 수 설정 0일 경우는 전부 보임
# listbox = Listbox(root, selectmode="extended", height=3)
 
listbox.insert(0, "사과") # 0번째
listbox.insert(1, "딸기") # 1번째
listbox.insert(END, "수박")# 마지막
listbox.insert(END, "포도") # 마지막
listbox.pack()

def btncmd():
    # listbox.delete(END) # 맨 뒤에 항목을 삭제
    listbox.delete(0) # 맨 앞에 항목을 삭제

    # 갯수 확인
    print(f"리스트에는 {listbox.size()}개가 있어요.")

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

    # 선택된 항목 확인. 인덱스 값 반환. (위치로 반환)
    print(f"선택된 항목 : {listbox.curselection()}")

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

체크 박스

  • 팝업 화면에서 일주일간 보지 않기 처럼 체크 or 해제하는 박스
chkvar = IntVar() # chkvar에 int 형으로 값을 저장한다.
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()

라디오 버튼

  • 체크 박스와는 다르게 여러 군데에서 하나를 택일하는 위젯
  • 하나를 선택하고 다른걸 선택하면 선택되어 있는 것은 해제된다.
  • 체크박스에서는 각 체크박스 별로 각각의 var을 넣었었는데 라디오 버튼에서는 하나를 선택하는 것이기 때문에 항목이 그룹으로 묶여 있어야 한다. 하나의 var을 가지고 공유하도록 해야한다.
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()


메뉴와 음료는 서로 영향을 끼치지 않는다. variable로 구분.

콤보 박스

  • 어떤 창을 열어서 여러 목록 중 하나를 선택.
import tkinter.ttk as ttk

values = [str(i) + "일" for i in range(1,32)] # 1 ~ 31 까지의 숫자
combobox = ttk.Combobox(root, height=5, values=values) # height는 보이는 목록 수
combobox.pack()
combobox.set("카드 결제일") # 최초 목록 제목 설정, 버튼 클릭을 통한 값 설정도 가능

redonly_combobox = ttk.Combobox(root, height=10, values=values, state="readonly") # 읽기 전용
redonly_combobox.current(0) # 0번째 인덱스 값 선택
redonly_combobox.pack()


def btncmd():
    print(combobox.get()) # 선택된 값 출력
    print(redonly_combobox.get())


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

프로그래스바

  • 진행 상태를 표시
  • 1% 2% 오르면서 진행 상태 표시
import time
import tkinter.ttk as ttk

progressbar = ttk.Progressbar(root, maximum=100, mode="indeterminate") # 결정되지 않음
progressbar = ttk.Progressbar(root, maximum=100, mode="determinate") 
progressbar.start(10) # 10 ms 마다 움직임
progressbar.pack()


def btncmd():
    progressbar.stop() # 작동 중지

btn = Button(root, text="중지", command=btncmd)
btn.pack()

import time
import tkinter.ttk as ttk

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

def btncmd2():
    for i in range(1, 101): # 1 ~ 100
        time.sleep(0.01) # 0.01 초 대기

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


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

메뉴

def create_new_file():
    print("새 파일을 만듭니다.")


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)

root.config(menu=menu)

  • 라디오 체크 위젯
# 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="Language", 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)

메세지 박스

  • 에러가 떴을 때 팝업으로 이 동작을 수행할 수 없습니다 뜨는 것
import tkinter.messagebox as msgbox

# 기차 예매 시스템이라고 가정
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(f"응답 : {response}") # True, False, None -> 예 1, 아니오 0, 그 외
    if response == 1: # 네, ok
        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()

프레임

Label(root, text="메뉴를 선택해 주세요").pack(side="top")

Button(root, text="주문하기").pack(side="bottom")

# 버거 프레임
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()

스크롤바

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):
    listbox.insert(END, str(i) + "일")
listbox.pack(side="left")

scrollbar.config(command=listbox.yview)

그리드

  • grid는 좌표를 통한 영역 표시
  • 다음과 같은 계산기 만들기
  • grid에 sticky로 키보드 셀에 꽉 채우기
  • Button에 padx와 pady로 키 크기 키우기
  • grid에 padx와 pady로 버튼들 간 간격 조절하기 but 버튼마다 미세한 차이가 있는 걸 볼 수 있는데 이건 padx와 pady는 글자 기준으로 여백을 만드는 것이기 때문에 글자가 길면 좀 더 넓어지는 것이다. 똑같은 크기를 부여하고 싶을 때에는 padx, pady 말고 width와 height로 바꿔주면 된다.
# 맨 윗줄
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)

# claer줄
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)

# 7 시작 줄
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)

# 4 시작 줄
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)

# 1 시작 줄
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)

# 0 시작 줄
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)

profile
anaooauc1236@naver.com

0개의 댓글