2012-02-18 2 views
4

저는 tkinter를 처음 사용했습니다. 제어 흐름의 작동 방식을 파악하려고합니다.Tkinter, 시간이 지남에 따라 함수를 실행합니다.

직사각형을 표시하고 3 번 깜박이 길 원합니다. 이 코드를 작성했지만 작동하지 않습니다. 나는 blinkmainloop 전에 실행되고 실제로 아무것도 그려지지 않기 때문이라고 생각합니다. 그렇다면 어떻게하면 blinkmainloop 사이의 제어 흐름을 바꿔서 작동시킬 수 있습니까? 미리 감사드립니다.

내 코드 :

from tkinter import * 
from time import * 

def blink(rectangle, canvas): 
    for i in range(3): 
     canvas.itemconfigure(rectangle, fill = "red") 
     sleep(1) 
     canvas.itemconfigure(rectangle, fill = "white") 
     sleep(1) 

root = Tk() 
fr = Frame(root) 
fr.pack() 
canv = Canvas(fr, height = 100, width = 100) 
canv.pack() 
rect = canv.create_rectangle(25, 25, 75, 75, fill = "white") 
blink(rect, canv) 
root.mainloop() 

답변

16

이벤트 중심 프로그래밍에는 절차 코드와 다른 사고 방식이 필요합니다. 응용 프로그램이 무한 루프로 실행되고 대기열에서 이벤트를 가져 와서 처리합니다. 애니메이션 작업을 수행하려면 적절한 시간에 대기열에 항목을 배치하면됩니다.

Tkinter 위젯에는 after이라는 메서드가 있습니다.이 메서드를 사용하면 일정 시간이 지나면 함수가 실행되도록 예약 할 수 있습니다. 첫 번째 단계는 애니메이션의 하나의 "프레임"을 수행하는 함수를 작성하는 것입니다. 귀하의 경우에는 두 가지 색상을 전환하는 애니메이션을 정의하고 있습니다.

root.after(1000, blink, rect, canv) 
root.after(2000, blink, rect, canv) 
root.after(3000, blink, rect, canv) 

:

def blink(rect, canvas): 
    current_color = canvas.itemcget(rect, "fill") 
    new_color = "red" if current_color == "white" else "white" 
    canvas.itemconfigure(rect, fill=new_color) 

지금, 우리는 하나 개의 초 간격으로 그 함수의 실행을 세 번이 필요합니다 : 다음, 현재의 색을 확인 다른 컬러로 전환 함수는 당신이 필요로하는 모든 것입니다 메인 루프를 시작하면 1 초 후에 색이 바뀌고 또 다른 초 후에 다시 바뀌며 3 초 후에 다시 바뀝니다.

매우 구체적인 필요를 위해 작동하지만 아주 좋은 일반적인 해결책은 아닙니다. 좀 더 일반적인 해결책은 blink을 한 번 호출 한 다음 blink을 일정 기간 후에 다시 호출하도록하는 것입니다. blink은 깜박임을 멈출시기를 알아야 할 책임이 있습니다. 어떤 종류의 깃발이나 카운터를 설정하여 깜박 거리는 횟수를 추적 할 수 있습니다. 예를 들면 다음과 같습니다 조언의 마지막 비트로서

def blink(rect, canvas): 
    ... 
    # call this function again in a second to 
    # blink forever. If you don't want to blink 
    # forever, use some sort of flag or computation 
    # to decide whether to call blink again 
    canvas.after(1000, blink, rect, canvas) 

, 나는 당신이 그 클래스의 인스턴스를 생성하는 클래스로 프로그램을 정의하는 것이 좋습니다. 이렇게하면 전역 함수가 필요하지 않으므로 많은 인수를 전달할 필요가 없습니다. 20 라인짜리 프로그램에 대해서는 별 문제가되지 않지만 중요한 것을 쓸 때 문제가됩니다. 예를 들어

:

from tkinter import * 

class MyApp(Tk): 
    def __init__(self): 
     Tk.__init__(self) 
     fr = Frame(self) 
     fr.pack() 
     self.canvas = Canvas(fr, height = 100, width = 100) 
     self.canvas.pack() 
     self.rect = self.canvas.create_rectangle(25, 25, 75, 75, fill = "white") 
     self.do_blink = False 
     start_button = Button(self, text="start blinking", 
           command=self.start_blinking) 
     stop_button = Button(self, text="stop blinking", 
           command=self.stop_blinking) 
     start_button.pack() 
     stop_button.pack() 

    def start_blinking(self): 
     self.do_blink = True 
     self.blink() 

    def stop_blinking(self): 
     self.do_blink = False 

    def blink(self): 
     if self.do_blink: 
      current_color = self.canvas.itemcget(self.rect, "fill") 
      new_color = "red" if current_color == "white" else "white" 
      self.canvas.itemconfigure(self.rect, fill=new_color) 
      self.after(1000, self.blink) 


if __name__ == "__main__": 
    root = MyApp() 
    root.mainloop() 
+0

감사합니다! 그것은 많은 것을 명확히합니다! – wazabit

3

각 위젯이있는 기능을 '후'- 그게 지정된 시간 후에 또 다른 함수를 호출 할 수 있습니다 말을하는 것입니다 - 그럼, 당신이 원하는 것하는 전화입니다 :

root.after(1000, blink) 

반복 호출을 원할 경우 깜박임 기능에서 'after'를 다시 호출하기 만하면됩니다. 당신이 가질 수있는 유일한 문제는 깜박 거릴 인수를 전달하는 것입니다 - 어쩌면 그것을 위해 '후'의 내부에서 lamda를 사용하는 것을보십시오.

관련 문제