【发布时间】:2016-10-27 07:07:27
【问题描述】:
我制作框架,在其中粘贴一些小部件,然后将它们放在画布上。我的目标是能够以向上或向下的方式拖放这些窗口对象。
我想要做的是,当用户单击一个夹点并向上或向下移动窗口对象时,我希望在达到边界阈值后立即将其上方或下方的窗口对象移开.
我想用 Tkinter 复制的确切功能可以在这里看到: jQuery Drag and Drop Sortable
例如,当我向上拖动一个窗口对象时,一旦达到边界阈值,它上面的块就会向下移动以填充下面的相同坐标槽。相同类型的概念适用于向下运动。如果我向下移动,我希望下面的块在当前选定的窗口对象移动时向上移动以代替上面的插槽。
我的主要问题:我如何在当前窗口对象处于运动状态时获取上面和下面的窗口对象 ID相对?
您的第一个想法可能是self.canvas.find_above(item) 或self.canvas.find_below(item),但我无法弄清楚如何将上下窗口对象相对更新为动态窗口对象它会移动。
您的第二个想法可能是标签。例如,使用addtag_above(tag, item) 或addtag_below(tag, item) 添加和删除上下对象的标签。我对此进行了广泛尝试,但这仍然是一个有争议的问题,因为当移动窗口对象处于运动状态时,我无法更新上方和下方的标签。
代码中最相关的部分(注意:这是故意最小的,我尝试了很多东西,这个问题已经很长了):
def StartMove(self, event):
self.y = event.y
self.cy = event.widget.nametowidget(event.widget.winfo_parent()).winfo_y()
self.current = self.canvas.find_closest(10, self.cy)[0]
def OnMotion(self, event):
self.canvas.move(self.current, 0, event.y - 10)
def StopMove(self, event):
self.y = None
完整代码:
import tkinter as tk
class DragAndDrop(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.parent = parent
self.parent.columnconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)
self.block_count = 0
self.button = tk.Button(self, text='Add', command=self.addblock)
self.button.grid(row=0, column=0, columnspan=2, sticky='new')
self.container = tk.Frame(self)
self.container.grid(row=1, column=0, sticky='nsew')
self.canvas = tk.Canvas(self.container, width=200, height=450)
self.scrollbar = tk.Scrollbar(self.container,
orient='vertical',command=self.canvas.yview)
self.canvas.config(yscrollcommand=self.scrollbar.set)
self.canvas.grid(row=0, column=0, sticky='nsew')
self.scrollbar.grid(row=0, column=1, sticky='nse')
self.container.bind('<Configure>', self.handle_scroll)
def addblock(self):
self.block = tk.Frame(self.canvas, bd=1, relief='solid')
self.block.columnconfigure(0, weight=1)
self.grip = tk.Label(self.block, bitmap="gray25")
self.grip.grid(row=0, column=0, sticky='w')
self.grip.bind("<ButtonPress-1>", self.StartMove)
self.grip.bind("<ButtonRelease-1>", self.StopMove)
self.grip.bind("<B1-Motion>", self.OnMotion)
self.canvas.create_window((0, (self.block_count*25)),
window=self.block, anchor="nw",
width=200, height=24)
self.block_count += 1
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
def handle_scroll(self, event):
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
def StartMove(self, event):
self.y = event.y
self.cy = event.widget.nametowidget(event.widget.winfo_parent()).winfo_y()
self.current = self.canvas.find_closest(10, self.cy)[0]
def OnMotion(self, event):
self.canvas.move(self.current, 0, event.y - 10)
def StopMove(self, event):
self.y = None
root = tk.Tk()
app = DragAndDrop(root)
app.grid(row=0, column=0, sticky='ew')
root.mainloop()
【问题讨论】:
-
“我对此进行了广泛的尝试,但这仍然是一个有争议的问题,因为当移动窗口对象处于运动状态时,我无法更新上方和下方的标签。” - 什么停止了你不这样做?
-
当达到上限或下限并且是时候进行切换时,在
OnMotion事件中,我通常会检查某个坐标或索引是否高于或低于另一个的条件.如果这是真的,它通常在一个 for 循环中,所以我面临着在 for 循环中执行一次移动的挑战,除了在对象运动时执行的挑战之外。我更改坐标、画布移动和索引。通常块要么飞出屏幕,要么被其他块挡住,或者移动但当我尝试移动另一个块时,它是错误且不可靠的。
标签: python tkinter drag-and-drop draggable tkinter-canvas