chessguy
chessguy

Reputation: 165

Deactivate the drag-and-drop feature

def drag_and_drop(self):
    """
    Method allowing to drag and drop a pawn
    """
    if self.game.onOff.get() == 1:
       self._drag_data = {"x": 0, "y": 0, "item": None}
       self.tag_bind("piece", "<ButtonPress-1>", self.drag_beg)
       self.tag_bind("piece", "<ButtonRelease-1>", self.drag_end)
       self.tag_bind("piece", "<B1-Motion>", self.drag)
    else:
       do_Something()

def drag_beg(self, event):
    """Begining drag of an object"""
    # record the item and its location
    self._drag_data["item"] = self.find_closest(event.x, event.y)[0]
    self._drag_data["x"] = event.x
    self._drag_data["y"] = event.y

def drag_end(self, event):
    """End drag of an object"""
    # reset the drag information
    self._drag_data["item"] = None
    self._drag_data["x"] = 0
    self._drag_data["y"] = 0

def drag(self, event):
    """Handle dragging of an object"""
    # compute how much the mouse has moved
    delta_x = event.x - self._drag_data["x"]
    delta_y = event.y - self._drag_data["y"]
    # move the object the appropriate amount
    self.move(self._drag_data["item"], delta_x, delta_y)
    # record the new position
    self._drag_data["x"] = event.x
    self._drag_data["y"] = event.y

The code above allows me to drag and drop a pawn in a checkerboard. The drag_and_drop function is associated with a checkbutton (i.e. with tkinter). When I check the box in my interface, the drag and drop is activated. When I unchecked the box, I would like to bring back the old setup, i.e. I click once on a case source and I click a second time target case to move the pawn to the new case. I think I have to implement the method do_Something() to deactivate the drag-and-drop feature? How can I do that?

When I check the box, the drag-and-drop is very well activated, but when I unchecked the box, the function drag-and-drop is still activated. I have not found a way to deactivated it.

UPDATE

Can I unbind it this way?

self.tag_bind("piece", "<ButtonPress-1>")
self.tag_bind("piece", "<ButtonRelease-1>")
self.tag_bind("piece", "<B1-Motion>")

Upvotes: 1

Views: 208

Answers (1)

j_4321
j_4321

Reputation: 16169

There are several ways of switching on and off the drag and drop feature.

  1. As asked by the OP, it is possible to unbind the tag bindings: The use of tag_unbind is pretty straightforward: .tag_unbind(<tag>, <sequence>) will unbind all bindings to the given sequence for items with given tag. In this case:

    def drag_and_drop(self):
        """
        Method allowing to drag and drop a pawn
        """
        if self.game.onOff.get() == 1:
           self._drag_data = {"x": 0, "y": 0, "item": None}
           self.tag_bind("piece", "<ButtonPress-1>", self.drag_beg)
           self.tag_bind("piece", "<ButtonRelease-1>", self.drag_end)
           self.tag_bind("piece", "<B1-Motion>", self.drag)
        else:
           self.tag_unbind("piece", "<ButtonPress-1>")
           self.tag_unbind("piece", "<ButtonRelease-1>")
           self.tag_unbind("piece", "<B1-Motion>")
    

    Below is a full example:

    import tkinter as tk
    
    class Board(tk.Canvas):
        def __init__(self, master, drag_enabled, **kw):
            tk.Canvas.__init__(self, master, **kw)
            self.drag_enabled = drag_enabled
            self._drag_data = {"x": 0, "y": 0, "item": None}
            self.create_oval(10, 10, 50, 50, fill='white', tags='piece')
    
        def drag_and_drop(self):
            """
            Method allowing to drag and drop a pawn
            """
            if self.drag_enabled.get():
                self._drag_data = {"x": 0, "y": 0, "item": None}
                self.tag_bind("piece", "<ButtonPress-1>", self.drag_beg)
                self.tag_bind("piece", "<ButtonRelease-1>", self.drag_end)
                self.tag_bind("piece", "<B1-Motion>", self.drag)
            else:
                self.tag_unbind("piece", "<ButtonPress-1>")
                self.tag_unbind("piece", "<ButtonRelease-1>")
                self.tag_unbind("piece", "<B1-Motion>")
    
        def drag_beg(self, event):
            """Begining drag of an object"""
            # record the item and its location
            self._drag_data["item"] = self.find_closest(event.x, event.y)[0]
            self._drag_data["x"] = event.x
            self._drag_data["y"] = event.y
    
        def drag_end(self, event):
            """End drag of an object"""
            # reset the drag information
            self._drag_data["item"] = None
            self._drag_data["x"] = 0
            self._drag_data["y"] = 0
    
        def drag(self, event):
            """Handle dragging of an object"""
            # compute how much the mouse has moved
            delta_x = event.x - self._drag_data["x"]
            delta_y = event.y - self._drag_data["y"]
            # move the object the appropriate amount
            self.move(self._drag_data["item"], delta_x, delta_y)
            # record the new position
            self._drag_data["x"] = event.x
            self._drag_data["y"] = event.y
    
    root = tk.Tk()
    drag_enabled = tk.BooleanVar(root)
    board = Board(root, drag_enabled)
    tk.Checkbutton(root, text='Enable drag', variable=drag_enabled,
                   command=board.drag_and_drop).pack(side='bottom')
    board.pack()
    root.mainloop()
    
  2. As suggested in the comments, it is possible to check whether drag and drop is activated inside the functions called by the bindings and return without doing anything if it is disabled. Something like:

     def <drag function>(self, event):
         if self.drag_enabled.get():
              # drag and drop actions
    

    In this case, the drag_and_drop() function is not needed and can be put into the initialization of the board:

     import tkinter as tk
    
     class Board(tk.Canvas):
         def __init__(self, master, drag_enabled, **kw):
             tk.Canvas.__init__(self, master, **kw)
             self.drag_enabled = drag_enabled
             self._drag_data = {"x": 0, "y": 0, "item": None}
             self.create_oval(10, 10, 50, 50, fill='white', tags='piece')
    
             self._drag_data = {"x": 0, "y": 0, "item": None}
             self.tag_bind("piece", "<ButtonPress-1>", self.drag_beg)
             self.tag_bind("piece", "<ButtonRelease-1>", self.drag_end)
             self.tag_bind("piece", "<B1-Motion>", self.drag)
    
         def drag_beg(self, event):
             """Begining drag of an object"""
             # record the item and its location
             if self.drag_enabled.get():
                 self._drag_data["item"] = self.find_closest(event.x, event.y)[0]
                 self._drag_data["x"] = event.x
                 self._drag_data["y"] = event.y
    
         def drag_end(self, event):
             """End drag of an object"""
             # reset the drag information
             self._drag_data["item"] = None
             self._drag_data["x"] = 0
             self._drag_data["y"] = 0
    
         def drag(self, event):
             """Handle dragging of an object"""
             # compute how much the mouse has moved
             if self.drag_enabled.get():
                 delta_x = event.x - self._drag_data["x"]
                 delta_y = event.y - self._drag_data["y"]
                 # move the object the appropriate amount
                 self.move(self._drag_data["item"], delta_x, delta_y)
                 # record the new position
                 self._drag_data["x"] = event.x
                 self._drag_data["y"] = event.y
    
     root = tk.Tk()
     drag_enabled = tk.BooleanVar(root)
     b = Board(root, drag_enabled)
     tk.Checkbutton(root, text='Enable drag', variable=drag_enabled).pack(side='bottom')
     b.pack(fill='both', expand=True)
     root.mainloop()
    

Upvotes: 1

Related Questions