tkinter puzzler

P

Paul Rubin

I have a gui with a bunch of buttons, labels, the usual stuff. It
uses the grid manager:

gui = Frame()
gui.grid()
gui.Label(....).grid() # put some widgets into the gui
... # more widgets

Now at the the very bottom of the gui, I want to add two more buttons,
let's say "stop" and "go". I want "stop" to appear in the gui's lower
left corner and "go" to appear in the gui's lower right corner.
Suppose that up to now, row 16 is the last row in the gui. Then this
works:

Button(gui, text="stop").grid(sticky=W) # starts row 17
Button(gui, text="go").grid(row=17, column=1, sticky=E)

But I don't really want that hardwired row number and I don't want to
keep counting rows and adjusting stuff if I stick new rows in the gui.
So I try the obvious, make one Frame widget containing both new buttons:
stopgo = Frame(gui)
Button(stopgo, "stop").grid(sticky=W)
Button(stopgo, "go").grid(sticky=E)

and try to stretch it across the bottom row of the gui:

stopgo.grid(sticky=E+W)

However, the buttons keep coming out centered in the gui's bottom row
pretty much no matter what I do (I've tried all sorts of combinations).

Am I missing something? I'm not a tkinter whiz and this stuff is
pretty confusing. I did come up with an ugly workaround that I'll
spare you the agony of seeing, but there should be a natural way to do
this.

Thanks for any advice.
 
M

Martin Franklin

Paul said:
I have a gui with a bunch of buttons, labels, the usual stuff. It
uses the grid manager:

gui = Frame()
gui.grid()
gui.Label(....).grid() # put some widgets into the gui
... # more widgets

Now at the the very bottom of the gui, I want to add two more buttons,
let's say "stop" and "go". I want "stop" to appear in the gui's lower
left corner and "go" to appear in the gui's lower right corner.
Suppose that up to now, row 16 is the last row in the gui. Then this
works:

Button(gui, text="stop").grid(sticky=W) # starts row 17
Button(gui, text="go").grid(row=17, column=1, sticky=E)

But I don't really want that hardwired row number and I don't want to
keep counting rows and adjusting stuff if I stick new rows in the gui.
So I try the obvious, make one Frame widget containing both new buttons:
stopgo = Frame(gui)
Button(stopgo, "stop").grid(sticky=W)
Button(stopgo, "go").grid(sticky=E)

and try to stretch it across the bottom row of the gui:

stopgo.grid(sticky=E+W)

However, the buttons keep coming out centered in the gui's bottom row
pretty much no matter what I do (I've tried all sorts of combinations).

Am I missing something? I'm not a tkinter whiz and this stuff is
pretty confusing. I did come up with an ugly workaround that I'll
spare you the agony of seeing, but there should be a natural way to do
this.

Thanks for any advice.

Sorry to say Paul but you may have to show us that ugly code! I'm no
whiz with the grid manager (I prefer pack!) but seeing your code will
help us help you

I suspect you need to look at the columnconfigure / rowconfigure methods
of the container (toplevel or frame)


Martin
 
P

Peter Otten

Paul Rubin wrote:

I think you are missing the columnconfigure()/rowconfigure() methods as
Martin Franklin pointed out. Anyway, here is some code to illustrate the
matter. I've found it helpful to use "false" colors to see what's going on.
the yellow 'main' frame contains the red 'north' and the blue 'south'
frame.

import Tkinter as tk

root = tk.Tk()
main = tk.Frame(root, bg="yellow")
main.pack(expand=True, fill="both")
main.columnconfigure(0, weight=1)
main.rowconfigure(0, weight=1)

north = tk.Frame(main, bg="red")
north.columnconfigure(1, weight=1)
for row, text in enumerate("alpha beta gamma delta".split()):
label = tk.Label(north, text=text)
label.grid(row=row, column=0, sticky="NW")
entry = tk.Entry(north)
entry.grid(row=row, column=1, sticky="NEW")
button = tk.Button(north, text=text.upper())
button.grid(row=row, column=2, sticky="NW")
north.rowconfigure(row, weight=1)
north.grid(column=0, row=0, sticky="NEW")

south = tk.Frame(main, bg="blue")
stop = tk.Button(south, text="Stop")
go = tk.Button(south, text="Go")
stop.grid(column=0, row=0)
go.grid(column=2, row=0)
# the empty column takes all the extra space
south.columnconfigure(1, weight=1)
south.grid(column=0, row=1, sticky="NSEW")

root.mainloop()

Peter
 
R

Russell E. Owen

Paul Rubin said:
I have a gui with a bunch of buttons, labels, the usual stuff. It
uses the grid manager:

gui = Frame()
gui.grid()
gui.Label(....).grid() # put some widgets into the gui
... # more widgets

Now at the the very bottom of the gui, I want to add two more buttons,
let's say "stop" and "go". I want "stop" to appear in the gui's lower
left corner and "go" to appear in the gui's lower right corner.
Suppose that up to now, row 16 is the last row in the gui. Then this
works:

Button(gui, text="stop").grid(sticky=W) # starts row 17
Button(gui, text="go").grid(row=17, column=1, sticky=E)

But I don't really want that hardwired row number and I don't want to
keep counting rows and adjusting stuff if I stick new rows in the gui.

A couple of options here:
- Put the main portion of the gui into one frame and pack or grid the
button frame below that. That sounds like a natural solution to this
problem based on the way you describe it. (if you do that, I suggest
packing the buttons into their frame; although I usually use the gridder
when in doubt, the packer is often the most natural layout manager for a
row of buttons).

- Increment as you go:
row = 0

wdg.grid(row=row, column=0, ...)
row += 1

wdg2.grid(row=row, column=0, ...)
row += 1

- If you are doing a lot of similar layout, it is worth creating a class
to do your gridding for you. Each instance grids widgets in a particular
frame. It keeps track of the row # for you. For use an existing
gridder, for instance RO.Wdg.Gridder in the RO package
So I try the obvious, make one Frame widget containing both new buttons:
stopgo = Frame(gui)
Button(stopgo, "stop").grid(sticky=W)
Button(stopgo, "go").grid(sticky=E)

and try to stretch it across the bottom row of the gui:

stopgo.grid(sticky=E+W)

This looks OK to me so I'm not sure what's wrong; I think I'd have to
see your actual code. I suggest examining the size of the stopgo frame
by setting its background color.

-- Russell
 
P

Paul Rubin

Martin Franklin said:
I suspect you need to look at the columnconfigure / rowconfigure methods
of the container (toplevel or frame)

Thanks, columnconfigure turned out to be the answer and Peter Otten's
post showing how to use it was very informative. For some reason
columnconfigure is not documented in the otherwise excellent tkinter
reference manual from New Mexico Tech.

I'm having sort of a different prob now, which is I want to make a
pulldown menu as commonly seen on web pages. The NMT reference
suggests using the MenuButton widget, which sort of works, though the
entrycget and entryconfigure methods that are supposedly on the menu
items aren't really there. The toolkit itself says that MenuButton is
now considered obsolete and Frederik Lundh's manual seems to say
to use Menu somehow instead, but I haven't quite figured out how.

Is there a preferred and normal way to do this? One thing I need is
to be able to disable individual menu choices based on stuff happening
in the application, which is why I wanted to use entryconfigure.

Also, I don't see how to get the little horizontal bar marker on the
button (as seen in IDLE) indicating that the button is a pulldown. A
minute examining the IDLE source code didn't show it either, though I
can probably find it there with more effort.

Thanks as usual.
 
R

Russell E. Owen

Paul Rubin said:
Thanks, columnconfigure turned out to be the answer and Peter Otten's
post showing how to use it was very informative. For some reason
columnconfigure is not documented in the otherwise excellent tkinter
reference manual from New Mexico Tech.

I'm having sort of a different prob now, which is I want to make a
pulldown menu as commonly seen on web pages. The NMT reference
suggests using the MenuButton widget, which sort of works, though the
entrycget and entryconfigure methods that are supposedly on the menu
items aren't really there. The toolkit itself says that MenuButton is
now considered obsolete and Frederik Lundh's manual seems to say
to use Menu somehow instead, but I haven't quite figured out how.

MenuButton is (as far as I know) the recommended way to do this
(and I've been puzzled by F. Lendh's assertion that they are
obsolete). The basics are:

mbut = Tkinter.Menubutton.(master, text="MyMenu", inicatoron=True)
mnu = Tkinter.Menu(mbut, tearoff=False)
mbut["menu"] = mnu

where indicatoron=True gives you the "this is a pop-up menu" indicator
icon. The circular reference is icky but appears to be necessary (i.e.
having the menubutton be a parent to the menu and the menu attribute of
the menubutton point to the menu).

I suggest you buy Grayson's "Python and Tkinter Programming"
(it has a very useful reference section in the back, though
unfortunately it is somewhat incomplete). For more serious work you'll
also want Welch's "Practical Programming in Tcl and Tk" (lots of good
details about Tk).

-- Russell
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,263
Messages
2,571,064
Members
48,769
Latest member
Clifft

Latest Threads

Top