Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

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

342 views
Skip to first unread message

Frederic Rentsch

unread,
Jul 8, 2012, 5:19:13 PM7/8/12
to pytho...@python.org
Hi widget wizards,

The manual describes the "event" attribute "widget" as "The widget
which generated this event. This is a valid Tkinter widget instance, not
a name. This attribute is set for all events."
Ans so it is--has been until on the latest occasion "event.widget" was
not the widget, but its name, crashing the handler.
# Here I build a list of selectable records having each four fields.
# The fields are labels. The selectable line is a frame containing the
# labels side by side. The line frames go into self, which is a Frame.

for n in range (len (records)):
record = records [n]
line_frame = Frame (self, name = '-%d-' % n, relief = RAISED, **BUTTON_FRAME_)
line_frame.bind ('<Enter>', self.enter)
line_frame.bind ('<Leave>', self.leave)
line_frame.bind ('<ButtonRelease-1>', self.pick_record)
line_frame.bind ('<ButtonRelease-3>', self.info_profile)
line_frame.grid (row = n+2, column = 1)
for i in self.range_n_fields: # (0, 1, 2, 3)
field = Label (line_frame, text = record [self.INDICES [i]], anchor = W, width = self.COLUMN_WIDTHS [i], **DB_LIST_LABEL_)
field.grid (row = 0, column = i, sticky = NW)

# Here is the <Enter> handler:

def enter (self, event):
w = event.widget
print 'hit list.enter (). Event, widget', event, w, w.__class__ # Tracing line
w.config (bg = SELECTED_BG_COLOR)

# And here is what comes out. The first line is my tracing line. The name is correct in that it
# names the entered line_frame, but is wrong because it should be the line_frame, not its name.
# The rest is the red exception message:

hit list.enter (). Event, widget <Tkinter.Event instance at 0x9115dcc> .main-frame.data-frame.title-hit-list.-10- <type 'str'>
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib/python2.6/lib-tk/Tkinter.py", line 1413, in __call__
return self.func(*args)
File "/home/fr/python/finance/piam/hit_list.py", line 83, in enter
w.config (bg = SELECTABLE_BG_COLOR)
AttributeError: 'str' object has no attribute 'config'

# The same thing happens with <Leave>. The other handlers I haven't done yet. The same bindings work well in
# a Menu class with the difference that the bindings are on the Labels, not a containing Frame.

# Dell E6500, Ubuntu 10.04, Python 2.6


Frederic


Terry Reedy

unread,
Jul 9, 2012, 1:58:48 AM7/9/12
to pytho...@python.org
On 7/8/2012 5:19 PM, Frederic Rentsch wrote:
> Hi widget wizards,
>
> The manual describes the "event" attribute "widget" as "The widget
> which generated this event. This is a valid Tkinter widget instance, not
> a name. This attribute is set for all events."

Same in 3.3, with nice example of using it.

def turnRed(self, event):
event.widget["activeforeground"] = "red"

self.button.bind("<Enter>", self.turnRed)

> Ans so it is--has been until on the latest occasion "event.widget" was
> not the widget, but its name, crashing the handler.

Has event.widget been the widget only in other programs or previously
with the same program?



> # Here I build a list of selectable records having each four fields.
> # The fields are labels. The selectable line is a frame containing the
> # labels side by side. The line frames go into self, which is a Frame.
>
> for n in range (len (records)):

for n, record in enumerate(records):

> record = records [n]
> line_frame = Frame (self, name = '-%d-' % n, relief = RAISED, **BUTTON_FRAME_)
> line_frame.bind ('<Enter>', self.enter)
> line_frame.bind ('<Leave>', self.leave)
> line_frame.bind ('<ButtonRelease-1>', self.pick_record)
> line_frame.bind ('<ButtonRelease-3>', self.info_profile)
> line_frame.grid (row = n+2, column = 1)
> for i in self.range_n_fields: # (0, 1, 2, 3)
> field = Label (line_frame, text = record [self.INDICES [i]], anchor = W, width = self.COLUMN_WIDTHS [i], **DB_LIST_LABEL_)
> field.grid (row = 0, column = i, sticky = NW)

