Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #80320 > unrolled thread
| Started by | "ast" <nomail@invalid.com> |
|---|---|
| First post | 2014-11-06 09:32 +0100 |
| Last post | 2014-11-06 04:25 -0500 |
| Articles | 9 — 5 participants |
Back to article view | Back to comp.lang.python
Moving a window on the screen "ast" <nomail@invalid.com> - 2014-11-06 09:32 +0100
Re: Moving a window on the screen Chris Angelico <rosuav@gmail.com> - 2014-11-06 19:57 +1100
Re: Moving a window on the screen "ast" <nomail@invalid.com> - 2014-11-06 10:18 +0100
Re: Moving a window on the screen Akira Li <4kir4.1i@gmail.com> - 2014-11-08 19:35 +0300
Re: Moving a window on the screen Terry Reedy <tjreedy@udel.edu> - 2014-11-08 13:40 -0500
Re: Moving a window on the screen Akira Li <4kir4.1i@gmail.com> - 2014-11-08 23:31 +0300
Re: Moving a window on the screen Terry Reedy <tjreedy@udel.edu> - 2014-11-12 15:06 -0500
Re: Moving a window on the screen Peter Otten <__peter__@web.de> - 2014-11-06 10:15 +0100
Re: Moving a window on the screen Terry Reedy <tjreedy@udel.edu> - 2014-11-06 04:25 -0500
| From | "ast" <nomail@invalid.com> |
|---|---|
| Date | 2014-11-06 09:32 +0100 |
| Subject | Moving a window on the screen |
| Message-ID | <545b321a$0$2396$426a34cc@news.free.fr> |
Hi
Why the following program doesn't work ?
for x in range(0, 100, 10):
fen.geometry("200x200+%d+10" % x)
time.sleep(0.5)
where fen is a window (fen = Tk())
The fen window goes from it's initial location to the last one
but we dont see all the intermediate steps
thx
[toc] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2014-11-06 19:57 +1100 |
| Message-ID | <mailman.15536.1415264262.18130.python-list@python.org> |
| In reply to | #80320 |
On Thu, Nov 6, 2014 at 7:32 PM, ast <nomail@invalid.com> wrote: > The fen window goes from it's initial location to the last one > but we dont see all the intermediate steps You usually don't want to use time.sleep() in a GUI program. Try doing the same thing, but with an event loop delay call instead; often, the display won't update until you go back to the main loop. ChrisA
[toc] | [prev] | [next] | [standalone]
| From | "ast" <nomail@invalid.com> |
|---|---|
| Date | 2014-11-06 10:18 +0100 |
| Message-ID | <545b3cd8$0$2306$426a34cc@news.free.fr> |
| In reply to | #80322 |
"Chris Angelico" <rosuav@gmail.com> a écrit dans le message de
news:mailman.15536.1415264262.18130.python-list@python.org...
> You usually don't want to use time.sleep() in a GUI program. Try doing
> the same thing, but with an event loop delay call instead; often, the
> display won't update until you go back to the main loop.
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()
[toc] | [prev] | [next] | [standalone]
| From | Akira Li <4kir4.1i@gmail.com> |
|---|---|
| Date | 2014-11-08 19:35 +0300 |
| Message-ID | <mailman.15582.1415464608.18130.python-list@python.org> |
| In reply to | #80324 |
"ast" <nomail@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], 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]:
#!/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,
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,
move, delta_x, root.winfo_screenwidth())
root.mainloop()
[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
[toc] | [prev] | [next] | [standalone]
| From | Terry Reedy <tjreedy@udel.edu> |
|---|---|
| Date | 2014-11-08 13:40 -0500 |
| Message-ID | <mailman.15583.1415472071.18130.python-list@python.org> |
| In reply to | #80324 |
On 11/8/2014 11:35 AM, Akira Li wrote:
> "ast" <nomail@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
> 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
> #!/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.
> 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.
> move, delta_x, root.winfo_screenwidth())
> root.mainloop()
>
>
> [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
>
--
Terry Jan Reedy
[toc] | [prev] | [next] | [standalone]
| From | Akira Li <4kir4.1i@gmail.com> |
|---|---|
| Date | 2014-11-08 23:31 +0300 |
| Message-ID | <mailman.15585.1415478753.18130.python-list@python.org> |
| In reply to | #80324 |
Terry Reedy <tjreedy@udel.edu> writes:
> On 11/8/2014 11:35 AM, Akira Li wrote:
>> "ast" <nomail@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
[toc] | [prev] | [next] | [standalone]
| From | Terry Reedy <tjreedy@udel.edu> |
|---|---|
| Date | 2014-11-12 15:06 -0500 |
| Message-ID | <mailman.15738.1415822826.18130.python-list@python.org> |
| In reply to | #80324 |
On 11/8/2014 3:31 PM, Akira Li wrote: > Terry Reedy <tjreedy@udel.edu> writes: >> On my Win7 machine, your complicated code is much worse as it causes >> the window to jump about every half second After cutting and pasting again, I do not see the jumps. I do not have the code I ran before to compare. I do remember that I deleted, added back, and re-deleted the phase correction, and ran a couple of times each, to be sure that the aberrant behavior was reproducible in general effect. -- Terry Jan Reedy
[toc] | [prev] | [next] | [standalone]
| From | Peter Otten <__peter__@web.de> |
|---|---|
| Date | 2014-11-06 10:15 +0100 |
| Message-ID | <mailman.15537.1415265339.18130.python-list@python.org> |
| In reply to | #80320 |
ast wrote:
> Why the following program doesn't work ?
>
> for x in range(0, 100, 10):
> fen.geometry("200x200+%d+10" % x)
> time.sleep(0.5)
>
>
> where fen is a window (fen = Tk())
>
> The fen window goes from it's initial location to the last one
> but we dont see all the intermediate steps
As Chris says, using sleep() with a gui program usually doesn't work. While
the script is sleeping the event loop doesn't run and consequently the user
will not see any updates of the program's state.
Instead of sleeping you have to schedule events that trigger a callback and
then go back to the event loop. Such a callback may schedule another
invocation of itself, thus giving you the desired effect:
import tkinter as tk
root = tk.Tk()
xpositions = iter(range(0, 100, 10))
def move_next():
try:
x = next(xpositions)
except StopIteration:
pass
else:
root.geometry("200x200+%d+10" % x)
root.after(500, move_next) # have tkinter call move_next again
# in about 500 milliseconds
root.after_idle(move_next)
root.mainloop()
[toc] | [prev] | [next] | [standalone]
| From | Terry Reedy <tjreedy@udel.edu> |
|---|---|
| Date | 2014-11-06 04:25 -0500 |
| Message-ID | <mailman.15538.1415265932.18130.python-list@python.org> |
| In reply to | #80320 |
On 11/6/2014 3:57 AM, Chris Angelico wrote:
> On Thu, Nov 6, 2014 at 7:32 PM, ast <nomail@invalid.com> wrote:
>> The fen window goes from it's initial location to the last one
>> but we dont see all the intermediate steps
>
> You usually don't want to use time.sleep() in a GUI program. Try doing
> the same thing, but with an event loop delay call instead; often, the
> display won't update until you go back to the main loop.
import tkinter as tk
root = tk.Tk()
x = 0
def march():
global x
print(x)
root.geometry("200x200+%d+%d" % (x,x))
x += 10
if x < 200:
root.after(300, march)
march()
root.mainloop()
--
Terry Jan Reedy
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.python
csiph-web