【问题标题】:How do you use a button to move items on a canvas in Python?如何在 Python 中使用按钮在画布上移动项目?
【发布时间】:2017-01-31 23:41:06
【问题描述】:

我正在尝试修改此处发布的示例脚本:

board-drawing code to move an oval

原始脚本允许您在画布上单击和拖动对象。我对其进行了更改,以便按钮可以移动第一个对象,但出现按钮错误: TypeError: button_move() 正好需要 2 个参数(1 个给定) 我不明白第二个参数应该是什么。

这是修改后的脚本:

import Tkinter as tk

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

    def __init__(self, parent):
        tk.Frame.__init__(self, parent)

        # 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 of 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.on_token_press)
        self.canvas.tag_bind("token", "<ButtonRelease-1>", self.on_token_release)
        self.canvas.tag_bind("token", "<B1-Motion>", self.on_token_motion)
#-----------------------------------------------------------------------------
        self.canvas.button2 = tk.Button(self.canvas, text="Button Test",
                                 command=self.button_move)
        self.canvas.button2.config(bg="cyan",fg="black")
        self.canvas.button2.pack(side='top')

        self.canvas.tag_bind("button2", "<ButtonPress-1>", self.button_move)
#-----------------------------------------------------------------------------
    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 on_token_press(self, event):
        '''Begining 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 on_token_release(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 on_token_motion(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.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
#-----------------------------------------------------------------------------
    def button_move(self, event):
        '''Handle dragging of an object'''
        # set movement amount
        delta_x = 15
        delta_y = 15
        # move the object the appropriate amount
        #self.canvas.move(self._drag_data["item"], delta_x, delta_y)
        self.canvas.move(self._drag_data[1], delta_x, delta_y)
        # record the new position
        self._drag_data["x"] = event.x
        self._drag_data["y"] = event.y
#-----------------------------------------------------------------------------
if __name__ == "__main__":
    root = tk.Tk()
    Example(root).pack(fill="both", expand=True)
    root.mainloop()

【问题讨论】:

    标签: python canvas tkinter


    【解决方案1】:

    command= 在没有 event 的情况下执行函数,但您分配的函数需要 event - command=self.button_move -> def button_move(self, event)

    bindevent 执行相同的功能,因此您需要此功能与event

    解决方法:使用默认值,即None

    def button_move(self, event=None):
    

    但是如果你用command=执行什么,你不能在这个函数中使用event.xevent.y

    【讨论】:

    • 添加“event=None”是关键。我还在"button_move"函数中注释掉了"self._drag_data["x"] = event.x"和"self._drag_data["y"] = event.y"。
    【解决方案2】:

    这是使用 furas 建议的更新代码:

    import Tkinter as tk
    
    class Example(tk.Frame):
        '''Illustrate how to drag items on a Tkinter canvas'''
    
        def __init__(self, parent):
            tk.Frame.__init__(self, parent)
    
            # 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 of 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.on_token_press)
            self.canvas.tag_bind("token", "<ButtonRelease-1>", self.on_token_release)
            self.canvas.tag_bind("token", "<B1-Motion>", self.on_token_motion)
    #-----------------------------------------------------------------------------
            self.canvas.button2 = tk.Button(self.canvas, text="Button Test",
                                     command=self.button_move)
            self.canvas.button2.config(bg="cyan",fg="black")
            self.canvas.button2.pack(side='top')
    
            self.canvas.tag_bind("button2", "<ButtonPress-1>", self.button_move)
    #-----------------------------------------------------------------------------
        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 on_token_press(self, event):
            '''Begining 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 on_token_release(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 on_token_motion(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.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
    #-----------------------------------------------------------------------------
        def button_move(self, event=None):
            '''Handle dragging of an object'''
            # set movement amount
            delta_x = 15
            delta_y = 15
            # move the object the appropriate amount
            #self.canvas.move(self._drag_data["item"], delta_x, delta_y)
            #self.canvas.move(self._drag_data[1], delta_x, delta_y)
            self.canvas.move(1, delta_x, delta_y) # moves item 1, when cursor is over token
            # record the new position
            #self._drag_data["x"] = event.x
            #self._drag_data["y"] = event.y
    #-----------------------------------------------------------------------------
    if __name__ == "__main__":
        root = tk.Tk()
        Example(root).pack(fill="both", expand=True)
        root.mainloop()
    

    【讨论】:

    • 更好地编辑问题并添加有问题的新代码。
    【解决方案3】:

    当你将一个回调如button_move()配置为按钮的command时,它被调用时唯一给它的参数是self,就像你这样调用它:

    self.button_move()
    

    但是因为 button_move() 还需要一个 event 参数,所以您会收到以下错误:

    TypeError: button_move() takes exactly 2 arguments (1 given).
    

    因此从button_move() 定义中删除event 参数将是第一步。

    另外,由于event 不在button_move() 范围内,您应该删除这两行:

    self._drag_data["x"] = event.x
    self._drag_data["y"] = event.y
    

    最后,您需要从要移动的画布对象中获取 id,以便 self.canvas.move() 行工作。我建议您删除该行

    self._drag_data["item"] = None
    

    来自on_token_release(),因此最后点击的画布对象的id保存在self._drag_data["item"]中。那么你需要做的就是在尝试调用canvas.move()之前检查self._drag_data["item"]是否不是None。

    应用所有这些更改会产生以下代码:

    import Tkinter as tk
    
    class Example(tk.Frame):
        '''Illustrate how to drag items on a Tkinter canvas'''
    
        def __init__(self, parent):
            tk.Frame.__init__(self, parent)
    
            # 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 of 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.on_token_press)
            self.canvas.tag_bind("token", "<ButtonRelease-1>", self.on_token_release)
            self.canvas.tag_bind("token", "<B1-Motion>", self.on_token_motion)
    
            self.canvas.button2 = tk.Button(self.canvas, text="Button Test",
                                     command=self.button_move)
            self.canvas.button2.config(bg="cyan",fg="black")
            self.canvas.button2.pack(side='top')
    
            self.canvas.tag_bind("button2", "<ButtonPress-1>", self.button_move)
    
        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 on_token_press(self, event):
            '''Begining 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 on_token_release(self, event):
            '''End drag of an object'''
            # reset the drag information
            self._drag_data["x"] = 0
            self._drag_data["y"] = 0
    
        def on_token_motion(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.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
    
        def button_move(self):
            if not self._drag_data["item"]:
                return
    
            '''Handle dragging of an object'''
            # set movement amount
            delta_x = 15
            delta_y = 15
            # move the object the appropriate amount
            #self.canvas.move(self._drag_data["item"], delta_x, delta_y)
            self.canvas.move(self._drag_data["item"], delta_x, delta_y)
    
    if __name__ == "__main__":
        root = tk.Tk()
        Example(root).pack(fill="both", expand=True)
        root.mainloop()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-12
      • 2020-11-17
      • 1970-01-01
      • 1970-01-01
      • 2021-11-16
      • 1970-01-01
      • 1970-01-01
      • 2018-11-30
      相关资源
      最近更新 更多