4

First of all, take a look at my previous thread here: Tkinter understanding mainloop

After following the advice from there, in GUI programming, infinite loops have to be avoided at all costs, in order to keep the widgets responsive to user input.

Instead of using:

while 1:
    ball.draw()
    root.update()
    time.sleep(0.01)

I managed using self.canvas.after(1, self.draw) inside my draw() function.

So my code now looks like this:

# Testing skills in game programming

from Tkinter import *

root = Tk()
root.title("Python game testing")
root.resizable(0, 0)
root.wm_attributes("-topmost", 1)

canvas = Canvas(root, width=500, height=400, bd=0, highlightthickness=0)
canvas.pack()
root.update()

class Ball:
    def __init__(self, canvas, color):
        self.canvas = canvas
        self.id = canvas.create_oval(10, 10, 25, 25, fill=color)
        self.canvas.move(self.id, 245, 100)

        self.canvas_height = canvas.winfo_height()
        self.x = 0
        self.y = -1

    def draw(self):
        self.canvas.move(self.id, self.x, self.y)

        pos = self.canvas.coords(self.id)
        if pos[1] <= 0:
            self.y = 1
        if pos[3] >= self.canvas_height:
            self.y = -1

        self.canvas.after(2, self.draw)


ball = Ball(canvas, "red")
ball.draw()

root.mainloop()

However, time inside self.canvas.after() does not work properly... If set to 1 it's extremely fast! If it's set to 10, 5 or even 2, it's too slow! I didn't have that problem while using the above while loop in my code since the time.sleep() worked as it should!


EDIT:

I can now report that the time inside the after function of Tkinter does not work properly in my Windows 8.1 tablet, and in my Windows 8.1 laptop, while in the same laptop when running Ubuntu through virtual machine it does work as it should.

Community
  • 1
  • 1
midkin
  • 1,503
  • 2
  • 18
  • 23
  • The time in `sleep` is in seconds, but in `after` its milli seconds. With `after(10,...)` it seems to be just as fast as with `sleep(0.01)`.What exactly is the problem? – tobias_k Mar 20 '15 at 22:12
  • It's not that! I type self.canvas.after(1, self.draw) and it's responding as it should (1 milli second), then i put 2 milli seconds and it responds as i used 20... I cannot see any change if i use 2 or 5 or 10... how can 1 milli second be that fast and 2 be that slow... this function just doesnt work the way it should... On the other hand time.sleep() works perdect – midkin Mar 20 '15 at 22:15
  • 2
    Can not reproduce. I certainly see a difference wheter I put in `after(2,...)` or `after(20,...)` – tobias_k Mar 20 '15 at 22:16
  • Really? So for you 2 is twice slower than 1???? oO – midkin Mar 20 '15 at 22:18
  • Yes, 2 is about twice as slow as 1, i.e. the ball takes about twice as much time for one passage. – tobias_k Mar 20 '15 at 22:21
  • Just mesured it it takes less than 2 secs for the ball to go upside down when using 1 milli second and 12 secs when using 2!!! – midkin Mar 20 '15 at 22:22
  • 1
    2 seconds for 1ms? For me it takes about 1/2 second on that setting! Which is to be expected, as the ball moves one pixel per iteration, and the frame is 500 pixels high. There seems to be something really weird on your end... – tobias_k Mar 20 '15 at 22:24
  • am using win8.1 in a tablet... i ll try this in my laptop and respone back! :O – midkin Mar 20 '15 at 22:25
  • 2
    on my laptop right now 14 secs while using 1 milli second... omg!!! I ll run it on my linux too.. – midkin Mar 20 '15 at 22:33
  • 1
    I can now report that the time inside the after function of Tkinter does not work properly in my win8.1 tablet, and in my win8.1 laptop, while in the same laptop when running ubuntu through virtual machine it does work as it should!!! :O – midkin Mar 20 '15 at 22:37
  • This seems to be specific to @midkin 's devices, maybe the interpreter/tkinter wasn't installed properly, or one of its dependencies... – Annonymous Apr 06 '15 at 13:39
  • Thanks for the answer any suggestions how to fix this? – midkin Apr 06 '15 at 13:40

2 Answers2

0

Time in time.sleep is in seconds whereas in after() it is in milliseconds. time.sleep(0.01) is the same as self.canvas.after(10, self.draw). If after(2, func) was too slow but after(1, func) was too fast then you could try sleep(0.0005) then after(1, func) do give a delay of 1.5 milliseconds but it is barely noticeable. Either way, fiddle with the timing until the pause is right.

Evan Quiney
  • 95
  • 1
  • 7
0

Speed of the object (canvas) and clock/loop speed should be considered as two different things, IMHO. Hence, you can leave loop after 2ms or even larger like 10...25...

...
self.canvas.after(2, self.draw)
... # loop this after 2 ms.

while, changing speed in terms of 'how many pixels' :

pos = self.canvas.coords(self.id)
    if pos[1] <= 0:
        self.y = 20
    if pos[3] >= self.canvas_height:
        self.y = -20

so adjusting these values, and :

self.canvas.move(self.id, 245, 100)

can let you fine-tune position and speed of your red dot. Hope it helps

Lorenzo Bassetti
  • 795
  • 10
  • 15