0

I'm in a situation where I must use .pack() or .grid() alone to achieve specified widget sizes when they are laid out next to each other.

I used to mix .pack() with .grid() based on the knowledge gained in this post:

In what cases Tkinter's grid() cannot be mixed with pack()?

i.e., having frames packed next to each other, but inside each frame, I have grids. It worked fine, until I upgraded Tcl/TK backend to 8.6.8 in official Python 3.7.2, when I start seeing interpreter woes:

_tkinter.TclError: cannot use geometry manager grid inside . which already has slaves managed by pack

I then switched everything to .pack(), but now I have trouble to bring back my column designs where some widgets are wider than others.

Should I make everything .grid() to achieve this or are there secret ingredients in .pack() that I didn't see in docs?

Ideally I expect to achieve the following

  1. In a row of widgets, widgets are next to each other and fill the space as much as possible, similar to .pack(side='left', fill='x', expand=True)
  2. In the same row, I can still specify one widget to be wider than the rest, so that when setting everything to expand=True, the relative sizes are still in control.

Example

On macOS, the following code gives me wider entry and narrower slider, while I'd like the other way around, with just .pack().

import tkinter as tk
import tkinter.ttk as ttk


root = tk.Tk()
mainframe = tk.Frame(root, bg='blue')
mainframe.pack()
row1 = tk.Frame(mainframe, bg='red')
entry = ttk.Entry(row1, text='Search...')
slider = ttk.Scale(row1)
btn1 = ttk.Button(row1, text='Reset')
btn2 = ttk.Button(row1, text='Help')

entry.pack(side='left', fill='x', expand=True)
slider.pack(side='left', fill='x', expand=True)
btn1.pack(side='left', fill='x', expand=True)
btn2.pack(side='left', fill='x', expand=True)
row1.pack()

root.mainloop()

I must stress that I know how to use .grid() with my "rows" using .grid_columnconfigure(col, weight), which worked. It's just my working code (more complex than the above example, of course) simply broke after upgrading to TK 8.6, which implies that as my project gets bigger, mixed managers would be increasingly hard to maintain. So I decided to pick a camp between .pack() and .grid(). If one can achieve everything the other can at a cost, that'd be great.

kakyo
  • 10,460
  • 14
  • 76
  • 140
  • The error message is telling you exactly what is wrong -- you're using both grid and pack in the root window. As the question you linked to says, you can't do that. – Bryan Oakley Dec 27 '18 at 00:44
  • @BryanOakley Yes. My question is not about that, but how to achieve size portions with a row of widgets with `.pack()` alone. I'll update my question accordingly. – kakyo Dec 27 '18 at 00:54
  • 1
    The question is too vague. There are many ways to do layouts, the best way is highly dependent on exactly what behavior you want. If you're laying things out in columns, usually (though not always), grid is best since that's what it's designed for. Trying to achieve exact column widths can be challenging with pack, though it depends a lot on what other widgets are in each column. – Bryan Oakley Dec 27 '18 at 00:57
  • I suggest you make your question less vague by editing it and adding enought code to it so it's a runnable example (even if it doesn't do the layout the way you want). – martineau Dec 27 '18 at 01:06
  • @martineau I updated the question with an example. Thanks. – kakyo Dec 27 '18 at 03:38

2 Answers2

2

With pack, it is not possible to have some widgets expand more than others. Either they expand or they don't. If you want to maintain relative proportions, you must either force each widget to a specific size and only have the one widget expand, or you need to use something other than pack.

Since it's unclear precisely what you want to achieve, and you claim to have had a working solution with grid, I recommend sticking with grid. It appears that you're already using pack for the root window. A simple solution is to create a frame that you can add to the root with pack, and then put the widgets inside the frame with grid.

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
1

Personally, I would do everything in .grid() because it is just easier to maintain and much simpler once things get complicated than .pack() is. I used pack a while back and it took me ages to get stuff done because things ended up where I didn't want them. More on grid column sizing: http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/grid-config.html and Tkinter configure columnwidth

P.S. if you are into making GUI there is a library called Kivy which is great for this sort of stuff, just check it out (https://kivy.org/#home) if you're interested otherwise ya, use grid.

FUSIONCIDE
  • 11
  • 4
  • Thanks for the ideas. I'm aware of Kivy, Qt, wx, etc.. Many of them are great solutions. Right now, I'd love to use the stock solution of the Python runtime for easy distribution. – kakyo Dec 27 '18 at 03:41