Terry Reedy <tjre...@udel.edu> writes: > On 11/8/2014 11:35 AM, Akira Li wrote: >> "ast" <nom...@invalid.com> writes: >> >>> Ok, thx, it works now with: >>> >>> import tkinter >>> fen = tkinter.Tk() >>> >>> x=0 >>> >>> def moveW(): >>> global x >>> fen.geometry("200x200+%d+10" % x) >>> x = x + 10 >>> if (x < 1200): >>> fen.after(50, moveW) >>> >>> moveW() >> >> In general, to avoid the start time "drift" [1], > > which is hardly noticeable
Do you mean hardly noticeable for these particular *period*, delta_x and (small) fixed number of repeatitions? That is why I said, "in general". The link [1] that I've provided contains an example where it *is* noticable. >> you could lock the >> execution with a timer e.g., to move the window from left to right >> *delta_x* pixels at a time every *period* ms [2]: > > On my Win7 machine, your complicated code is much worse as it causes > the window to jump about every half second Could you add print(timer()) inside move(), to see the values? What happens if you increase the period to 100 ms? >> #!/usr/bin/env python3 >> from time import monotonic >> from tkinter import Tk >> >> def timer(): >> return int(monotonic() * 1000) # milliseconds >> >> def call_repeatedly(period, function, *args): >> root.after(period - timer() % period, call_repeatedly, period, > > The '- timer() % period' 'correction' is wrong when not 0 as it causes > jumps. The formula is correct. It is obvious if you make the period one second (1000ms) and print the timer() values (in milliseconds): 52002 53000 54000 55000 56001 57000 58000 59001 60001 61000 62000 ... As you can see the start time is locked with the timer: the function is called at whole seconds. Individual calls may happens slightly sooner or later but the timing doesn't drift, the difference between the expected start time and the actual start time is 1ms: >>> M[0], M[-1], M[0] + 1000*(len(M)-1) (52002, 224001, 224002) Here's the same thing if I remove the locking `-timer() % period` and use just `root.after(period, call..)`: 34235 35236 36236 37236 38236 39237 40237 41237 42237 43238 44238 45238 46238 47239 48239 ... The start time drifts: >>> L[0], L[-1], L[0] + 1000*(len(L)-1) (34235, 206279, 206235) the difference between the expected start time and the actual start time is 44ms (4400% worse than the previous method). I agree, for the purpose of moving a window on the screen, the difference doesn't matter though if it is a GUI clock then you should not ignore it otherwise it will be wrong by a minute in a couple of days. >> function, *args) # schedule the next call >> function(*args) >> >> def move(delta_x, max_x, width=200, x=[0]): >> root.geometry("%dx50+%d+100" % (width, x[0])) >> x[0] += delta_x # poor man's object >> if x[0] > (max_x - width): >> root.destroy() # exit >> >> root = Tk() >> period = 20 # call every *period* milliseconds >> delta_x = 2 # how many pixels to move at a time >> root.after(period - period % timer(), call_repeatedly, period, > > 'period % timer()' is nonsensical as timer() is arbitrary. It will > typically be 0 anyway. 'after(0, ...)' works fine. > It is a bug (the terms are swapped by mistake). Thank you for noticing. It should be `timer() % period` instead. The same expression as used in the call_repeatedly() and in the link [2] that I've provided. `period - timer() % period` is used here to make the first start time at the exact boundary so there is the same interval between function(*args) calls. [1]: http://stackoverflow.com/questions/8600161/executing-periodic-actions-in-python#comment26637231_8600301 [2]: http://stackoverflow.com/questions/24174924/how-to-run-a-function-periodically-in-python Akira -- https://mail.python.org/mailman/listinfo/python-list