【问题标题】:Why does this shape in Tkinter update slowly?为什么 Tkinter 中的这个形状更新缓慢?
【发布时间】:2017-07-24 05:06:41
【问题描述】:

尝试在 tkinter 中进行简单的移动:

import tkinter as tk

class GameApp(object):
    """
    An object for the game window.

    Attributes:
        master: Main window tied to the application
        canvas: The canvas of this window
    """

    def __init__(self, master):
        """
        Initialize the window and canvas of the game.
        """

        self.master = master
        self.master.title = "Game"
        self.master.geometry('{}x{}'.format(500, 500))

        self.canvas = tk.Canvas(self.master)
        self.canvas.pack(side="top", fill="both", expand=True)

        self.start_game()

    #----------------------------------------------#


    def start_game(self):
        """
        Actual loading of the game.
        """

        player = Player(self)

    #----------------------------------------------#

#----------------------------------------------#


class Player(object):
    """
    The player of the game.

    Attributes:
        color: color of sprite (string)
        dimensions: dimensions of the sprite (array)
        canvas: the canvas of this sprite (object)
        window: the actual game window object (object)
        momentum: how fast the object is moving (array)
    """


    def __init__(self, window):

        self.color = ""
        self.dimensions = [225, 225, 275, 275]
        self.window = window
        self.properties()

    #----------------------------------------------#

    def properties(self):
        """
        Establish the properties of the player.
        """

        self.color = "blue"
        self.momentum = [5, 0]

        self.draw()
        self.mom_calc()

    #----------------------------------------------#

    def draw(self):
        """
        Draw the sprite.
        """

        self.sprite = self.window.canvas.create_rectangle(*self.dimensions, fill=self.color, outline=self.color)

    #----------------------------------------------#


    def mom_calc(self):
        """
        Calculate the actual momentum of the thing
        """

        self.window.canvas.move(self.sprite, *self.momentum)
        self.window.master.after(2, self.mom_calc)

    #----------------------------------------------#

#----------------------------------------------#


root = tk.Tk()

game_window = GameApp(root)

其中self.momentum 是一个包含 2 个整数的数组:一个用于 x 运动,另一个用于 y 运动。但是,矩形的实际移动非常慢(大约每秒移动 5 次),self.window.master.after() 时间似乎没有效果。

之前在另一个 tkinter 项目中,我设法获得了真正响应的 tkinter 运动,所以我只是想知道在这种情况下是否可以通过使用不同风格的 OOP 来最小化运动更新时间,或者只是完全不同的代码。

更新:原来.after() 方法中的时间确实很重要,它实际上叠加到方法的实时时间上。使用timeit 计时调用该方法后,我得到了以下输出:

>>> print(timeit.timeit("(self.window.master.after(2, self.mom_calc))", number=10000, globals={"self":self}))
0.5395521819053108

所以我想真正的问题是:为什么 .after() 方法需要这么长时间?

更新 2:在多台计算机上测试,在任何平台上移动仍然很慢。

【问题讨论】:

标签: python tkinter tkinter-canvas


【解决方案1】:

“默认的 Windows 计时器分辨率约为 15 毫秒。尝试每 1 毫秒触发一次计时器不太可能按照您想要的方式工作,并且对于游戏来说可能是完全没有必要的(运行 60FPS 的显示器仅每 16 毫秒更新一次) . 见Why are .NET timers limited to 15 ms resolution?"

Python - tkinter call to after is too slow 找到了解决方案,其中 Andrew Medico 给出了一个很好的答案(在评论中)。

【讨论】:

    【解决方案2】:

    至少我没有看到您在使用 Python 3.6 的 Windows 10 上报告的问题。我如图所示测试了该程序,并且必须在最后添加一个root.mainloop()。这显示没有矩形,因为对象从画布上移得太快而无法看到。

    所以我修改了它以在墙壁之间反弹并添加一个计数器来打印每秒mom_calc 调用的数量。正如预期的那样,将后超时设置为 20 毫秒,我每秒收到 50 个动作调用。将其设置为 2 毫秒,如您的帖子中所示,我每秒大约 425 次,所以这里有一点错误,每次调用大约需要 2.3 或 2.4 毫秒。这有点可变,因为其他进程可能会在此粒度上占用一些时间。

    这是(稍微)修改的代码:

    import tkinter as tk
    
    class GameApp(object):
        """
        An object for the game window.
    
        Attributes:
            master: Main window tied to the application
            canvas: The canvas of this window
        """
    
        def __init__(self, master):
            """
            Initialize the window and canvas of the game.
            """
    
            self.master = master
            self.master.title = "Game"
            self.master.geometry('{}x{}'.format(500, 500))
    
            self.canvas = tk.Canvas(self.master, background="white")
            self.canvas.pack(side="top", fill="both", expand=True)
    
            self.start_game()
    
        #----------------------------------------------#
    
    
        def start_game(self):
            """
            Actual loading of the game.
            """
    
            player = Player(self)
    
        #----------------------------------------------#
    
    #----------------------------------------------#
    
    
    class Player(object):
        """
        The player of the game.
    
        Attributes:
            color: color of sprite (string)
            dimensions: dimensions of the sprite (array)
            canvas: the canvas of this sprite (object)
            window: the actual game window object (object)
            momentum: how fast the object is moving (array)
        """
    
    
        def __init__(self, window):
    
            self.color = ""
            self.dimensions = [225, 225, 275, 275]
            self.window = window
            self.movement = 0
            self.movement_last = 0
            self.properties()
    
        #----------------------------------------------#
    
        def properties(self):
            """
            Establish the properties of the player.
            """
    
            self.color = "blue"
            self.momentum = [5, 0]
    
            self.draw()
            self.mom_calc()
            self.velocity()
    
        #----------------------------------------------#
    
        def draw(self):
            """
            Draw the sprite.
            """
    
            self.sprite = self.window.canvas.create_rectangle(*self.dimensions, fill=self.color, outline=self.color)
    
        #----------------------------------------------#
    
    
        def mom_calc(self):
            """
            Calculate the actual momentum of the thing
            """
    
            pos = self.window.canvas.coords(self.sprite)
            if pos[2] > 500:
                self.momentum = [-5, 0]
            elif pos[0] < 2:
                self.momentum = [5, 0]
    
            self.window.canvas.move(self.sprite, *self.momentum)
            self.window.master.after(2, self.mom_calc)
            self.movement = self.movement + 1
    
        def velocity(self):
            print(self.movement - self.movement_last)
            self.movement_last = self.movement
            self.aid_velocity = self.window.master.after(1000, self.velocity)
    
        #----------------------------------------------#
    
    #----------------------------------------------#
    
    
    if __name__ == '__main__':
        root = tk.Tk()
        game_window = GameApp(root)
        root.mainloop()
    

    【讨论】:

    • root.mainloop() 忘记这一点感觉像个白痴,这似乎是最重要的。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-19
    • 2016-04-20
    • 2021-05-03
    • 2011-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多