Tkinter After Loop Only Runs to Time if Mouse Moving

Viewed 185

I'm using after() for a Tkinter animation loop:

from tkinter import Tk, Canvas
from time import time

root = Tk()
root.configure(width=1920, height=1080)
root.resizable(True, True)

main = Canvas(root, width=1600, height=900)

ball = main.create_oval(80, 80, 120, 120, fill="#FF0000")
main.pack()

frametarget = 17

lasttime = time()
frametimes = []


def move():
    global lasttime
    frametimes.append(time() - lasttime)
    lasttime = time()

    main.move(ball, 1, 1)
    root.after(frametarget, move)


root.after(0, move)
root.mainloop()

print(sum(frametimes[60:]) / len(frametimes[60:]) * 1000)

This generally seems to be updating in the region of ~30ms and looks visually slow when left unattended, but when the mouse is continuously moving over the window it hits 17ms consistently and runs smooth, but reverts back once this stops.

I'm using Python 3.7, Windows 10

Tests:

Average frame time where frametarget = 17 (for ~60fps)

Without mouse movement = 29.28ms
With mouse movement = 17.08ms

Average frame time where frametarget = 50 (for 20fps)

Without mouse movement = 62.50ms
With mouse movement = 50.04ms

Update: The same issue is not present on Linux.

2 Answers

Upgrading to Python 3.8.6 (from 3.7.4) solved the issue.

It appeared to be unique to my own environment as the problem did not reproduce on OSX, Linux or other Windows environments.

I had almost the same problem except in my case I didn't have to move the mouse, just hover with it on the window, but I think this solution will work for both cases.
Add this at the start of your code:

from ctypes import windll

timeBeginPeriod = windll.winmm.timeBeginPeriod
timeBeginPeriod(1)
Related