Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bind drag function to object in Tkinter UI

I'm trying to write a solitaire playing program - mainly to explore how to use a mouse to move objects in a GUI using Tkinter. I find the following code allows the user to move a card around a window with the mouse:

from tkinter import *
window = Tk()
window.state('zoomed')
window.configure(bg = 'green4')

def drag(event):
    card.place(x=event.x_root, y=event.y_root,anchor=CENTER)

card = Canvas(window, width=74, height=97, bg='blue')
card.place(x=300, y=600,anchor=CENTER)
card.bind("<B1-Motion>", drag)

window.mainloop()

However if I add another card, as in:

another_card = Canvas(window, width=74, height=97, bg='red')
another_card.place(x=600, y=600,anchor=CENTER)
another_card.bind("<B1-Motion>", drag)

Clicking this card will only move the first card. When I try to modify the drag function, as in:

def drag(event, card):
    card.place(x=event.x_root, y=event.y_root,anchor=CENTER)

and

another_card.bind("<B1-Motion>", drag(event, another_card))

I get 'too many arguments' or "name 'event' is not defined" errors. As I am eventually going to have up to 52 cards on the screen I can't write a separate drag function for each one. Is it possible to write a generic 'drag' code that could be bound to any object ?

PS in this example I have just used a blank canvas. However I have gifs for 52 playing cards that I will (hopefully) be moving around the GUI in the game itself.

like image 511
Andy G Avatar asked Feb 12 '26 12:02

Andy G


1 Answers

The problem is that you are hardcoding a reference to the first card in your drag() function.

from tkinter import *
window = Tk()
window.state('zoomed')
window.configure(bg = 'green4')

def drag(event):
    event.widget.place(x=event.x_root, y=event.y_root,anchor=CENTER)

card = Canvas(window, width=74, height=97, bg='blue')
card.place(x=300, y=600,anchor=CENTER)
card.bind("<B1-Motion>", drag)

another_card = Canvas(window, width=74, height=97, bg='red')
another_card.place(x=600, y=600,anchor=CENTER)
another_card.bind("<B1-Motion>", drag)

window.mainloop()

By using event.widget, you always get the widget (Canvas) that generated the event.

like image 78
James Kent Avatar answered Feb 14 '26 03:02

James Kent



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!