When posting problem code, you should post a minimal, self-contained
example that people can try on other systems and versions. Can you
create the problem with one record, which you could give, and one
binding? Do you need 4 fields, or would 1 'work'?


> # Here is the <Enter> handler:
>
> def enter (self, event):
> w = event.widget
> print 'hit list.enter (). Event, widget', event, w, w.__class__ # Tracing line
> w.config (bg = SELECTED_BG_COLOR)
>
> # And here is what comes out. The first line is my tracing line. The name is correct in that it
> # names the entered line_frame, but is wrong because it should be the line_frame, not its name.
> # The rest is the red exception message:
>
> hit list.enter (). Event, widget <Tkinter.Event instance at 0x9115dcc> .main-frame.data-frame.title-hit-list.-10- <type 'str'>
> Exception in Tkinter callback
> Traceback (most recent call last):
> File "/usr/lib/python2.6/lib-tk/Tkinter.py", line 1413, in __call__
> return self.func(*args)
> File "/home/fr/python/finance/piam/hit_list.py", line 83, in enter
> w.config (bg = SELECTABLE_BG_COLOR)
> AttributeError: 'str' object has no attribute 'config'
>
> # The same thing happens with <Leave>. The other handlers I haven't done yet. The same bindings work well in
> # a Menu class with the difference that the bindings are on the Labels, not a containing Frame.
>
> # Dell E6500, Ubuntu 10.04, Python 2.6

You might try a current Python release, and the latest tcl/tk 8.5.11
released last March (comes with 3.3.0 Windows release, don't know how on
Ubuntu). There might be (have been?) a bug with events on Frames, or on
Frames within Frames treated as widgets.

--
Terry Jan Reedy

Rick Johnson

unread,
Jul 9, 2012, 1:49:07 PM7/9/12
to
On Jul 9, 12:58 am, Terry Reedy <tjre...@udel.edu> wrote:
> When posting problem code, you should post a minimal, self-contained
> example that people can try on other systems and versions. Can you
> create the problem with one record, which you could give, and one
> binding? Do you need 4 fields, or would 1 'work'?

I'll firmly back that sentiment. Fredric, if you cannot get the
following simple code events to work properly, then how do you think
you can get events working properly on something more complex?

## START CODE ARTISTRY ##
import Tkinter as tk
from Tkconstants import *

class MyFrame(tk.Frame):
def __init__(self, master, **kw):
tk.Frame.__init__(self, master, **kw)
self.bind('<Enter>', self.evtMouseEnter)
self.bind('<Leave>', self.evtMouseLeave)
self.bind('<Button-1>', self.evtButtonOneClick)

def evtMouseEnter(self, event):
event.widget.config(bg='magenta')

def evtMouseLeave(self, event):
event.widget.config(bg='SystemButtonFace')

def evtButtonOneClick(self, event):
event.widget.config(bg='green')

if __name__ == '__main__':
root = tk.Tk()
for x in range(10):
f = MyFrame(root, height=20, bd=1, relief=SOLID)
f.pack(fill=X, expand=YES, padx=5, pady=5)
root.mainloop()
## END CODE ARTISTRY ##

-----------------------
More points to ponder:
-----------------------
1. Just because the Tkinter designers decided to use idiotic names for
event sequences does not mean you are required to blindly follow their
bad example (the whole: "if johnny jumps off a cliff...", thing comes
to mind)

2. I would strongly recommend you invest more thought into your event
handler identifiers. ALL event handlers should marked as *event
handlers* using a prefix. I like to use the prefix "evt". Some people
prefer other prefixes. In any case, just remember to be consistent.
Also, event handler names should reflect WHAT event they are
processing, not some esoteric functionality of the application like
"pick_record" or "info_profile". However if you like, simply have the
event handler CALL an outside func/meth. This type of consistency is
what separates the men from the boys.

3. The Python Style Guide[1] frowns on superfluous white space (be it
horizontal OR vertical!) I would strongly recommend you read and adapt
as much of this style as you possibly can bear. Even if we don't all
get along, it IS *very* important that we structure our code in a
similar style.

