Chapter 4. Packing Widgets

Table of Contents

4.1. Theory of Packing Boxes
4.2. Details of Boxes
4.3. Packing Demonstration Program
4.4. Packing Using Tables
4.5. Table Packing Example

When creating an application, you'll want to put more than one widget inside a window. Our first helloworld example only used one widget so we could simply use the gtk.Container add() method to "pack" the widget into the window. But when you want to put more than one widget into a window, how do you control where that widget is positioned? This is where packing comes in.

4.1. Theory of Packing Boxes

Most packing is done by creating boxes. These are invisible widget containers that we can pack our widgets into which come in two forms, a horizontal box, and a vertical box. When packing widgets into a horizontal box, the objects are inserted horizontally from left to right or right to left depending on the call used. In a vertical box, widgets are packed from top to bottom or vice versa. You may use any combination of boxes inside or beside other boxes to create the desired effect.

To create a new horizontal box, we use a call to gtk.HBox(), and for vertical boxes, gtk.VBox() . The pack_start() and pack_end() methods are used to place objects inside of these containers. The pack_start() method will start at the top and work its way down in a vbox, and pack left to right in an hbox. The pack_end() method will do the opposite, packing from bottom to top in a vbox, and right to left in an hbox. Using these methods allows us to right justify or left justify our widgets and may be mixed in any way to achieve the desired effect. We will use pack_start() in most of our examples. An object may be another container or a widget. In fact, many widgets are actually containers themselves, including the button, but we usually only use a label inside a button.

You may find when working with containers that the size (and aspect ratio) of your widget isn't quite what you would expect. That's an intentional consequence of the GTK+ box model. The size of any given widget is determined both by by how it packs among the widgets around it and whether or not its container offers it the possibility to expand and fill space available to it.

if you have a container a single child, this child will take up all its space minus its border:

Figure 4.1. Packing: A Single Widget in a Container

Packing: A Single Widget in a Container

If you have a container (say a VBox or HBox) with two (or more) children, they will fight[1] to determine who takes up more space:

Figure 4.2. Packing: Two Widgets in a Container

Packing: Two Widgets in a Container

How much each one actually gets is determined by:

  • the default and requested sizes of the widgets, which normally depends on their contents (for labels, in particular).

  • the expand and fill arguments supplied to add() or pack_start/pack_end(), all three of which we will describe in more detail later in this chapter:

    • expand=True means "I will fight for space"

    • expand=False means "I don't want more space"

    • fill=True means "If I got more space, I will occupy it with my content"

    • fill=False means "If I got more space, leave it blank"

This is important to understand when assembling your interfaces, and is the most peculiar thing about GTK+ programming to a newbie; although the packing-based widget geometry is more complex to understand initially than fixed-width layouts, it is superior because GTK+ windows actually resize properly.

To get an intuitive grasp of the box model, spend some time experimenting with the "packing" tab in Glade.

[1] A cute analogy; in reality fill, expansion, requested sizes, widget expansion semantics, container packing semantics, electron spins and lunar cycles are computed to determine how much space each widget wins.