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