[1] http://www.python.org/dev/peps/pep-0008/

Terry Reedy

unread,
Jul 9, 2012, 3:45:38 PM7/9/12
to pytho...@python.org
I copied and pasted this self-contained code into a 3.3 Idle edit window
and lightly edited for 3.x. Change 'Tkinter' to 'tkinter', remove
tkconstants import and prefix constants with 'tk.'. (The alternative:
change 'tkconstants' to 'tkinter.constants', but I prefer prefixes). It
runs as expected.

import tkinter as tk

class MyFrame(tk.Frame):
def __init__(self, master, **kw):
tk.Frame.__init__(self, master, **kw)
self.bind('<Enter>', self.evtMouseEnter)
self.bind('<Leave>', self.evtMouseLeave)
self.bind('<Button-1>', self.evtButtonOneClick)

def evtMouseEnter(self, event):
event.widget.config(bg='magenta')

def evtMouseLeave(self, event):
event.widget.config(bg='SystemButtonFace')

def evtButtonOneClick(self, event):
event.widget.config(bg='green')

if __name__ == '__main__':
root = tk.Tk()
for x in range(10):
f = MyFrame(root, height=20, bd=1, relief=tk.SOLID)
f.pack(fill=tk.X, expand=tk.YES, padx=5, pady=5)
root.mainloop()

Add details and data (maybe less than 10 records) until you get what you
want or recreate problem.

--
Terry Jan Reedy



Frederic Rentsch

unread,
Jul 9, 2012, 4:39:45 PM7/9/12
to pytho...@python.org
On Mon, 2012-07-09 at 01:58 -0400, Terry Reedy wrote:
> On 7/8/2012 5:19 PM, Frederic Rentsch wrote:
> > Hi widget wizards,
> >
> > The manual describes the "event" attribute "widget" as "The widget
> > which generated this event. This is a valid Tkinter widget instance, not
> > a name. This attribute is set for all events."
>
> Same in 3.3, with nice example of using it.
>
> def turnRed(self, event):
> event.widget["activeforeground"] = "red"
>
> self.button.bind("<Enter>", self.turnRed)
>
> > Ans so it is--has been until on the latest occasion "event.widget" was
> > not the widget, but its name, crashing the handler.
>
> Has event.widget been the widget only in other programs or previously
> with the same program?

I bind <Enter> to Frames, each Frame calling the same handler that is
supposed to change the background color. It is the Enter action that
generates the event. No later the handler receives the event whose
attribute widget is the widget's name (full path). My code doesn't
create events anywhere. I suppose events vanish when the last handler
terminates.

. . .

> When posting problem code, you should post a minimal, self-contained
> example that people can try on other systems and versions.

Attempting to strip the critical code, throwing out everything
incidental to the problem so I could post something intelligible, I
failed to fail: the bare essentials work. The problem appears to be in
the incidental.

> Can you
> create the problem with one record, which you could give, and one
> binding? Do you need 4 fields, or would 1 'work'?
>
It fails even with the Frame containing no Labels at all, like this:

for n, record in enumerate(records):
line_frame = Frame (self, name = _verbalize_number (n), width = 600, height = 20, relief = RAISED, **BUTTON_FRAME_)
line_frame.bind ('<Enter>', self.enter)
## No Labels at all:
## for i in self.range_n_fields:
## field = Label (line_frame, text = record [self.INDICES [i]], anchor = W, width = self.COLUMN_WIDTHS [i], **DB_LIST_LABEL_)
## field.grid (row = 0, column = i, sticky = NW)

def enter (self, event):
w = event.widget
print 'hit list.enter (). Event, widget', event, w, w.__class__
w.config (bg = ENTERED_BG_COLOR)

hit list.leave (). Event, widget <Tkinter.Event instance at 0xa52c60c> .main-frame.data-frame.title-hit-list.one-zero <type 'str'>
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib/python2.6/lib-tk/Tkinter.py", line 1413, in __call__
return self.func(*args)
File "/home/fr/python/finance/piam/hit_list.py", line 114, in enter
w.config (bg = ENTERED_BG_COLOR)
AttributeError: 'str' object has no attribute 'config'

