Question

I'm trying to do something quite standard in GUI design using Python and Tkinter, and I can't figure it out. I'm trying to make something like the following:

+------+----------------------+
|      |                      |
|      |                      |
|      |                      |
|      |                      |
|      |                      |
|      |                      |
|      |                      |
|      |                      |
|      |                      |
|      |                      |
|      |                      |
|      |                      |
|      |                      |
|      |                      |
+------+----------------------+

Very simple setup with a sidebar and a main content area. I can manage to lay out the frames no problem, but the problem comes when I go to resize the window. I can get the sidebar to resize just fine, vertically but not horizontally and stuck to the left side, but the main content area refuses to fill the rest of the space horizontally. It's like the sidebar still takes up the same horizontal space even though it's set to resize only in the y direction.

Here's some very simple code to demonstrate what I mean:

from Tkinter import *

root = Tk()

# sidebar
sidebar = Frame(root, width=200, bg='white', height=500, relief='sunken', borderwidth=2)
sidebar.pack(expand=True, fill='y', side='left', anchor='nw')

# main content area
mainarea = Frame(root, bg='#CCC', width=500, height=500)
mainarea.pack(expand=True, fill='both', side='right')

root.mainloop()

And here's what happens when I try to resize it:

improperly-resizing layout

Any ideas? I mean, this has to be doable, right? It's practically a standard.

Was it helpful?

Solution

TL;DR: use fill="both" for the sidebar.

Overview of the problem

The extra space you are seeing belongs to the sidebar. Because you use expand=true for both widgets, they each are given part of the extra space when you resize the window. Since you didn't specify fill In the "x" direction for the sidebar, it's being given some of the extra space but it is not filling it. It is filling it in the "y" direction, just as you asked, and the main area is completely filling its space since it has fill="both".

You need to either have the sidebar fill in both the "x" and "y" dimension, or turn expand off to have it be a fixed size. Note: when I say "fixed size", it will still fill the area it is given if you use fill=both, but when you resize the window, all extra space will go to the main window.

Using a fixed size sidebar

To have a fixed size sidebar, turn expand off but set fill to be both. You want it to fill the area that was allocated to it, but you don't want that area to grow if the window gets bigger:

import Tkinter as tk

root = tk.Tk()

# sidebar
sidebar = tk.Frame(root, width=200, bg='white', height=500, relief='sunken', borderwidth=2)
sidebar.pack(expand=False, fill='both', side='left', anchor='nw')

# main content area
mainarea = tk.Frame(root, bg='#CCC', width=500, height=500)
mainarea.pack(expand=True, fill='both', side='right')

root.mainloop()

Using an expanding sidebar

To have a flexible-sized sidebar, turn expand on so that it will be given part of the extra space when you resize the window. You want fill to be both so that it fills the space that it is given.

import Tkinter as tk

root = tk.Tk()

# sidebar
sidebar = tk.Frame(root, width=200, bg='white', height=500, relief='sunken', borderwidth=2)
sidebar.pack(expand=True, fill='both', side='left', anchor='nw')

# main content area
mainarea = tk.Frame(root, bg='#CCC', width=500, height=500)
mainarea.pack(expand=True, fill='both', side='right')

root.mainloop()

Summary

The only difference between the two examples is the use of expand=True or expand=False. expand controls what happens to any extra space when the window resizes. When true, extra space is allocated to the widget, along with any other widgets that have expand set to true. In both cases, however, you want the sidebar to completely fill the area it has been given. So in both cases you want fill="both". fill only determines what the widget does with the area it has been given (fill it or not), but has no bearing on whether the widget gets more or less space that it asks for.

  • expand: whether the widget is given more space as the window resizes
  • fill: whether the widget fills the space it is given, or whether part of the space is left empty
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top