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

Discussion in 'Python' started by Terry Reedy, Jul 9, 2012.

  1. Terry Reedy

    Terry Reedy Guest

    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 ], anchor = W, width = self.COLUMN_WIDTHS , **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
    Terry Reedy, Jul 9, 2012
    #1
    1. Advertising

  2. Terry Reedy

    Rick Johnson Guest

    On Jul 9, 12:58 am, Terry Reedy <> 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/
    Rick Johnson, Jul 9, 2012
    #2
    1. Advertising

  3. Terry Reedy

    Terry Reedy Guest

    On 7/9/2012 1:49 PM, Rick Johnson wrote:
    > On Jul 9, 12:58 am, Terry Reedy <> 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 ##


    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
    Terry Reedy, Jul 9, 2012
    #3
  4. On Mon, 2012-07-09 at 10:49 -0700, Rick Johnson wrote:
    > On Jul 9, 12:58 am, Terry Reedy <> 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/


    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
    Frederic Rentsch, Jul 9, 2012
    #4
  5. On Mon, 2012-07-09 at 10:49 -0700, Rick Johnson wrote:
    > On Jul 9, 12:58 am, Terry Reedy <> 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 ##
    >


    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
    Frederic Rentsch, Jul 10, 2012
    #5
  6. Terry Reedy

    Rick Johnson Guest

    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, Jul 10, 2012
    #6
  7. Terry Reedy

    Rick Johnson Guest

    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
    Rick Johnson, Jul 11, 2012
    #7
  8. 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.

    > [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
    Frederic Rentsch, Jul 11, 2012
    #8
  9. 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
    Frederic Rentsch, Jul 12, 2012
    #9
  10. Terry Reedy

    Peter Otten Guest

    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.
    Peter Otten, Jul 13, 2012
    #10
  11. On Fri, 2012-07-13 at 09:26 +0200, Peter Otten wrote:
    > 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.
    >


    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
    Frederic Rentsch, Jul 13, 2012
    #11
  12. Terry Reedy

    Terry Reedy Guest

    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
    Terry Reedy, Jul 14, 2012
    #12
  13. Terry Reedy

    Peter Otten Guest

    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.
    Peter Otten, Jul 14, 2012
    #13
  14. Terry Reedy

    Guest

    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 interferlike 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 beingsimultaneously 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 geometrymanagement 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.
    , Jul 15, 2012
    #14
  15. Terry Reedy

    Guest

    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 interferlike 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 beingsimultaneously 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 geometrymanagement 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.
    , Jul 15, 2012
    #15
  16. On Sat, 2012-07-14 at 20:10 -0700, 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.

    > ## 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
    Frederic Rentsch, Jul 16, 2012
    #16
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Jeff Epler
    Replies:
    0
    Views:
    490
    Jeff Epler
    Aug 20, 2004
  2. Replies:
    1
    Views:
    680
    Damien
    Feb 22, 2007
  3. K Viltersten
    Replies:
    0
    Views:
    364
    K Viltersten
    Aug 22, 2009
  4. Frederic Rentsch
    Replies:
    0
    Views:
    216
    Frederic Rentsch
    Jul 8, 2012
  5. Frederic Rentsch
    Replies:
    0
    Views:
    414
    Frederic Rentsch
    Jul 9, 2012
Loading...

Share This Page