Getting the widget that triggered an Event?

前端 未结 3 770
慢半拍i
慢半拍i 2020-11-30 09:08

In Tkinter, I have a multiple widgets bound to the left-mouse button. They all trigger the same event when clicked.

How do I recover which widget was clicked?

相关标签:
3条回答
  • 2020-11-30 09:33

    Sounds like all your widgets are sharing an event handler. This excerpt from the Tkinter 8.5 Reference by John W. Shipman - NM Tech, may help.

    54.7. The extra arguments trick

    Sometimes you would like to pass other arguments to a handler besides the event.

    Here is an example. Suppose your application has an array of ten checkbuttons whose widgets are stored in a list self.cbList, indexed by the checkbutton number in range(10).

    Suppose further that you want to write one handler named .__cbHandler for <Button-1> events in all ten of these checkbuttons. The handler can get the actual Checkbutton widget that triggered it by referring to the .widget attribute of the Event object that gets passed in, but how does it find out that checkbutton's index in self.cbList?

    It would be nice to write our handler with an extra argument for the checkbutton number, something like this:

        def __cbHandler(self, event, cbNumber):
    

    But event handlers are passed only one argument, the event. So we can't use the function above because of a mismatch in the number of arguments.

    Fortunately, Python's ability to provide default values for function arguments gives us a way out. Have a look at this code:

        def __createWidgets(self):
            ...
            self.cbList = []  # Create the checkbutton list
            for i in range(10):
                cb = Checkbutton(self, ...)
                self.cbList.append(cb)
                cb.grid(row=1, column=i)
                def handler(event, self=self, i=i):  # [1]
                    return self.__cbHandler(event, i)
                cb.bind("<Button-1>", handler)
            ...
        def __cbHandler(self, event, cbNumber):
            ...
    

    [1] These lines define a new function handler that expects three arguments. The first argument is the Event object passed to all event handlers, and the second and third arguments will be set to their default values?the extra arguments we need to pass it.

    This technique can be extended to supply any number of additional arguments to handlers.

    A slightly more concise way to do this, as @Bryan Oakley does for the second button in his answer, is to define each handler function in-line with a lambda expression, i.e.:

    def __createWidgets(self):
        ...
        self.cbList = [] # Create the checkbutton list
        for i in range(10):
            cb = Checkbutton(self, ...)
            self.cbList.append(cb)
            cb.grid(row=1, column=i)
            cb.bind("<Button-1>", lambda event, self=self, i=i:
                                    self.__cbHandler(event, i))
        ...
    def __cbHandler(self, event, cbNumber):
        ...
    
    0 讨论(0)
  • 2020-11-30 09:35

    You have a couple options. One way is to access the widget attribute of the event object. Another way is to pass an object reference in to your function. Here's an example that uses one of each.

    import Tkinter as tk
    
    def onClickA(event):
        print "you clicked on", event.widget
        event.widget.config(text="Thank you!")
    
    
    def onClickB(event, obj):
        print "you clicked on", obj
        obj.config(text="Thank you!")
    
    root = tk.Tk()
    l1 = tk.Label(root, text="Click me")
    l2 = tk.Label(root, text="No, click me!")
    l1.pack()
    l2.pack()
    
    l1.bind("<1>", onClickA)
    l2.bind("<1>", lambda event, obj=l2: onClickB(event, obj))
    
    root.mainloop()
    
    0 讨论(0)
  • 2020-11-30 09:43
    def f(event):
        caller = event.widget
    
    0 讨论(0)
提交回复
热议问题