2016-05-17 22 views
1

Ich versuche, ein Python-Programm zu machen, in dem Sie Widgets bewegen können.Drag & Drop-Widgets tkinter

Dies ist mein Code:

import tkinter as tk 
main = tk.Tk() 
notesFrame = tk.Frame(main, bd = 4, bg = "a6a6a6") 
notesFrame.place(x=10,y=10) 
notes = tk.Text(notesFrame) 
notes.pack() 
notesFrame.bind("<B1-Motion>", lambda event: notesFrame.place(x = event.x, y = event.y) 

Aber das bekommt Super glitchy und das Widget springt hin und her.

Danke!

+2

Haben Sie versucht wirklich * dieses * Code? Denn es hat mehrere Fehler und scheint nichts zu bewegen - zumindest unter Python 3.5 auf Mac. –

+0

Sie haben den Klick auf die Grenze, nicht das Textfeld –

Antwort

5

Das Verhalten, das Sie beobachten, wird durch die Tatsache verursacht, dass die Koordinaten des Ereignisses relativ zum gezogenen Widget sind. Aktualisieren der Widgets Position (in absolute Koordinaten) mit relativ Koordinaten offensichtlich ergibt sich Chaos.

Um dies zu beheben, habe ich die Funktionen (die erlauben, die relativen Koordinaten in absolute Koordinaten zu verwandeln), und das Button-1 Ereignis verwendet, um die Position des Cursors auf dem Widget zu bestimmen, wenn der Ziehvorgang beginnt. Das folgende ist ein Mixin, der ein Widget ziehbar macht.

class DragDropWidget: 
    def __init__(self, *args, **kwargs): 
     super().__init__(*args, **kwargs) 

     self.drag_start_x = 0 
     self.drag_start_y = 0 
     self.bind("<Button-1>", self.drag_start) 
     self.bind("<B1-Motion>", self.drag_motion) 

    def drag_start(self, event): 
     self.drag_start_x = event.x 
     self.drag_start_y = event.y 

    def drag_motion(self, event): 
     x = self.winfo_x() - self.drag_start_x + event.x 
     y = self.winfo_y() - self.drag_start_y + event.y 
     self.place(x=x, y=y) 

Verbrauch:

# As always when it comes to mixins, make sure to 
# inherit from DragDropWidget FIRST! 
class DnDFrame(DragDropWidget, tk.Frame): 
    pass 

# This wouldn't work: 
# class DnDFrame(tk.Frame, DragDropWidget): 
#  pass 

main = tk.Tk() 
notesFrame = DnDFrame(main, bd = 4, bg = "grey") 
notesFrame.place(x=10,y=10) 
notes = tk.Text(notesFrame) 
notes.pack() 
+0

Vielen Dank! Es funktionierte –

2

Tkinter hat dafür ein Modul, dokumentiert im Modul Docstring. Es wurde erwartet, dass es durch ein tk dnd Modul ersetzt wird, aber das ist nicht passiert. Ich habe es noch nie ausprobiert. Die Suche nach SO nach [tkinter] dnd ergibt this page. Unten ist der Beginn des Docstrings.

>>> from tkinter import dnd 
>>> help(dnd) 
Help on module tkinter.dnd in tkinter: 

NAME 
    tkinter.dnd - Drag-and-drop support for Tkinter. 

DESCRIPTION 
    This is very preliminary. I currently only support dnd *within* one 
    application, between different windows (or within the same window). 
[snip]