Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pack a tkinter widget underneath an existing widget that has been packed to the left side?

I'm attempting to write a basic Tkinter GUI that has a Text widget at the top, then a Button widget left aligned under it, then another Text widget underneath the button. The problem I'm having is, after packing the Button widget to the left, when I then go to pack the second Text widget, it puts it next to the button on the right, rather than underneath the button. This happens regardless of what I set the side argument to for the second Text widget Here's a simple piece of code that demonstrates this behaviour:

from Tkinter import *

root = Tk()

w = Text(root)
w.pack()

x = Button(root, text="Hi there!")
x.pack(side=LEFT)

y = Text(root)
y.pack(side=BOTTOM)

root.mainloop()

So how would I go about setting up the second Text widget so that it appears below the button, rather than to the right of it?

like image 783
Bryce Thomas Avatar asked Sep 28 '09 04:09

Bryce Thomas


People also ask

Can we use pack and place together in Tkinter?

Important: pack(), place(), and grid() should not be combined in the same master window.

What is the use of pack () function for the Tkinter widget?

The pack() fill option is used to make a widget fill the entire frame. The pack() expand option is used to expand the widget if the user expands the frame. fill options: NONE (default), which will keep the widget's original size.

Can I use grid and pack together?

You cannot use both pack and grid on widgets that have the same master. The first one will adjust the size of the widget. The other will see the change, and resize everything to fit it's own constraints. The first will see these changes and resize everything again to fit its constraints.

How do you use PADX and Pady in Tkinter?

The padx puts some space between the button widgets and between the closeButton and the right border of the root window. The pady puts some space between the button widgets and the borders of the frame and the borders of the root window. The okButton is placed next to the closeButton with 5 px space between them.


2 Answers

Do it the same way that WebView does using the Mosaic Canvas Widget Sets internals(which are very similar to Tk). The trick is that the second identical named Frame Object works as a Block Level Float(inline:block;) for everything placed after it and everything that calls "fr" already will automatically begin over inside of it.

You can have many doing this of TOP aligned widgets and simply add another identical named Frame where you want to break between side=LEFT's. Works after Bottom also.

fr=Frame(root)
fr.pack(fill=X, side=TOP)

block1=Label(fr)
block1.pack(side=LEFT)

block2=Label(fr)
block2.pack(side=LEFT)

block3=Button(fr)
block3.pack(side=LEFT)

# NAME IT THE SAME ID NAME AS THE FIRST MAIN FRAME...
fr=Frame(root)
fr.pack(fill=X, side=TOP)

# These NOW jump into the second Frame breaking the side=LEFT in new Frame
block4=Label(fr) 
block4.pack(side=LEFT)

block5=Label(fr)
block5.pack(side=LEFT)

# AND THEY CONTINUE GOING side=LEFT AFTERWARDS.
like image 134
rodeone2 Avatar answered Sep 21 '22 05:09

rodeone2


There are generally two solutions to layout problems:

  1. switch to using grid. It becomes real easy to do layouts like what you are trying to accomplish. Grid can solve probably 95% of all layout issues (it's amazing when you think about it -- Tk does with one manager what most toolkits need half a dozen to accomplish!)

  2. use multiple frames. If some widgets need to be stacked top-to-bottom and some left-to-right you can't always get what you want packing everything in a single frame. Use one frame for the top-to-bottom parts of the layout and additional frames for the left-to-right content.

Also realize that widgets don't have to be children of the widget in which they are packed/gridded. You can use the "in" parameter to put widgets in some other container than their parent.

For example, in your specific example you can create three frames, top, middle, bottom. Pack these top-to-bottom in your toplevel window. Then you can pack the first text widget in the top, the button or buttons horizontally in the middle, and the other text widget in the bottom.

The advantage to such an approach is that it makes it much easier to change the layout in the future (which in my experience always happens at some point). You don't have to re-parent any of your widgets, just pack/place/grid them in some other container.

In your short example it doesn't make much difference, but for complex apps this strategy can be a life saver.

My best advice is this: layout isn't an afterthought. Do a little planning, maybe even spend five minutes drawing on some graph paper. First decide on the major regions of your app and use a frame or some other container for each (paned window, notebook, etc). Once you have those, do the same divide-and-conquer approach for each section. This lets you use different types of layout for different sections of your app. Toolbars get horizontal layout, forms might get vertical layout, etc.

like image 45
Bryan Oakley Avatar answered Sep 21 '22 05:09

Bryan Oakley