2013-07-01 2 views
3

Я пытаюсь сделать возможным, чтобы пользователь моей программы перетаскивал изображение из виджета и отбрасывал его в другой, не удаляя изображение с первого должность.Отличительные образы «Перетаскивание» в Tkinter (Python 3.x)

Я подумал об использовании TopLevel. При нажатии + перетащить событие, TopLevel, содержащее то же изображение, появится прямо над щелчком на event.x и event.y. Затем он изменит свое положение вместе с мышью и только после ButtonRelease-1 будет уничтожен TopLevel.

Если событие Кнопки фиксатора было вызвано на мастер х и у координаты, соответствующая где мой другой виджет (в случае, холст), то это вызовет canvas.create_image() с использованием event.x и event.y.

Проблемы я сталкиваюсь являются:

  1. только 1 TopLevel должен появиться сразу, но я не имел никакого успеха ограничивающее его. Несколько окон перекрываются, когда я нажимаю и перетаскиваю мышь.

  2. Я не могу сделать Toplevel.geometry использовать позиции x и y связанного события.

  3. Как сделать Toplevel отображать то же изображение, что и пользователь, нажав без магических чисел и переменных?

Вот мой код до сих пор:

class animalImgList(): 

    def __init__(self, a): 
     #Constructor 
     initX = 75 
     initY = 40 

     animalList = ['pig2.jpg', 'pig3.jpg', 'pig4.jpg'] 

     for a in animalList: 
      vars(self)[a+'img'] = PIL.Image.open(a) 

      vars(self)[a+'tkimg'] = PIL.ImageTk.PhotoImage(vars(self)[a+'img']) 

      vars(self)[a+'labelName'] = Label(anmlCanvas, image=vars(self)[a+'tkimg']) 
      vars(self)[a+'canvasImg'] = anmlCanvas.create_image(initX, initY,image=(vars(self)[a+'tkimg'])) 
      initY = initY + 70 

      anmlImgList = [] 
      anmlImgList.append(vars(self)[a+'canvasImg']) 

      imgTags = anmlCanvas.addtag_all("img") 
      anmlCanvas.tag_bind("img", "<Button-1>", self.createImg) 

    def createImg(self, event): 

     newImg = Toplevel(root) 
     newImg.geometry("50x40"+"+"+ x+"+"+y) 

     newImgMsg = Message(newImg, text="This is supposed to be an image") 
     newImgMsg.pack() 

     newImg.update_idletasks() 
     newImg.overrideredirect(True) 

     createImgOpen = True 

     if createImgOpen == True: 
      pass 

ответ

0

Чтобы перетащить изображение между двумя полотнами, не удаляя изображение с первого холста.

Идея заключается в следующем:

  • Когда пользователь нажимает на холсте can1 (click1 функция):

    • получить деталь пользователь нажал на с can1.find_closest
    • получить его изображение с can1.itemcget
    • создать изображение, содержащее изображение
    • привяжите движение мыши, чтобы перетащить вдоль верхнего слоя: для этого вам нужно использовать event.x_root и event.y_root, чтобы изменить геометрию верхнего слоя.
  • Когда пользователь отпускает левую кнопку мыши (release функция):

    • отвязать движение мыши
    • если верхнего уровня находится внутри холста can2, создать изображение в can2 в положении мыши
    • уничтожить верхнего уровня

Таким образом, может быть только один уровень, потому что каждый раз, когда кнопка отпускается, верхний слой разрушается.

Вот код:

import tkinter as tk 

class DragToplevel(tk.Toplevel): 
    def __init__(self, master, image, x, y): 
     tk.Toplevel.__init__(self, master) 
     self.overrideredirect(True) 
     self.geometry('+%i+%i' % (x, y)) 

     self.image = image 

     self.label = tk.Label(self, image=image, bg='red') 
     self.label.pack() 

    def move(self, x, y): 
     self.geometry('+%i+%i' % (x, y)) 


root = tk.Tk() 

can1 = tk.Canvas(root, width=300, height=300, bg='white') 
can2 = tk.Canvas(root, width=300, height=300, bg='white') 

can1.pack(side='left') 
can2.pack(side='right') 
root.geometry('800x800') 

im = tk.PhotoImage('tux', master=root, file='/home/juliette/Images/tux_mini.png') 
drag_id = '' 
dragged = None 
can1.create_image(100, 200, image=im) 

def click1(event): 
    global drag_id, dragged 
    items = can1.find_closest(event.x, event.y) 
    if items: 
     image = can1.itemcget(items[0], 'image') 
     dragged = DragToplevel(root, image, event.x_root, event.y_root) 
     drag_id = root.bind('<Motion>', lambda e: dragged.move(e.x_root, e.y_root)) 


def release(event): 
    global drag_id, dragged 
    root.unbind('<Motion>', drag_id) 
    drag_id = "" 
    xr, yr = event.x_root, event.y_root 
    x2, y2 = can2.winfo_rootx(), can2.winfo_rooty() 
    w2, h2 = can2.winfo_width(), can2.winfo_height() 
    if dragged and xr >= x2 and xr < x2 + w2 and yr >= y2 and yr < y2 + h2: 
     can2.create_image(xr - x2, yr - y2, image=dragged.image, anchor='nw') 
    if dragged: 
     dragged.destroy() 
     dragged = None 


can1.bind('<ButtonPress-1>', click1) 
root.bind('<ButtonRelease-1>', release) 

root.mainloop() 
Смежные вопросы