강의노트 이벤트
명령 바인딩
명령 바인딩은 콜백 함수를 위젯의 이벤트(버튼 클릭, 키 입력)와 연결하는 방법이다.
위젯 이벤트가 발생하면 콜백 함수가 호출되어 이벤트에 연결된 함수를 처리한다.
Tkinter의 일부 위젯의 commands에 명령 바인딩을 사용하여 콜백 함수로 이벤트와 연결할 수 있다.
명령 바인딩을 사용하려면 함수를 콜백으로 정의하고 위젯의 명령 옵션에 함수 이름을 지정한다.
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
def button_clicked(): #1
print('Button clicked')
button = ttk.Button(root, text='Click Me', command=button_clicked) #2
button.pack()
root.mainloop()
- 함수(button_clicked)를 정의한다.
- 함수를 버튼 위젯의 명령 옵션("command=button_clicked")에 연결한다. 명령 옵션 내에 괄호( ) 없이 콜백 함수를 전달해야 한다. 그렇지 않으면 프로그램이 실행되는 즉시 콜백이 호출된다.
콜백 함수에 인수를 전달해야되는 경우에는 람다 표현식을 사용해야 한다. 먼저 인수를 받는 함수를 정의한다. 그런 다음 람다 표현식을 정의하고 버튼 위젯의 명령 인수에 할당한다. 다음은 람다 표현식 내에서 콜백 함수를 호출한다.
ttk.Button(root, text='Button', command=lambda: callback(args))
다음 프로그램은 버튼 명령과 연결된 콜백 함수에 인수를 전달하는 방법이다.
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
def select(option):
lbl.configure(text=option)
ttk.Button(root, text='Rock', command=lambda: select('Rock')).pack()
ttk.Button(root, text='Paper',command=lambda: select('Paper')).pack()
ttk.Button(root, text='Scissors', command=lambda: select('Scissors')).pack()
lbl = ttk.Label(root,text="")
lbl.pack()
root.mainloop()
버튼을 클릭하면 버튼과 연결된 람다 표현식이 실행된다. 이 표현식은 문자열 인수를 사용하여 select( ) 함수를 호출합니다.
명령 바인딩의 제한 사항
첫째, 명령 옵션은 모든 위젯에서 사용할 수 있는 것이 아니다.
둘째, 리턴 키에는 바인딩되지 않는다.
명령 기능의 바인딩을 쉽게 변경할 수 없다. 이러한 한계를 극복하기 위해 Tkinter는 이벤트 바인딩이라는 방법을 제공한다.
이벤트 바인딩
위젯의 이벤트에 함수를 할당하는 것을 이벤트 바인딩이라고 한다. 이벤트가 발생하면 할당된 함수가 호출된다.
Tkinter는 bind( ) 메서드를 통해 이벤트 바인딩을 제공한다.
bind( ) 메서드 구문은 다음과 같다.
widget.bind(event, 함수)
이벤트가 발생하면 Tkinter는 함수를 호출한다.
다음 프로그램은 버튼을 마우스로 클릭하는 이벤트가 발생하면 on_click 함수를 호출한다.
on_click함수는 마우스가 클릭된 위치 좌표를 레이블에 표시한다.
import tkinter as tk
def on_click(event):
lbl.configure(text=f"버튼 클릭! (x={event.x:02d}, y={event.y:02d})")
root = tk.Tk()
button = tk.Button(root, text="클릭하세요")
button.pack(pady=10)
lbl = tk.Label(root, text=" ")
lbl.pack(pady = 10)
button.bind("" , on_click) #1
root.mainloop()
- 버튼 위젯의 마우스 왼쪽 버튼을 클릭하면 bind() 메서드가 호출되어 on_click함수가 호출된다.
핸들러를 추가로 등록하려면 add 인수에 '+'를 전달하면 된다. 이렇게 하면 동일한 이벤트에 여러 개의 이벤트 핸들러를 등록할 수 있다.
다음 예제는 bind() 메서드를 사용하여 동일한 이벤트에 대해 여러 핸들러를 등록하는 방법을 보여준다.
다음은 '저장' 버튼의 Return 키 누름 이벤트에 log() 함수를 바인딩하는 예시입니다
import tkinter as tk
from tkinter import ttk
def button_pressed(event): #1
print('Mouse left button pressed.')
def log(event): #2
print(event)
root = tk.Tk()
btn = ttk.Button(root, text='Save')
btn.bind('' , button_pressed) #3
btn.bind('' , log, add='+') #4
btn.focus() #5
btn.pack(expand=True)
root.mainloop()
- button_pressed함수를 정의한다.
- log함수를 정의한다.
- 마우스 왼쪽 버튼을 누르면 이벤트 발생하여 button_pressed함수를 호출한다.
- 마우스 왼쪽 버튼을 누르면 이벤트 발생하여 log함수를 호출한다. 이 문에서 세 번째 인수 add = '+'는 이미 존재하는 이벤트에 함수를 추가한다. add='+' 인수를 지정하지 않으면 bind( )메서드가 기존 함수(button_pressed)를 새 함수(log)로 대체한다.
- 버튼에 포커스를 준다.
루트 창에 이벤트 바인딩하기
Tkinter를 사용하면 최상위 창에 이벤트를 바인딩할 수 있다.
bind()의 구문을 루트 창에서 호출한다는 점을 제외하면 동일하다.
root.bind('<리턴>', 핸들러)
바인딩 수준
이전 예제에서는 이벤트를 위젯의 특정 인스턴스에 바인딩하는 방법을 배웠다. 이를 인스턴스 수준 바인딩이라고 한다.
Tkinter를 사용하면 위젯의 모든 인스턴스에 이벤트를 바인딩할 수도 있다. 예를 들어 프로그램의 모든 텍스트 상자에 이벤트를 바인딩할 수 있다:
root.bind_class('Entry', '' , 붙여넣기)
참고로 Tkinter에서는 엔트리 위젯을 사용하여 텍스트 상자를 만든다.
이벤트를 인스턴스 대신 클래스에 바인딩하기 때문에 이를 클래스 수준 바인딩이라고 한다.
이벤트 바인딩 해제하기
때로는 이전 바인딩의 효과를 취소하고 싶을 때가 있다. 이를 위해 unbind() 메서드를 사용할 수 있다:
widget.unbind(event)
다음 예제는 btn 버튼에서 이벤트의 바인딩을 해제한다 :
btn.unbind('<리턴>')
예제
창 크기 변경 이벤트
창의 크기를 변경하면 코멘드 창에 현재 창의 크기가 출력한다.
import tkinter as tk
def on_resize(event):
print("창 크기:", event.width, "x", event.height)
root = tk.Tk()
root.geometry("300x200")
root.bind("" , on_resize)
root.mainloop()
canvas의 공을 만들고 움직인다.
import tkinter as tk
import time
def moveleft(event):
global aliens
for alien in aliens:
Cvs.move(alien,-10,0)
def moveright(event):
global aliens
for alien in aliens:
Cvs.move(alien,10,0)
def f_quit():
root.destroy()
def f_create():
global aliens
aliens.append(Cvs.create_oval(20, 260, 120, 360, outline='white', fill='blue'))
aliens = []
root = tk.Tk()
Cvs = tk.Canvas(root, width=400, height=400)
Cvs.pack()
Btn1 = tk.Button(root,text='Create',command=f_create)
Btn2 = tk.Button(root,text='Stop',command=f_quit)
Btn1.pack(side='left')
Btn2.pack(side='left')
root.bind("" ,moveleft)
root.bind("" ,moveright)
root.mainloop()
키보드 방향키
키보드를 누르면 라벨에 방향 표시하기
import tkinter as tk
def on_arrow(event):
label.config(text=f"눌린 키: {event.keysym}")
root = tk.Tk()
label = tk.Label(root, text="방향키를 눌러보세요")
label.pack(pady=20)
root.bind("< Left >", on_arrow)
root.bind("< Right >", on_arrow)
root.bind("< Up >", on_arrow)
root.bind("< Down >", on_arrow)
root.mainloop()
마우스를 움직이면 캔버스에 점을 찍는 그림판 만들기
import tkinter as tk
def draw(event):
canvas.create_oval(event.x-2, event.y-2, event.x+2, event.y+2, fill="black")
root = tk.Tk()
canvas = tk.Canvas(root, width=300, height=200, bg="white")
canvas.pack()
canvas.bind("" , draw) # 왼쪽 버튼 누른 채 이동
root.mainloop()
창을 닫으려고 하면 "정말 종료하시겠습니까?" 메세지 출력하기
import tkinter as tk
from tkinter import messagebox
def on_close(event=None):
if messagebox.askyesno("종료 확인", "정말 종료하시겠습니까?"):
root.destroy()
root = tk.Tk()
root.protocol("WM_DELETE_WINDOW", on_close) # 창 닫기 버튼 이벤트 처리
root.mainloop()
로그인 하면 댓글을 쓸 수 있습니다.