1
votes

I wrote a simple python code which creates canvas and items in canvas can be moved freely using mouse only. Also, previous shapes created in canvas can be moved. However, I have some problems here:

  1. When moving items like 1 rect. 1 circle, somehow they overlap or one of them completely unseen in canvas.
  2. My delete button works but I can't do anything after using delete button. System gives error. (I think I couldn't make object_id value 0 because after reset, I add rect. and object_id doesn't start from 0, and interestingly it has no coord?? )
  3. When I try to drag shapes in canvas, mouse automatically picks top left corner of the shape, how can I change it? (Maybe moving shapes from the point that I try to click with mouse)

My code:

from tkinter import *

from tkinter import messagebox

def click(event):
    my_label.config(text="Coordinates: x: "+ str(event.x) +" y: " +str(event.y)) 
    
    if object_id is not None: 
        for i in range(object_id):
            coord = my_canvas.coords(i+1) # +1 added because for loop starts from 0
            print(coord)
            print(object_id)
            if ((event.x<=coord[2]+10) and (event.x>=coord[0]-10) and (event.y<=coord[3]+10) and 
            (event.y>=coord[1])-10):

                print(coord)
                width = coord[2] - coord[0]
                height = coord[3] - coord[1]
                my_canvas.coords(i+1, event.x, event.y, event.x+width, event.y+height)
            else:
                pass
    else:
        pass
        
def label_mod(event): #While not pressing button, show coords!
    my_label.config(text="Coordinates: x: "+ str(event.x) +" y: " +str(event.y))

def delete():
    global object_id #Delete butonunda sistem fail oluyor
    msg = messagebox.askyesnocancel('Info', 'Delete my_canvas ?')
    if msg == True:
        my_canvas.delete(ALL)
        print(object_id)
        object_id=0 
        print(object_id)

def create_rectangle():
    global object_id
    object_id=my_canvas.create_rectangle(10, 10, 70, 70, fill='white', outline='blue', width=3)

def create_line():
    global object_id
    object_id=my_canvas.create_line(200, 200, 100, 100, fill='red', width=5)
    
def create_circle():
    global object_id
    object_id=my_canvas.create_oval(10, 10, 70, 70, fill='orange', outline='blue')
    
# Main Codes

object_id = 0

root = Tk()
root.title('Moving objects')
root.resizable(width=False, height=False)
root.geometry('1200x600+100+50')
root.configure(bg='light green')

my_label=Label(root, text="")
my_label.pack()

my_canvas = Canvas(root, bg='white', height=500, width=500)
my_canvas.pack(side=RIGHT)
my_canvas.bind("<B1-Motion>", click)
my_canvas.bind("<Motion>", label_mod)

btn_line = Button(root, text='Line', width=30, command=create_line)
btn_line.pack()

btn_rectangle = Button(root, text='Rectangle', width=30, command=create_rectangle)
btn_rectangle.pack()

btn_circle = Button(root, text='Circle', width=30, command=create_circle)
btn_circle.pack()

btn_delete = Button(root, text='Delete', width=30, command=delete)
btn_delete.pack()

root.mainloop()
1
Do you want to move all the shapes at the same time or only the one under the mouse?j_4321
When you clear the canvas, the objects are deleted but the ids are not reset, therefore the next item you create does not have id 1.j_4321
@j_4321 I want to move all items individually, I think my program works fine for this. My purpose of the project is, creating blocks and change their positions and connect them. What can I do for my delete button work? Any idea? I experienced ids are not reset but what I see also is, after delete button used, new id's don't have any coords.Talat Özmüslüman

1 Answers

0
votes

You don't need object_id at all. You can use my_canvas.find_overlapping() to select the canvas item you want, and use my_canvas.move() to move the selected item:

def on_click(event):
    selected = my_canvas.find_overlapping(event.x-10, event.y-10, event.x+10, event.y+10)
    if selected:
        my_canvas.selected = selected[-1]  # select the top-most item
        my_canvas.startxy = (event.x, event.y)
        print(my_canvas.selected, my_canvas.startxy)
    else:
        my_canvas.selected = None

def on_drag(event):
    if my_canvas.selected:
        # calculate distance moved from last position
        dx, dy = event.x-my_canvas.startxy[0], event.y-my_canvas.startxy[1]
        # move the selected item
        my_canvas.move(my_canvas.selected, dx, dy)
        # update last position
        my_canvas.startxy = (event.x, event.y)

def delete():
    msg = messagebox.askyesnocancel('Info', 'Delete my_canvas ?')
    if msg == True:
        my_canvas.delete(ALL)

def create_rectangle():
    my_canvas.create_rectangle(10, 10, 70, 70, fill='white', outline='blue', width=3)

def create_line():
    my_canvas.create_line(200, 200, 100, 100, fill='red', width=5)
    
def create_circle():
    my_canvas.create_oval(10, 10, 70, 70, fill='orange', outline='blue')

...

my_canvas.bind("<Button-1>", on_click)
my_canvas.bind("<B1-Motion>", on_drag)