-2

I was stuck trying to understand the code that I came across from Bryan Oakley here. Currently, this code allows the user to drag two ovals using tkinter. I wanted to be able to modify this code so that instead of ovals, the user is able to drag strings (key-value pairs) from two lists and match them. For instance, I want the user to be able to drag a string like "User" from one list and "Ryan" from another list and match them. I would greatly appreciate any input on how I should go about to modify the code so the user is able to drag the two strings.

import Tkinter as tk

class SampleApp(tk.Tk):
    '''Illustrate how to drag items on a Tkinter canvas'''

    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)

        # create a canvas
        self.canvas = tk.Canvas(width=400, height=400)
        self.canvas.pack(fill="both", expand=True)

        # this data is used to keep track of an 
        # item being dragged
        self._drag_data = {"x": 0, "y": 0, "item": None}

        # create a couple movable objects
        self._create_token((100, 100), "white")
        self._create_token((200, 100), "black")

        # add bindings for clicking, dragging and releasing over
        # any object with the "token" tag
        self.canvas.tag_bind("token", "<ButtonPress-1>", self.OnTokenButtonPress)
        self.canvas.tag_bind("token", "<ButtonRelease-1>", self.OnTokenButtonRelease)
        self.canvas.tag_bind("token", "<B1-Motion>", self.OnTokenMotion)

    def _create_token(self, coord, color):
        '''Create a token at the given coordinate in the given color'''
        (x,y) = coord
        self.canvas.create_oval(x-25, y-25, x+25, y+25, 
                                outline=color, fill=color, tags="token")

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

    def OnTokenButtonRelease(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 OnTokenMotion(self, event):
        '''Handle dragging of an object'''
        # compute how much this object 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.canvas.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

if __name__ == "__main__":
    app = SampleApp()
    app.mainloop()
Community
  • 1
  • 1
Neil
  • 127
  • 2
  • 10

1 Answers1

2

Is this what you are looking for:

import tkinter as tk

class SampleApp(tk.Tk):
    '''Illustrate how to drag items on a Tkinter canvas'''

    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)

        # create a canvas
        self.canvas = tk.Canvas(width=400, height=400, bg='red')
        self.canvas.pack(fill="both", expand=True)

        # this data is used to keep track of an 
        # item being dragged
        self._drag_data = {"x": 0, "y": 0, "item": None}

        # create a couple movable objects
        self._create_token((100, 100), "white", "User")
        self._create_token((200, 100), "black", "Ryan")

        # add bindings for clicking, dragging and releasing over
        # any object with the "token" tag
        self.canvas.tag_bind("token", "<ButtonPress-1>", self.OnTokenButtonPress)
        self.canvas.tag_bind("token", "<ButtonRelease-1>", self.OnTokenButtonRelease)
        self.canvas.tag_bind("token", "<B1-Motion>", self.OnTokenMotion)

    def _create_token(self, coord, color, mytext):
        '''Create a token at the given coordinate in the given color'''
        (x,y) = coord
        self.canvas.create_text(x-25, y-25,  
                                fill=color, tags="token", text=mytext)

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

    def OnTokenButtonRelease(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 OnTokenMotion(self, event):
        '''Handle dragging of an object'''
        # compute how much this object 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.canvas.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

if __name__ == "__main__":
    app = SampleApp()
    app.mainloop()

?

What I changed:
(EDITED LINES: 10, 18, 19, 27, 30 and 31)
-canvas background color from default (white) to red to identify white and black objects on it better;
-self.canvas.create_oval to self.canvas.create_text since you want strings instead of ovals;
-also, removed the second couple of coordinates (x+25, y+25) since create_text requires only one couple of coordinates (create_oval requires two of them), and removed outline=color since a text object doesn't have outline option, so Tkinter returns an unknown option error;
-and finally, after changing it from create_oval to create_text, I had to add the text option mytext to the _create_token function (def _create_token(self, coord, color, mytext):) and its instances ("User" & "Ryan") to the movable objects:
self._create_token((100, 100), "white", "User") self._create_token((200, 100), "black", "Ryan").

Parviz Karimli
  • 1,247
  • 1
  • 14
  • 26
  • Yes, this is great. If you don't mind, can you explain why we need the tags="token" in `create_text`? – Neil Jul 19 '16 at 18:50
  • It's just a tag name. Tags are used to control objects. Tags are symbolic names attached to items. Tags are ordinary strings, and they can contain anything except whitespace (as long as they don’t look like item handles) (source: http://effbot.org/tkinterbook/canvas.htm). I recommend you to read [this](http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/canvas-tags.html). – Parviz Karimli Jul 19 '16 at 19:01