Tkinter列表框拖放

6
我正在尝试创建一个具有拖放功能的列表框,以便将其拖放到画布上。我之前做过拖放,但仅限于在canvas.create_text之间进行松散的拖放,基于我在这里找到的此checkers程序的代码我看到了几个关于拖放列表框的问题,但它们只处理更改列表框中元素的顺序。我正在处理的是一个具有名称列表的列表框,以及一些create_text对象的画布,我想要能够从列表框拖动名称到画布上。我想我需要创建一个Listbox子类,但我不确定接下来该怎么做。
所以我有一个DialogWindow(Toplevel的子类),并且我的画布和列表框都在DialogWindow中。我已经想出了一种从列表框中获取名称的方法:当我点击名称时,我将其转换为canvas.create_text对象,然后拖动它。我的问题是投放。我尝试使用canvas.canvasx将其转换为画布坐标,但对我没有起作用。 x和y仍然在列表框坐标中。
def onRelease(self, event): 
    x = self.canvas.canvasx(event.x)
    y = self.canvas.canvasx(event.y)
    print(event.x, event.y)
    print(x, y) #Prints the same thing as the previous line

我已更新我的答案以解决获取正确坐标的问题。 - Bryan Oakley
1个回答

4
拖放功能的关键在于需要执行以下三个步骤:
- 绑定 <ButtonPress-1> 来选择要拖动的项目 - 绑定 <B1-Motion> 执行拖动操作 - 绑定 <ButtonRelease-1> 执行释放操作
这些操作都不需要进行子类化,所有的绑定都在列表框小部件上。您可能需要创建一个带有文本标签并去除窗口装饰(使用 wm_overrideredirect(True))的 Toplevel 实例来代表正在拖动的项目。
在释放时,您需要使用画布的 canvasxcanvasy 方法将鼠标的坐标转换为画布坐标。不要从 event.xevent.y 开始(它们是相对于列表框的),而是使用 winfo_pointerxy 方法获取鼠标的屏幕坐标,然后进行一些数学计算。
以下是如何执行拖放操作的示例:
def _on_drag_drop(self, event):
    i = self.listbox.curselection()[0]
    text = self.listbox.get(i)
    wx, wy = self.canvas.winfo_rootx(), self.canvas.winfo_rooty()
    x,y = self.winfo_pointerxy()
    cx = self.canvas.canvasx(x-wx)
    cy = self.canvas.canvasy(y-wy)
    self.canvas.create_text(cx,cy,text=text, anchor="sw")
    self.canvas.configure(scrollregion=self.canvas.bbox("all"))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接