Tkinter.event.widget: handler gets name instead of widget.

Frederic Rentsch anthra.norell at
Mon Jul 16 12:32:09 CEST 2012

On Sat, 2012-07-14 at 20:10 -0700, rantingrickjohnson at wrote:
> On Thursday, July 12, 2012 1:53:54 PM UTC-5, Frederic Rentsch wrote:
> > The "hit list" is a table of investment titles (stock, funds, bonds)
> > that displays upon entry of a search pattern into a respective template.
> > The table displays the matching records: name, symbol, ISIN, CUSIP, Sec.
> > Any line can be click-selected. So they are to look like buttons.
> Hmm. If they "appear" like a button widget anyway, then why not just use a button widget?

Why indeed? Why does one do simple things in a complicated way? Stations
on the sinuous path the explorer takes surveying unknown territory, I
guess. Your example below is just what I need. Thanks! 

> > Representing the mentioned names and id codes in Label widgets was the
> > simplest way I could come up with to align them in columns, admittedly
> > without the benefit of much experience. But it does look good. the
> > layout is fine.
> But is it really the "simplest"? :)
> ## START CODE ##
> import Tkinter as tk
> from Tkconstants import *
> colWidths = (5,10,30,5)
> N_COLS = len(colWidths)
> N_ROWS = 6
> root = tk.Tk()
> for r in range(N_ROWS):
>     # Create some imaginary text to display in each column.
>     # Also try using string methods "center" and "rjust" to
>     # see alternative justification of text.
>     lst = [str(r).ljust(colWidths[r]) for r in range(N_COLS)]
>     b=tk.Button(root, text=''.join(lst))
>     b.pack(padx=5, pady=5)
> root.mainloop()
> ## END CODE ##
> You could easily expand that into something reusable.
> Now. If you need to place fancy borders around the texts, or use multiple fonts, or use images, or blah blah blah... then you may want to use the "canvas items" provided by the Tkinter.Canvas widget INSTEAD of buttons. 
> With the canvas, you can create a simple rectangle (canvas.create_rectangle) that represents a button's outside dimension and give it a "button styled" border. Then you can bind click events to mimic the button press action. Then you can place canvas_text items on top of that fake button and configure them to be invisible to click events. These text items will not interfer like the Tkinter.Label widgets are currently doing. 
> However, i would suggest the Tkinter.Button solution is the easiest by far.
> > I find the Tkinter system quite challenging. Doing a layout isn't so
> > much a matter of dimensioning and placing things as a struggle to trick
> > a number of automatic dimensioning and placing mechanisms into
> > obliging--mechanisms that are rather numerous and hard to remember.
> I don't think i agree with that assessment. 

Sticky, justify, side, anchor, width, height, pad, ipad . . . a plethora
of similar formatting concepts with applicability, precedence and effect
rules that are certainly easy to work with once one knows them inside
out. Until such time it's much trial-and-error, and reading of course,
which also frequently involves guessing what is meant and cross-checking
by experiment.
   For instance, I had to find a way to control the size of frames. The
geometry mangers deflate everything bottom to top and utterly ignore
width and height specifications unless the widget is empty. The solution
I found was "spanners", frames slimmed down to zero whose length acts as
a foot in the door of their parent, as it were. I suspect there are
better ways.

> I find the geometry management of Tkinter to be quite powerful whilst being simultaneously simplistic. You only have three main types of management: "Grid", "Place", and "Pack". Each of which has a very specific usage. One caveat to know is that you can NEVER mix "Grid" and "Pack" in the same container widget! I find myself using grid and pack the most, with grid being at the top of the list.
> Now, i will agree that grid can be confusing at first until you understand how to "rowconfigure" and "columnconfigue" the containing widget (be it a frame or a toplevel). There is also the "sticky" attribute to consider. 

Thanks for the reminder.

> But all in all, i would say the most difficult part of the Tkinter geometry management API is coming to grips as to which of the three geometry managers is the best choice for the particular problem at hand -- and you will find yourself using more than one manager in a single GUI app!
> But i don't see you solving this problem by stacking one widget on another. I believe it's time to seek out a new solution.

I agree. Your idea of using pre-formatted text in buttons is definitely
the way to go.  

> EASY: Using rows of Tkinter.Button coupled with a per-formatted text string.
> ADVANCED: Creating "pseudo buttons" on a canvas and stacking text objects (or whatever you like) on them.

I'll keep that in mind.

Finally I can report that I found the error I started this thread with.
(Attribute 'widget' of an event was type str)
	I have a Frame "Data" as a container of all sorts of things, among
which lists with selectable lines (the "Hit Lists"). Two such lists get
initiated with said data frame as parent, and they instantly get removed
(grid_remove) to be resuscitated (grid) later on demand. Both lists are
assigned to respective attributes of a Main object that controls
everything. At some point Hit List 1 gets resuscitated and is passed
records to display, which it does. Selecting one of the records
backfires with the mentioned error. Comparing ids I noticed that 

	id (Main.children ['data-frame'].children ['hit-list-1'])

is different from 

	id (Main.Hit_List_1)

when it should be the same. I conclude that it is a bad idea to prepare
widgets one expects to need, grid_remove them and grid them temporarily
on demand. They get into each other's way if they share parents and the
place in the layout. The way to go is to create them on demand and
destroy them when they're done.          

Thanks again to all who provided directions and shared their thoughts.


More information about the Python-list mailing list