Why is this form updated slowly in Tkinter?

Trying to make a simple move in 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) 

Where self.momentum is an array containing 2 integers: one for movement x and the other for movement y. However, the actual movement of the rectangle is very slow (about 5 movements per second), and the time self.window.master.after() has no effect.

Earlier in another tkinter project, I managed to get a very responsive tkinter movement, so I'm just wondering if there is a way to reduce the update time of the movement in this case, using either a different OOP style or a completely different code.

UPDATE: It turns out that the time in the .after() method has a value, and it actually drains in real time of the method. After using timeit while calling the method, I got this output:

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

So, I think the real question is: why does this .after() method take so long?

UPDATE 2: Tested on multiple computers, movement is still slow on any platform.

+6
source share
2 answers

I don't see the problem you are reporting on Windows 10 using at least Python 3.6. I tested the program as shown and had to add root.mainloop() at the end. This did not show the rectangle because the object moved too quickly from the canvas to see.

So, I changed this to bounce between the walls and added a counter to print the number of mom_calc calls per second. After the timeout set to 20 ms, I get 50 motion calls per second, as expected. Setting this value to 2 ms, as in your message, I get about 425 per second, so there is a small error here, and it takes about 2.3 or 2.4 ms per call. This is a bit variable, as other processes may take some time with this granularity.

Here is the (slightly) modified code:

 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() 
+1
source

"The default resolution for Windows is ~ 15 ms by default. Attempting to start the timer every 1 ms is unlikely to work the way you want, and it is probably not necessary for the game (the 60FPS display updates only every ~ 16 ms) See " Why are .NET timers limited to 15ms? "

Found a solution in calling Python-tkinter after too slow , where Andrew Medico gave a good answer (in the comment).

+3
source

Source: https://habr.com/ru/post/1015455/


All Articles