Python Forum
tkinter move object continuously with Timer in Canvas
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
tkinter move object continuously with Timer in Canvas
#1
I want to move an object and scroll the canvas window for follow the object continuously with the Timer function from the threading module,
here is an executable example
    from tkinter import *
    from threading import Timer

    x_movement = 3
    def move_Timer(object):
        canvas.move(object, x_movement, 0)
        canvas.xview_scroll(3, UNITS)
        Timer(30/1000, lambda: move_Timer(object)).start()


    def move_after(object):
        canvas.move(object, x_movement, 0)
        canvas.xview_scroll(3, UNITS)
        master.after(30, lambda: move_after(object))


    master = Tk()

    canvas_width = 1000
    canvas_height = 600
    canvas_scrollregion_width = 3000
    canvas_scrollregion_height = 3000
    canvas = Canvas(master, width=canvas_width, height=canvas_height, bg="black")
    canvas.configure(scrollregion=(0, 0, canvas_scrollregion_width,     canvas_scrollregion_height), yscrollincrement='1', xscrollincrement='1')
    x = (master.winfo_screenwidth() / 2) - (canvas_width // 2)
    y = (master.winfo_screenheight() / 2) - (canvas_height // 2)
    master.geometry('%dx%d+%d+%d' % (canvas_width + 4, canvas_height + 4, x, y))
    canvas.pack()

    x1, y1 = canvas_scrollregion_width/2, canvas_scrollregion_height/2
    ball = canvas.create_oval(x1, y1, x1 + 50, y1 + 50, fill="red")
    canvas.xview_moveto((x1 - canvas_width/2)/canvas_scrollregion_width)
    canvas.yview_moveto((y1 - canvas_height/2)/canvas_scrollregion_height)


    master.bind("d", lambda event: move_Timer(ball))
    master.bind('<Right>', lambda event: move_after(ball))
    master.bind("<Button-1>", lambda event: print(canvas.canvasx(event.x),canvas.canvasy(event.y)))
    master.mainloop()
In this example there are two functions, the first move_Timer(object) that move the object using Timer (in the example is activated by pressing the d key) and the second move_after(object) that moves the object using after (in the example is activated by pressing the arrow_right key).
The problem is that with the first function when the object starts to move it starts to vibrate too while with the second function the object movement is correct. I don't understand why the object vibrate when i use the Timer function, i need to use it for not overload the main loop.
I'm working on Windows 10 with python 3
Reply
#2
1. Just use tkinter after method. Don't use threading timer.

Instead of this.
master.after(30, lambda: move_after(object))
You can just do this.
master.after(30, move_after, object)
Example
import tkinter as tk

FPS = int(1000 / 30)

# Simple global container until you learn classes
class Game:
    pass

def move_ball(obj, x, y):
    Game.canvas.move(obj, x, y)
    #Game.canvas.xview_scroll(3, tk.UNITS)

def update_keypressed():
    if Game.keys['d']:
        move_ball(Game.ball, Game.xmove, 0)
    elif Game.keys['a']:
        move_ball(Game.ball, -Game.xmove, 0)

    Game.master.after(FPS, update_keypressed)

def key_pressed(event):
    #print('KeyPress', event.keysym)
    Game.keys[event.keysym] = True

def key_release(event):
    #print('KeyRelease', event.keysym)
    Game.keys[event.keysym] = False

def main():
    Game.master = tk.Tk()

    # Set Globals
    Game.xmove = 3

    canvas_width = 1000
    canvas_height = 600
    canvas_scroll_width = 3000
    canvas_scroll_height = 3000

    Game.canvas = tk.Canvas(Game.master,
        width=canvas_width,
        height=canvas_scroll_height,
        bg='black')

    Game.canvas.configure(scrollregion=(0, 0,
        canvas_scroll_width, canvas_scroll_height),
        yscrollincrement='1',
        xscrollincrement='1')

    x = (Game.master.winfo_screenwidth() / 2) - (canvas_width / 2)
    y = (Game.master.winfo_screenheight() / 2) - (canvas_height / 2)

    Game.master.geometry('%dx%d+%d+%d' % (canvas_width + 4, canvas_height + 4, x, y))
    Game.canvas.pack()

    x1, y1 = canvas_scroll_width/2, canvas_scroll_height/2
    Game.ball = Game.canvas.create_oval(x1, y1, x1 + 50, y1 + 50, fill="red")
    Game.canvas.xview_moveto((x1 - canvas_width / 2) / canvas_scroll_width)
    Game.canvas.yview_moveto((y1 - canvas_height / 2) / canvas_scroll_height)

    Game.keys = {'d':False, 'a':False}
    Game.master.bind("a<KeyPress>", key_pressed)
    Game.master.bind("a<KeyRelease>", key_release)
    Game.master.bind("d<KeyPress>", key_pressed)
    Game.master.bind("d<KeyRelease>", key_release)

    # Start the update key loop
    update_keypressed()
    Game.master.mainloop()

main()
99 percent of computer problems exists between chair and keyboard.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  how to move the 'Human' object using keys. ashik 0 2,181 Apr-29-2018, 08:00 AM
Last Post: ashik

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020