title: Tkinter Drag-and-Drop Window Objects Up or Down on Canvas
body: <p>I make frames, stick a few widgets in them, then place them on a canvas. My goal is to be able to drag-and-drop these window objects around in an up or down fashion.</p>
  
  <p>What I'm trying to do is, when the user clicks a grip and moves a window object either up or down, I want the window object immediately above or below it to move out of its way once a boundary threshold is reached.</p>
  
  <p>The exactly functionality I'm trying to replicate with Tkinter can be seen here:
  <a href="https://jqueryui.com/draggable/#sortable" rel="nofollow">jQuery Drag and Drop Sortable</a></p>
  
  <p><a href="https://i.stack.imgur.com/OaQhU.png" rel="nofollow"><img src="https://i.stack.imgur.com/OaQhU.png" alt="Draggable Visual Example"></a></p>
  
  <p>For example, as I drag a window object upward, the blocks above it move downward once a boundary threshold is reached to fill the same coordinate slot below. The same type of concept applies to a downward movement. If I move downward, I want the blocks below to move up to take the place of the slots above as the currently selected window object moves.</p>
  
  <p><strong>My Primary Question</strong>: How do I get the above and below window object IDs <strong>relative</strong> to a current window object while it's in-motion?</p>
  
  <p>Your first thought might be <code>self.canvas.find_above(item)</code> or <code>self.canvas.find_below(item)</code> but I haven't been able to figure out how to update the above and below window objects <strong>relative</strong> to the window object in-motion as it moves.</p>
  
  <p>Your second thought might be tags. For example, add and remove tags as to the upper and lower objects with <code>addtag_above(tag, item)</code> or <code>addtag_below(tag, item)</code>. I tried this extensively and it's still a moot point because I can't update above and below tags while the moving window object is in-motion.</p>
  
  <p>The most relevant part of the code (note: this is minimal on purpose, I have tried so many things and this question is already quite long):</p>
  
  <pre><code>  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
  </code></pre>
  
  <p>Full Code:</p>
  
  <pre><code>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('&lt;Configure&gt;', 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("&lt;ButtonPress-1&gt;", self.StartMove)
      self.grip.bind("&lt;ButtonRelease-1&gt;", self.StopMove)
      self.grip.bind("&lt;B1-Motion&gt;", 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()
  </code></pre>