本文介绍了为什么 tkinter 的 after() 函数会冻结我的窗口?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 tkinter 创建一个 dodger 的副本.我正面临计时对象移动的问题.有人告诉我时间模块不能很好地与 tkinter 一起使用,因此我应该使用 after() 代替.但是,我在使用 after() 函数时遇到了与 time 模块相同的问题.这是我的代码:

I am creating a replica of dodger using tkinter. I am facing a problem with timing object movement. I was told the time module does not work well with tkinter, therefore I should use after() instead. However, I face the same problem with the after() function as I did with the time module. Here is my code:

from tkinter import *
from random import randint


class Window(Frame):
    def __init__(self, master=None):
        Frame.__init__(self, master)

        self.master = master
        self.initWindow()

    def initWindow(self):
        self.master.title('Dodger')
        self.pack(fill=BOTH, expand=1)
        self.master.geometry('600x800')
        self.master.config(bg='black')

        menu = Menu(self.master)
        self.master.config(menu=menu)

        def clientExit():
            exit()

        file = Menu(menu)
        file.add_command(label='Exit', command=clientExit)
        file.add_command(label='Start', command=self.game)

        menu.add_cascade(label='File', menu=file)

    def game(self):
        canvas = Canvas(self.master, width='600', height='800', borderwidth='0', highlightthickness='0')
        canvas.pack()
        canvas.create_rectangle(0, 0, 600, 800, fill='black', outline='black')

        character = canvas.create_rectangle(270, 730, 330, 760, fill='magenta', outline='cyan', width='2')

        def left(event):
            cord = canvas.coords(character)
            if cord[0] <= 5:
                pass
            else:
                canvas.move(character, -10, 0)

        def right(event):
            cord = canvas.coords(character)
            if cord[2] >= 595:
                pass
            else:
                canvas.move(character, 10, 0)

        self.master.bind('<Left>', left)
        self.master.bind('<Right>', right)

        class variables:
            sizeMin = 10
            sizeMax = 80

            y = 10
            minX = 5
            maxX = 545

        def createShape():
            size = randint(variables.sizeMin, variables.sizeMax)

            x = randint(variables.minX, variables.maxX)
            topLeft = [x, variables.y]
            bottomRight = [x + size, variables.y + size]

            shape = canvas.create_rectangle(topLeft[0], topLeft[1], bottomRight[0], bottomRight[1],
                                            fill='red', outline='red')
            return shape

        def moveShape(shape):
            canvas.move(shape, 0, 800)

        for x in range(5):
            x = createShape()
            self.master.after(1000, moveShape(x))


root = Tk()
app = Window(root)
app.mainloop()

如您所见,在游戏实例的底部,我创建了一个正方形并以 1 秒的间隔将其向下移动五次.然而,这不起作用;我的窗户在规定的时间内冻结了,然后又恢复了.我不确定这是因为我的电脑很烂还是我做错了什么.请在你的编辑器中运行我的代码,如果我做错了什么,请向我解释.

As you can see, at the bottom of the game instance, I created a square and moved it down five times at 1 second intervals. However, this did not work; my window just froze for the allotted time, then resumed afterwards. I am not sure if this is because my computer sucks or if I did something wrong. Please run my code in you editor and explain to me if I did something wrong.

推荐答案

它冻结的原因是因为你调用了 after 错误.

The reason it freezes is because you're calling after wrong.

考虑这个代码:

self.master.after(1000, moveShape(x))

...和这段代码完全一样:

... it is exactly the same as this code:

result = moveShape(x)
self.master.after(1000, result)

... 与此相同,因为 moveShape 返回 None:

... which is the same as this, since moveShape returns None:

result  = moveShape(x)
self.master.after(1000, None)

... 与此相同:

result = moveShape(x)
self.master.after(1000)

...与

result = moveShape(x)
time.sleep(1)

换句话说,你告诉它睡觉,所以它睡觉.

In other words, you're telling it to sleep, so it sleeps.

after 需要一个可调用,或者一个函数的引用.您可以将额外的 args 作为参数传递给 after.所以正确的调用方式是这样的:

after requires a callable, or a reference to a function. You can pass additional args as arguments to after. So the proper way to call it is this:

self.master.after(1000, moveShape, x)

不过,我怀疑这正是您想要的,因为所有五次迭代都将尝试在循环开始后 1000 毫秒运行代码,而不是相隔 1000 毫秒.这只是应用一点数学的简单问题.

Though, I doubt that is exactly what you want, since all five iterations will try to run the code 1000ms after the loop starts, rather than 1000ms apart. That's just a simple matter of applying a little math.

这篇关于为什么 tkinter 的 after() 函数会冻结我的窗口?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-10 16:48