_verbalize_number spells out the line numbers, because the manual says
something about digits being reserved for the auto-generated widget
names. I thought that assigned names containing digits might be a
problem, but it wasn't.
The dictionary arguments, by the way, are just style elements:
colors, fonts, reliefs, etc. nothing functionally essential.

> >
> > # Dell E6500, Ubuntu 10.04, Python 2.6
>
> You might try a current Python release, and the latest tcl/tk 8.5.11
> released last March (comes with 3.3.0 Windows release, don't know how on
> Ubuntu). There might be (have been?) a bug with events on Frames, or on
> Frames within Frames treated as widgets.
>
> --
> Terry Jan Reedy
>

Terry,

I interspersed a couple of answers above. As to your last suggestion I
got Python 2.7.3 and managed to compile it. I would have preferred
something ready to install, but that doesn't seem to be available for
Linux. The compile went smoothly. But it'll take me another day to
reorganize, beginning with the Applications menu which still shows "IDLE
(Python 2.6)", while terminals already call the new version 2.7.3, but
it doesn't know where MySQLdb is, and possibly where other things are.
So for now I can't report on this effort either.

But I certainly appreciate your help. Many thanks.


Frederic


Frederic Rentsch

unread,
Jul 9, 2012, 4:47:09 PM7/9/12
to pytho...@python.org
Rick,
Thanks for your remarks. I spent most of the day working with Terry's
input. And now I am falling asleep. So I shall study your inspirations
tomorrow.

Frederic


Chris Angelico

unread,
Jul 9, 2012, 6:23:39 PM7/9/12
to pytho...@python.org
On Tue, Jul 10, 2012 at 3:49 AM, Rick Johnson
<rantingri...@gmail.com> wrote:
> ALL event handlers should marked as *event
> handlers* using a prefix. I like to use the prefix "evt". Some people
> prefer other prefixes. In any case, just remember to be consistent.
> Also, event handler names should reflect WHAT event they are
> processing, not some esoteric functionality of the application like
> "pick_record" or "info_profile". However if you like, simply have the
> event handler CALL an outside func/meth. This type of consistency is
> what separates the men from the boys.

