Tkinter——随着时间的推移执行函数 [英] Tkinter — executing functions over time

查看:28
本文介绍了Tkinter——随着时间的推移执行函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试弄清楚 tkinter 控制流是如何工作的.

I'm trying to figure out how the tkinter control flow works.

我想显示一个矩形并使其闪烁三次.我写了这段代码,但它不起作用.我猜是因为 blinkmainloop 之前执行了,它实际上并没有绘制任何东西.如果是这样,我如何在 blinkmainloop 之间交换控制流以使其工作?

I want to display a rectangle and to make it blink three times. I wrote this code, but it doesn't work. I guess it's because blink is executed before mainloop, and it doesn't actually draw anything. If so, how can I swap the control flow between blink and mainloop to make it work?

我的代码:

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()

推荐答案

事件驱动编程需要与过程代码不同的思维方式.您的应用程序在无限循环中运行,从队列中提取事件并处理它们.要制作动画,您需要做的就是在适当的时间将项目放入该队列.

Event-driven programming requires a different mindset from procedural code. Your application is running in an infinite loop, pulling events off of a queue and processing them. To do animation, all you need to do is place items on that queue at an appropriate time.

Tkinter 小部件有一个名为 after 的方法,它可以让您安排要运行的函数一定的时间.第一步是编写一个函数来执行动画的一个帧".在您的情况下,您将动画定义为在两种颜色之间切换.检查当前颜色,然后切换到另一种颜色的功能就是您所需要的:

Tkinter widgets have a method named after which lets you schedule functions to run after a certain period of time. The first step is to write a function that does one "frame" of your animation. In your case, you're defining animation as switching between two colors. A function that checks the current color, then switches to the other color is all you need:

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 次:

Now, we just need to have that function run three times at one second intervals:

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

当你开始主循环时,颜色会在一秒后改变,再过一秒又会改变,三秒后又会改变.

When you start your main loop, after one second the color will change, after another second it will change again, and after a third second it will change again.

这适用于您非常具体的需求,但这不是一个很好的通用解决方案.更通用的解决方案是调用 blink 一次,然后在一段时间后让 blink 再次调用自身.blink 然后必须负责知道何时停止闪烁.您可以设置某种标志或计数器来跟踪您眨眼的次数.例如:

That works for your very specific need, but that's not a very good general solution. A more general solution is to call blink once, and then have blink call itself again after some time period. blink then must be responsible to know when to stop blinking. You can set a flag or counter of some sort to keep track of how many times you've blinked. For example:

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 行的程序来说这并不重要,但是当你想写一些实质性的东西时就开始重要了.

As a final bit of advice, I recommend that you define your program as a class, then create an instance of that class. This makes it so that you don't need global functions, and you don't need to pass around so many arguments. It doesn't really matter for a 20 line program, but it starts to matter when you want to write something substantial.

例如:

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()

这篇关于Tkinter——随着时间的推移执行函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