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

Frederic Rentsch anthra.norell at bluewin.ch
Thu Jul 12 14:53:54 EDT 2012


On Tue, 2012-07-10 at 15:11 -0700, Rick Johnson wrote:
> I've tried to condense your code using the very limited info you have
> provided. I have removed unnecessarily configuring of widgets and
> exaggerated the widget borders to make debugging easier. Read below
> for Q&A.
> 
> ## START CONDENSED CODE ##
> records = range(4)
> 
> CNF_SUBFRAME = {
>     'bd':5, # rowFrame boder width.
>     'relief':RIDGE,
>     }
> 
> CNF_LABEL = {
>     'anchor':W,
>     'width':10,
>     'bg':'gray',
>     }
> 
> class FooFrame(tk.Frame):
>     def __init__(self, master, **kw):
>         tk.Frame.__init__(self, master, **kw)
>         self.build_records()
> 
>     def build_records(self):
>         # Should this method be called by __init__???
>         # Not sure if "records" is passed-in or global???
>         for n in range(len(records)):
>             record = records[n]
>             rowFrame = tk.Frame(self, name='-%d-'%n, **CNF_SUBFRAME)
>             rowFrame.bind ('<Enter>', self.evtEnter)
>             rowFrame.bind ('<Leave>', self.evtLeave)
>             rowFrame.bind ('<ButtonRelease-1>',
> self.evtButtonOneRelease)
>             rowFrame.bind ('<ButtonRelease-3>',
> self.evtButtonThreeRelease)
>             rowFrame.grid (row=n+2, column=1, padx=5, pady=5)
>             for i in range(4):
>                 lbtext = 'Label_'+str(i)
>                 label = tk.Label(rowFrame, text=lbtext, **CNF_LABEL)
>                 label.grid (row=0, column=i, sticky=NW)
> 
>     def evtEnter(self, event):
>         w = event.widget
>         print 'evtEnter', w.winfo_class()
>         w.config(bg='magenta')
> 
>     def evtLeave(self, event):
>         w = event.widget
>         print 'evtLeave', w.winfo_class()
>         w.config(bg='SystemButtonFace')
> 
>     def evtButtonOneRelease(self, event):
>         w = event.widget
>         print 'evtButtonOneRelease', w.winfo_class()
>         w.config(bg='Green')
> 
>     def evtButtonThreeRelease(self, event):
>         w = event.widget
>         print 'evtButtonThreeRelease', w.winfo_class()
>         w.config(bg='Blue')
> 
> if __name__ == '__main__':
>     root = tk.Tk()
>     frame = FooFrame(root, width=100, height=100, bg='red', bd=1)
>     frame.pack(padx=5, pady=5)
>     root.mainloop()
> ## END CONDENSED CODE ##
> 
> 
> In the code sample provided, you will see that the label widgets
> stacked on each row will block "click" events on the containing
> "rowFrames" below them. You can get a click event (on the sub frames)
> to work by clicking the exaggerated border on the frames. All the
> events work properly for me, although this GUI interface seems
> unintuitive even with proper borders and colors.
> 
> Fredric, I can't help but feel that you are not attacking the problem
> correctly. Please explain the following questions in detail so that i
> may be able to provide help:
> 
It works for me too.

I spent another day running the offending class in a simplified
environment and it worked flawlessly. In what way the environment makes
the difference is anything but obvious. But it has got to be the
environment.

> Q1. You have subclassed a Tkinter.Frame and you are building "rows" of
> sub-frames into this toplevel frame; with each row holding
> horizontally stacked label widgets. Okay, I can see a need to wrap up
> a "RowFrame" object, but i don't see a need to create a
> "RowFrameFactory". Can you explain this design decision?
> 
I sent this same response yesterday with a screen shot attached. The
message didn't pass. It must have been rejected by a spam filter. So I
try again without the screen shot. (Too bad. A picture is worth a
thousand words).
   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.
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.
   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.

> Q2. It seems odd to me that you want to engage the "rowFrame" widgets
> via events but NOT the Label widgets. Can you explain this design
> decision?
> 
Again, the labels serve to align the fields into columns. As to the
bindings, I just now found out, that <Entry> and <Leave> can be bound to
the line frame, but the mouse buttons don't act on the frame with the
labels covering it wall to wall. Entry will lighten up the background of
the line. Leave restores the normal color. <ButtonRelease-N> will select
the line, darkening the text. The coloring has to be done separately on
each label across the line, as the labels cover the frame. That isn't a
problem.

I'm sorry I can't post an intelligible piece that does NOT work. I
obviously can't post the whole thing. It is way too convoluted. But I
will post an intelligible condensate the moment I manage to distill one
without distilling away the flaw in question. At any rate I will post
the solution when I find it, which I will however long that may take.
 
Frederic





More information about the Python-list mailing list