I'm making simple game - there're 8 ovals, they should be clickable and moveable. After click on an oval, the oval is following cursor. The target is to get the oval into rectangle, if you release mouse button in rectangle, the oval disappears. If you release mouse button outside rectangle, the oval should appear on it's initial position. I made this program and it works, but only for one oval. I need it works for all ovals. There's my code, any idea what to change, please?
import tkinter, random
class Desktop:
array = [(50,50,70,70),(100,50,120,70),(150,50,170,70),(150,100,170,120),
(150,150,170,170),(100,150,120,170),(50,150,70,170),(50,100,70,120)]
def __init__(self):
self.canvas = tkinter.Canvas(width=400,height=400)
self.canvas.pack()
self.canvas.create_rectangle(100,250,300,350)
for i in range(len(self.array)):
self.__dict__[f'oval{i}'] = self.canvas.create_oval(self.array[i], fill='brown',tags='id')
self.canvas.tag_bind('id','<B1-Motion>',self.move)
self.canvas.tag_bind('id','<ButtonRelease-1>',self.release)
def move(self, event):
self.canvas.coords(self.oval0,event.x-10,event.y-10,event.x+10,event.y+10)
def release(self, event):
if event.x>100 and event.x<300 and event.y>250 and event.y<350:
self.canvas.delete(self.oval0)
else:
self.canvas.coords(self.oval0,self.array[0])
d = Desktop()
I bind three methods
<ButtonPress-1>
to get ID of clicked item and assign to self.selected
<B1-Motion>
to move item using self.selected
<ButtonRelease-1>
to release or delete moved item using self.selected
Code
import tkinter as tk
import random
class Desktop:
array = [(50,50,70,70),(100,50,120,70),(150,50,170,70),(150,100,170,120),
(150,150,170,170),(100,150,120,170),(50,150,70,170),(50,100,70,120)]
def __init__(self, master):
self.canvas = tk.Canvas(master, width=400, height=400)
self.canvas.pack()
self.canvas.create_rectangle(100, 250, 300, 350)
# to keep all IDs and its start position
self.ovals = {}
for item in self.array:
# create oval and get its ID
item_id = self.canvas.create_oval(item, fill='brown', tags='id')
# remember ID and its start position
self.ovals[item_id] = item
self.canvas.tag_bind('id', '<ButtonPress-1>', self.start_move)
self.canvas.tag_bind('id', '<B1-Motion>', self.move)
self.canvas.tag_bind('id', '<ButtonRelease-1>', self.stop_move)
# to remember selected item
self.selected = None
def start_move(self, event):
# find all clicked items
self.selected = self.canvas.find_overlapping(event.x, event.y, event.x, event.y)
# get first selected item
self.selected = self.selected[0]
def move(self, event):
# move selected item
self.canvas.coords(self.selected, event.x-10, event.y-10, event.x+10,event.y+10)
def stop_move(self, event):
# delete or release selected item
if 100 < event.x < 300 and 250 < event.y < 350:
self.canvas.delete(self.selected)
del self.ovals[self.selected]
else:
self.canvas.coords(self.selected, self.ovals[self.selected])
# clear it so you can use it to check if you are draging item
self.selected = None
root = tk.Tk()
d = Desktop(root)
root.mainloop()
EDIT: using event.widget.find_withtag("current")[0]
I can get first selected item, and I can skip <ButtonPress-1>
.
import tkinter as tk
import random
class Desktop:
array = [(50,50,70,70),(100,50,120,70),(150,50,170,70),(150,100,170,120),
(150,150,170,170),(100,150,120,170),(50,150,70,170),(50,100,70,120)]
def __init__(self, master):
self.canvas = tk.Canvas(master, width=400, height=400)
self.canvas.pack()
self.canvas.create_rectangle(100, 250, 300, 350)
# to keep all IDs and its start position
self.ovals = {}
for item in self.array:
# create oval and get its ID
item_id = self.canvas.create_oval(item, fill='brown', tags='id')
# remember ID and its start position
self.ovals[item_id] = item
self.canvas.tag_bind('id', '<B1-Motion>', self.move)
self.canvas.tag_bind('id', '<ButtonRelease-1>', self.stop_move)
def move(self, event):
# get selected item
selected = event.widget.find_withtag("current")[0]
# move selected item
self.canvas.coords(selected, event.x-10, event.y-10, event.x+10,event.y+10)
def stop_move(self, event):
# get selected item
selected = event.widget.find_withtag("current")[0]
# delete or release selected item
if 100 < event.x < 300 and 250 < event.y < 350:
self.canvas.delete(selected)
del self.ovals[selected]
else:
self.canvas.coords(selected, self.ovals[selected])
root = tk.Tk()
d = Desktop(root)
root.mainloop()
EDIT: added del self.ovals[selected]