Or perhaps it separates the half-elves from the hobgoblins.
Hard-and-fast rules are seldom valid in stylistic questions. There's
nothing wrong with having a prefix like "evt" or "on" or whatever;
there's also nothing wrong with a naming convention of PB_Open_Click
(PB for "PushButton" (which is what that GUI toolkit called them),
Open being what the button does, and Click is the event being handled
- that's the VX-REXX convention). Or having no specific event handler
and going straight to your "pick_record" function; that's fine too,
especially if you have multiple entry-points to that.

Frederic, you'll get a lot of advice on this list, but treat it as
just that - advice. There are very few actual rules; read what people
say and then make your own choices.

ChrisA

Frederic Rentsch

unread,
Jul 10, 2012, 6:03:34 AM7/10/12
to pytho...@python.org
On Mon, 2012-07-09 at 10:49 -0700, Rick Johnson wrote:
This works perfectly well!

What makes the case difficult is an exceptional misbehavior for no
apparent reason. If I manage to strip the critical section of
environmental details in the interest of concision and legibility and
still reproduce the error I shall post it. So far I have failed: the
stripped model I distilled yesterday worked fine.

> -----------------------
> More points to ponder:
> -----------------------
> 1. Just because the Tkinter designers decided to use idiotic names for
> event sequences does not mean you are required to blindly follow their
> bad example (the whole: "if johnny jumps off a cliff...", thing comes
> to mind)
>
> 2. I would strongly recommend you invest more thought into your event
> handler identifiers. ALL event handlers should marked as *event
> handlers* using a prefix. I like to use the prefix "evt". Some people
> prefer other prefixes. In any case, just remember to be consistent.
> Also, event handler names should reflect WHAT event they are
> processing, not some esoteric functionality of the application like
> "pick_record" or "info_profile". However if you like, simply have the
> event handler CALL an outside func/meth. This type of consistency is
> what separates the men from the boys.
>
> 3. The Python Style Guide[1] frowns on superfluous white space (be it
> horizontal OR vertical!) I would strongly recommend you read and adapt
> as much of this style as you possibly can bear. Even if we don't all
> get along, it IS *very* important that we structure our code in a
> similar style.
>
> [1] http://www.python.org/dev/peps/pep-0008/

Excellent suggestions.


Frederic


Rick Johnson

unread,
Jul 10, 2012, 6:11:02 PM7/10/12
to
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:

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?

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?

Rick Johnson

unread,
Jul 10, 2012, 9:06:10 PM7/10/12
to

Also:

Q3: Why are you explicitly setting the name of your "subFrame" widgets
instead of allowing Tkinter to assign a unique name?...AND are you
aware of the conflicts that can arise from such changes[1]?

Q4: Are you aware of the built-in function "enumerate"[2]? I see you
are passing around indexes to iterables AND simultaneously needing the
obj reference itself. I prefer to keep indexing to a minimum. If
there is no bleeding edge performance issue to worry about (and there
almost *always* never is) why not use enumerate?

[1] http://www.pythonware.com/library/tkinter/introduction/x147-more-on-widget-names.htm
[2] http://docs.python.org/release/3.0.1/library/functions.html#enumerate

Frederic Rentsch

unread,
Jul 11, 2012, 3:59:27 AM7/11/12
to pytho...@python.org
On Tue, 2012-07-10 at 18:06 -0700, Rick Johnson wrote:
> Also:
>
> Q3: Why are you explicitly setting the name of your "subFrame" widgets
> instead of allowing Tkinter to assign a unique name?...AND are you
> aware of the conflicts that can arise from such changes[1]?
>

I find custom-named widgets easier to work with during development. I can tell
what this is; ".main-frame.data-frame.title-hit-list.-10-". If I didn't assign
names it would look something line this:".2837029.283725.283762.2848308".
Once my program works I can drop custom-naming.
I understand that conflicts may arise if one assigns numeric names.
To find out whether the digits in the label names ('-10-' above) might
be implicated, I changed to spelled-out names ('ten'). The change had no
effect. The reference you list blow (x147-more-on-widget-names.htm)
indeed says "don't use names which only contain digits".

> Q4: Are you aware of the built-in function "enumerate"[2]? I see you
> are passing around indexes to iterables AND simultaneously needing the
> obj reference itself. I prefer to keep indexing to a minimum. If
> there is no bleeding edge performance issue to worry about (and there
> almost *always* never is) why not use enumerate?
>
Aware, yes. In the habit of, no. Thanks for the reminder.
Frederic


Frederic Rentsch

unread,
Jul 12, 2012, 2:53:54 PM7/12/12
to pytho...@python.org
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


Peter Otten

unread,
Jul 13, 2012, 3:26:31 AM7/13/12
to pytho...@python.org
Frederic Rentsch wrote:

> I'm sorry I can't post an intelligible piece that does NOT work. I
> obviously can't post the whole thing.

How about a pastebin then? Or even bitbucket/github as you need to track
changes anyway?

> It is way too convoluted.

"Convoluted" code is much easier to debug than no code ;)

Another random idea: run your code on a more recent python/tcl installation.
If you are lucky you get a different error.

Frederic Rentsch

unread,
Jul 13, 2012, 4:24:59 PM7/13/12
to pytho...@python.org
So many good ideas! I can hardly keep up. Let me try anyway.

I hesitate to ask dumb questions, but I guess I have to. What is
python/tcl? I enlisted Google, Synaptic, apt-cache, apt-get, dpkg and
scouring the profusion I couldn't detect any actionable piece of
information, undoubtedly due to my modest expertise in matters of system
administration.
I next spent a day with an attempt to upgrade to Python 2.7.3,
figuring that that might simultaneously take care of upgrading tcl.
Accustomed to installing packages I had to venture into the unknown
territory of compiling source, because no package was available.
(Windows, Apple, yes. Linux, no). The compile went smoothly, but ended
like this:

... build finished, but the necessary bits to build these modules were
not found:

