【问题标题】:Tkinter Drag-and-Drop Window Objects Up or Down on CanvasTkinter 在画布上向上或向下拖放窗口对象
【发布时间】: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


【解决方案1】:

我的主要问题:如何获取上方和下方的窗口对象 相对于处于运动中的当前窗口对象的 ID?

在我看来,最简单的解决方案是从生成所有块及其坐标的列表开始。然后,按 Y 坐标对列表进行排序。在您的绑定中,找到列表中 Y 坐标位于鼠标上方的最后一个块,以及第一个 Y 坐标位于鼠标下方的对象。

【讨论】:

  • 这正是我走过的众多路线之一。自从您提出建议后,我将更多地关注这条路线。我使用dict 来执行此操作,但排序功能在这里真的很关键,所以我将使用一个列表,看看我是否最终能解决这个问题!
猜你喜欢
  • 1970-01-01
  • 2022-11-16
  • 1970-01-01
  • 2017-08-08
  • 2017-09-14
  • 1970-01-01
  • 2016-11-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多