Is this a bug or a feature in TkInter?
Terry Reedy
tjreedy at udel.edu
Thu May 10 15:23:32 EDT 2018
On 5/10/2018 2:12 PM, charmingoldgit at gmail.com wrote:
> I'm learning to use TkInter in Python and came across this example program from 'Thinking in TkInter' (http://thinkingtkinter.sourceforge.net) - see below.
>
> Two buttons 'button1' and 'button2' are defined. The bug is that event.widget returns '.!frame.!button' from a button1 event.
The internal pathname of a widget is generated by tkinter for
interaction with tk. '.' is the name given to the root Tk widget.
Before a couple of years ago, children were given random 8(I
believe)-digit names. So you might have seen something like
.88023535.29038503. Now, the path component for a widget is '!' +
widgetName (+ number suffix if needed). A number suffix is only needed
to avoid duplication after the first widget of a given class for a
particular parent.
i.e. it somehow drops the '1' from the widget name.
There never was a '1' to be dropped.
Events on button2 are correctly reported.
>
> Is this a bug or a feature?
>
> <code>
> from tkinter import *
>
> class MyApp:
> def __init__(self, parent):
> self.myParent = parent
> self.myContainer1 = Frame(parent)
> self.myContainer1.pack()
>
> button_name = "OK"
> self.button1 = Button(self.myContainer1,
> command=self.buttonHandler(button_name, 1, "Good stuff!"))
This calls self.buttonHandler and binds the return value, None, to
command. Functions bound to 'command' must not require arguments. Add
'lambda:' before 'self' and the above will work. Nothing is printed
until you click the button and the printing is repeated each time you click.
>
> # self.button1.bind("<Return>", self.buttonHandler_a(event, button_name, 1, "Good stuff!"))
Functions bound to events must take one argument, the event. Add
'lambda event:' before 'self' and the above works when the focus is on
button1 and you hit return.
Repeat both fixes for button 2.
> self.button1.configure(text=button_name, background="green")
> self.button1.pack(side=LEFT)
> self.button1.focus_force() # Put keyboard focus on button1
>
> button_name = "Cancel"
> self.button2 = Button(self.myContainer1,
> command=self.buttonHandler(button_name, 2, "Bad stuff!"))
>
> # self.button2.bind("<Return>", self.buttonHandler_a(event, button_name, 2, "Bad stuff!"))
> self.button2.configure(text=button_name, background="red")
> self.button2.pack(side=LEFT)
>
>
> def buttonHandler(self, arg1, arg2, arg3):
> print(" buttonHandler routine received arguments:", arg1.ljust(8), arg2, arg3)
>
> def buttonHandler_a(self, event, arg1, arg2, arg3):
> print("buttonHandler_a received event", event)
> self.buttonHandler(arg1, arg2, arg3)
>
> print("\n"*100) # clear the screen
> print("Starting program tt077.")
> root = Tk()
> myapp = MyApp(root)
> print("Ready to start executing the event loop.")
> root.mainloop()
> print("Finished executing the event loop.")
> </code>
--
Terry Jan Reedy
More information about the Python-list
mailing list