Moving a window on the screen
Akira Li
4kir4.1i at gmail.com
Sat Nov 8 15:31:20 EST 2014
Terry Reedy <tjreedy at udel.edu> writes:
> On 11/8/2014 11:35 AM, Akira Li wrote:
>> "ast" <nomail at 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
More information about the Python-list
mailing list