_bsddb
_curses
_curses_panel
_sqlite3
_ssl
_tkinter
bsddb185
bz2
dbm
gdbm
readline
sunaudiodev

To find the necessary bits, look in setup.py in detect_modules() for the
module's name.

I didn't know what to look for in setup.py, spent a couple of hours
turning stones and encountered evidence of a bunch of missing header
files, probably of other modules which I had installed rather than
compiled.
2.7.3 came up in terminals, but not in an IDLE window. No wonder,
_tkinter was reported not found; and so many others with it that,
anxious to get on, I stopped venturing further into this labyrinth,
erased everything 2.7.3 and now I'm back to 2.6 and would greatly
appreciate advice on upgrading python/tcl.

I shall look at pastebin and bitbucket/github right away.

Frederic


Terry Reedy

unread,
Jul 13, 2012, 7:23:53 PM7/13/12
to pytho...@python.org
On 7/13/2012 4:24 PM, Frederic Rentsch wrote:
> On Fri, 2012-07-13 at 09:26 +0200, Peter Otten wrote:

>> Another random idea: run your code on a more recent python/tcl installation.

That might have been clearer as python + tcl/tk installation.

> I next spent a day with an attempt to upgrade to Python 2.7.3,
> figuring that that might simultaneously take care of upgrading tcl.

No, two completely separate actions.

> ... build finished, but the necessary bits to build these modules were
> not found:
>
> _bsddb
> _curses
> _curses_panel
> _sqlite3
> _ssl
> _tkinter
> bsddb185
> bz2
> dbm
> gdbm
> readline
> sunaudiodev

I believe _tkinter is the only one of those you need to run idle.

You need tcl/tk installed/compiled first to compile python with
_tkinter. Easier on *nix than windows. Many *nix systems come with
tcl/tk or easily install it with their package managers (same with some
of the other prerequisites for other modules).

--
Terry Jan Reedy



Peter Otten

unread,
Jul 14, 2012, 3:47:30 AM7/14/12
to pytho...@python.org
Terry Reedy wrote:

> On 7/13/2012 4:24 PM, Frederic Rentsch wrote:
>> On Fri, 2012-07-13 at 09:26 +0200, Peter Otten wrote:
>
>>> Another random idea: run your code on a more recent python/tcl
>>> installation.
>
> That might have been clearer as python + tcl/tk installation.

Yes, sorry; I meant that both the python and tcl/tk version matter.
You can find out the latter with

$ python -c 'import Tkinter as tk; print tk.TclVersion, tk.TkVersion'
8.5 8.5

>> I next spent a day with an attempt to upgrade to Python 2.7.3,
>> figuring that that might simultaneously take care of upgrading tcl.
>
> No, two completely separate actions.
>
>> ... build finished, but the necessary bits to build these modules were
>> not found:
>>
>> _bsddb
>> _curses
>> _curses_panel
>> _sqlite3
>> _ssl
>> _tkinter
>> bsddb185
>> bz2
>> dbm
>> gdbm
>> readline
>> sunaudiodev
>
> I believe _tkinter is the only one of those you need to run idle.
>
> You need tcl/tk installed/compiled first to compile python with
> _tkinter. Easier on *nix than windows. Many *nix systems come with
> tcl/tk or easily install it with their package managers (same with some
> of the other prerequisites for other modules).

If you don't want to compile tcl/tk yourself you need to install the tk-dev
package. I recommend that you install libreadline-dev, too -- without
readline it is painful to use the interactive interpreter.


rantingri...@gmail.com

unread,
Jul 14, 2012, 11:10:27 PM7/14/12
to pytho...@python.org
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?

> 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.

## START TANGENTIAL MEANDERINGS ##
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.
## END TANGENTIAL MEANDERINGS ##

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.

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.
Message has been deleted

Frederic Rentsch

unread,
Jul 16, 2012, 6:32:09 AM7/16/12
to pytho...@python.org
On Sat, 2012-07-14 at 20:10 -0700, rantingri...@gmail.com 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!
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.

> ## START TANGENTIAL MEANDERINGS ##
> 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.
> ## END TANGENTIAL MEANDERINGS ##
>

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.


Frederic


0 new messages