Tcl(tool command language)/Tk, tkinter
- Tcl : 웹, 데스트탑 어플, 네트워크, 테스팅 등 다양한 용도로 동적 프로그래밍 하기 좋은 언어
- Tk : GUI 라이브러리 제공하는 툴킷
- tkinter : Tcl/Tk 파이썬 레퍼로 tkinter 패키지로 gui 프로그래밍
1. tkinter window 관리 예제
- 윈도우 만들고, 크기 고정하고, X 누르면 메시지박스, iconify 버튼으로 아이콘화, quit버튼으로 종료
import tkinter
from tkinter import *
from tkinter import messagebox
global window
window = Tk()
window.title("window = Tk()")
window.geometry("300x300+100+100")
window.resizable(width=False, height = False)
def ask_quit():
result = messagebox.askquestion("Msg", "quit?")
if result == "yes":
window.destroy()
label = Label(window, text="Buttons")
label.pack() # pack()윈도우에 배치
iconBtn = Button(window, text="iconify", command=window.iconify) #iconify 아이콘화
iconBtn.pack()
quitBtn = Button(window, text="quit", command=window.destroy)
quitBtn.pack()
window.protocol("WM_DELETE_WINDOW", ask_quit)
window.mainloop()
tkinter의 widget(window gadget) 클래스
- tkinter의 위젯으로 frame, canvas가 있다.
- 하나의 윈도우에는 여러 프레임을 넣을 수 있다.
- 각 프레임에는 여러 캔버스를 넣을 수 있다.
- 각 캔버스에는 여러 라벨과 버튼 등의 위젯을 넣을 수 있다.
위젯 종류
- entry : 문자열 입력 공간
- scale : 슬라이드로 설정
- menu : 팝업 팝다운 메뉴
- 등
https://m.blog.naver.com/sisosw/221408280038
2. 윈도우 안에 프레임과 캔버스 그리기
import tkinter
from tkinter import *
window = Tk()
window.title("window - tk()")
window.geometry("600x600+200+100")
window.resizable(width=False, height=False)
frame1 = Frame(window, bg="light green", cursor="heart", bd=5, padx=10, pady=10, relief=GROOVE) #relief 프레임 기본 스타일
#relief : flat(기본), raised(버튼올린모양), sunken(버튼눌린모양), groove, ridge 등(대문자)
frame1.grid(row=0,column=0)
frame2 = Frame(window, bg="yellow", cursor="man", bd=5, padx=10, pady=10, relief=GROOVE)
frame2.grid(row=1,column=0)
frame3 = Frame(window, bg="yellow", cursor="plus", bd=5, padx=10, pady=10, relief=GROOVE)
frame3.grid(row=2, column=0)
canvas_11 = Canvas(frame1, bg="lime", width=100, height=100)
canvas_11.grid(row=0, column=0, fill=None, padx=10, pady=10)
canvas_12 = Canvas(frame1, bg="orange", width=150, height=100)
canvas_12.grid(row=0, column=1, fill=None, padx=10, pady=10)
canvas_13 = Canvas(frame1, bg="grey", width=100, height=100)
canvas_13.grid(row=1, column=1, fill=None, padx=10, pady=10)
canvas_21 = Canvas(frame2, bg="magenta", width=200, height=50)
canvas_21.grid(row=0, column=0, fill=None, padx=10, pady=10)
canvas_22 = Canvas(frame2, bg="brown", width=200, height=50)
canvas_22.grid(row=0, column=1, fill=None, padx=10, pady=10)
canvas_23 = Canvas(frame2, bg="sky blue", width=200, height=50)
canvas_23.grid(row=1, column=0, fill=None, padx=10, pady=10)
canvas_31 = Canvas(frame3, bg="light green", width=400, height=50)
canvas_31.grid(row=0, column=0, fill=None, padx=10, pady=10)
window.mainloop()
위젯 배치 layout
- 압축 배치 pack() : pack(fill=BOTH) # fill= X, Y, BOTH
- 격자 배치 grid() : grid(row=2, column=1)
- 절대 위치 배치 place() : place(x=200, y=200)
3. 압축 배치 연습
from tkinter import *
window =Tk()
window.title("testing pack layout")
window.geometry("400x300+100+200")
label1 = Label(window, text="label 1", bg="red", fg="white").pack(fill=X, padx=10, pady=10)
label2 = Label(window, text="label 2", bg="green", fg="black").pack(fill=X, padx=10, pady=10)
label3 = Label(window, text="label 3", bg="yellow", fg="white").pack(fill=X, padx=10, pady=10)
label4 = Label(window, text="label 4", bg="red", fg="black").pack(fill=X,padx=10, pady=10, side=LEFT)
label5 = Label(window, text="label 5", bg="green", fg="black").pack(fill=X, padx=10, pady=10, side=LEFT)
label6 = Label(window, text="label 6", bg="blue", fg="black").pack(fill=X, padx=10, pady=10, side=LEFT)
listbox = Listbox(window)
listbox.pack(fill=BOTH, expand=1)
L = [100, 200, 300, 400, 500]
for i in range(len(L)):
listbox.insert(END, str(L[i]))
mainloop()
grid 함수
- column = 열, row = 행
- columnspan = 위젯이 차지하는 열 칸 수, rowspan = 위젯이 차지할 행칸 수
- in : 위젯이 놓일 위젯, 디폴트는 부모 위젯
- sticky : 위젯을 어떻게 붙일건지 디폴트는 중앙, NSEW는 셀 경계 딱붙인다.
entry 위젯 주요 함수
- focus() : 키보드 입력 가능하게 함
- bind() : 특정 이벤트시 실행 함수 바인드
4. 그리드 레이아웃과 엔트리 바인드
- window.bind()와 Button(command=())로 엔터키를 누르거나("<Return>"), 버튼누를시 fetch()함수 호출
-> 엔터누르거나 fetch 버튼 클릭 시 fetch 함수대로 입력 데이터가 잘 출력된다.
from tkinter import *
def fetch(cells):
print("- input data -")
for i, e in enumerate(cells):
print(" {0}:{1}".format(fields[i], e.get()))
def make_form(fields):
cells = []
for r, field in enumerate(fields):
label = Label(window, width=10, text= field)
entry = Entry(window)
label.grid(row=r, column=0, sticky=NSEW)
entry.grid(row=r, column=1, sticky=NSEW)
cells.append(entry)
return cells
if __name__ == "__main__":
window = Tk()
window.title("Input Dialog with label and entry")
fields = ("Name", "Age", "Address")
cells = make_form(fields)
window.bind("<Return>", (lambda event, e=cells: fetch(e)))
#엔터키 눌릴떼 람다식 호출 바인드
#cells를 e에 담고 fetch 호출
# 주의 : bind 함수 호출시 lambda 식 앞단에 인수를 2개해야한다.
Button(window, text="Fetch", bg="green",
command=(lambda e=cells:fetch(e))).grid(row=3, column=0, sticky=NSEW)
# 버튼 눌릴때도 fetch(e) 호
Button(window, text="Quit", bg="Red", command=window.destroy).grid(row=3, column=1, sticky=NSEW)
print("grid size : ", window.grid_size())
window.grid_columnconfigure(1, weight=1)
window.grid_rowconfigure(0, weight=1)
window.mainloop()
캔버스 객체의 함수들
- after(delay_ms, callback=None, *args) : 딜레이 타임 후 콜백함수 호출
- bind(sequence=None, func=None, add=None) : 시퀀스 이벤트에 func 바인딩
- bind_all(csequence=None, func=None, add=None) : 모든 위젯에 func 바인딩
- bind_class(className, sequence=None, func=None, addd=None) : 해당 클래스 모든 위젯에 이벤트 func 바인딩
- create_image/line/oval/polygon/rectangle/text/window
- pos = canvas.coords(객체이름, pos) : 해당 객체 위치
- destroy() : 위젯과 객체제거
- mainloop() : 반복 시작
- quit() 반복 중지
- move(item, dx, dy) : 해당 아이템 객체를 이동
- update() 디스플레이 갱신
Event
- 버튼 : <Button-1>(마우스 왼쪽버튼 클릭), <Button-2> (마우스 휠 클릭), <button-3> (마우스 우클릭)
- 모션 : <Motion>(마우스 움직일때), <B1-Motion> 마우스 좌클릭채 움직일때, ...
- 위젯 동작 : <Configure> 위젯 모양 변경시, <Enter> 위젯안으로 마우스 들어갈때, <Leave> 위젯에서 나올때
- etc ...
5. 프레임, 캔버스 크기변경 이벤트 시 함수 호출
- 모든 위젯 크기 변경시 onsize 호출
- 그 중 위젯이 프레임일때 현재 크기반영해 라벨 변경
from tkinter import *
def onSize(event):
if event.widget == frame: # 이벤트 호출된 위젯이 프레임인경우
frame.update() # 라벨 변경전 갱신
label_fr.configure(text="frame size: {}x{}".format(frame.winfo_width(), frame.winfo_height()))
canvas.update()
label_cnv.configure(text="canvas size: {}x{}".format(canvas.winfo_width(), canvas.winfo_height()))
if __name__ == "__main__":
global label_Fr, label_cnv, frame, canvas
window =Tk()
window.title("finding frame and canvas size at resizing events")
frame = Frame(window, bg="light green", bd=10, padx=50, pady=50, relief=GROOVE)
frame.pack(expand=YES, fill=BOTH)
canvas = Canvas(frame, bg="white", width=600, height=400)
canvas.pack(expand=YES, fill=BOTH, padx=10, pady=10) #frame, canvas 양방향 조절 가능
frame.update()
label_fr = Label(canvas, text="frame size: {} x {}".format(frame.winfo_width(), frame.winfo_height()))
label_fr.grid(row=0, column=0, sticky=N)
canvas.update()
label_cnv = Label(canvas, text="canvas size: {} x {}".format(canvas.winfo_width(), canvas.winfo_height()))
label_cnv.grid(row=1, column=0, sticky=S)
# <Configure> : 위젯모양변경시 이벤트 -> onSize() 호출
# bind_all(컨피겨, func) -> 모든 위젯 크게 변경시 onsize() 호출
window.bind_all("<Configure>", onSize)
window.mainloop()
+ 깃 로컬 저장소를 원격 저장소에 올리기
1. git init으로 깃 저장소 초기화
2. git add . 모든 파일 스태징
3. 커밋
4. git remote add origint 원격저장소 주소
5. git remote -v로 연결되었는지 확인
6. git push -u origit master 로컬 저장소 브랜치를 원격 저장소 master로 푸시(u는 지역과 원격 연결을 위해 한번만)
7. 깃헙에 잘올라갔다.