How it works...

To handle the arrow keyboard events, we bind the "<KeyPress>" and "<KeyRelease>" sequences to the application instance. The currently pressed key symbols are stored in the pressed_keys dictionary:

    def __init__(self):
# ...
self.pressed_keys = {}
self.bind("<KeyPress>", self.key_press)
self.bind("<KeyRelease>", self.key_release)

def key_press(self, event):
self.pressed_keys[event.keysym] = True

def key_release(self, event):
self.pressed_keys.pop(event.keysym, None)

This approach is preferred instead of separately binding the "<Up>", "<Down>", "<Right>"and "<Left>" keys, because that would call each handler only when Tkinter processes the input keyboard events, causing the item to "jump" from one position to the next one rather than moving it smoothly on the horizontal and vertical axes.

The last sentence of the initialization of the App instance is the call to process_movements(), which starts processing the movement of the canvas item.

This method calculates the offset in each axis that the item should be displaced. Depending on the contents of the pressed_keys dictionary, the speed value is added or subtracted on each component of the coordinates:

    def process_movements(self):
off_x, off_y = 0, 0
speed = 3
if 'Right' in self.pressed_keys:
off_x += speed
if 'Left' in self.pressed_keys:
off_x -= speed
if 'Down' in self.pressed_keys:
off_y += speed
if 'Up' in self.pressed_keys:
off_y -= speed

After this, we retrieve the current item position by calling canvas.coords() and unpacking the couple of points that form the bounding box into four variables.

The center of the item is calculated by adding the x and y components of the upper-left corner to half of its width and height. This result, plus the offset in each axis, corresponds to the final position of the item after it is moved:

        x0, y0, x1, y1 = self.canvas.coords(self.item)
pos_x = x0 + (x1 - x0) / 2 + off_x
pos_y = y0 + (y1 - y0) / 2 + off_y

Then, we check whether this final item position is within the canvas area. To do so, we take advantage of Python's support for chaining comparison operators:

        if 0 <= pos_x <= self.width and 0 <= pos_y <= self.height:
self.canvas.move(self.item, off_x, off_y)

Finally, this method schedules itself with a delay of 10 milliseconds by calling self.after(10, self.process_movements). Thus, we achieve the effect of having a "custom mainloop" inside Tkinter's mainloop.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset