When I started to work with pyGTK, I had the impression that documentation is not as abundant and detailed as for learning the standard Python language in general. Among the most popular tutorials are an introduction to pyGTK by tutorialspoint.com and (so far my favourite) an intro by readthedocs.io. While these tutorials will explain the technical basics, I would have sometimes preferred a few more graphical illustrations to understand the effects of different commands to arrange graphical elements (‘widgets’) in a window.
A method frequently needed to arrange widgets in so called Box
containers that pops up in early introductory examples is pack_start
. I had a particular hard time of imagining what effects each of its parameters would have. So here’s a graphical illustration.
The function parameters
Taking the examples from the pyGTK tutorials and the official GTK documentation (which is not Python specific, but C++), the template for the pack_start
function is as follows:
1 |
box.pack_start(childWidget, expand, fill, padding) |
-
- Unsurprisingly,
box
is the destinationBox
object into which thechildWidget
is packed. childWidget
can be almost any widget – a Label, a CheckButton, a ComboBox, an image etc.expand
is of type boolean. If set toTrue
, Gtk will distribute all child objects with equal spaces in between. The name is a quite misleading, because the effect is not to alter the size of the object. Rather, the parameter influences the positioning of the object (with respect to the height of theVBox
or the width of anHBox
).Those who do PowerPoint will know the horizontally and vertically arrange buttons which have the same effect:- In case we have a
VBox
, the objects each object will be horizontally stretched to the full width of the VBox, and they will vertically be arranged so that the space before and after each object is identical. - In case we have an
HBox
, each widget will be vertically stretched to the full height of the box. Horizontally, the objects will be arranged so that the space before and after each object has the same width.
- In case we have a
- Similar ill-labelled is the
fill
parameter. First of all, the parameter is without any effect ifexpand
is set toFalse
. This parameter actually stretches each widget arranged along the Box object so that any blank space is filled (evidently, this does only make sense when the objects are aligned with equal spaces along the Box byexpand=True
. - The
padding
parameter has an equally strange defintion. According to the GTK+3 reference (which again isn’t Python specific) padding is basically the amount of Pixels that a widget is shifted along the orientation of the Box (i.e. horizontally to the right in case of an HBox, vertically to the bottom in case of a VBox) “over and above the global amount specified by the spacing property”. The spacing property is by default set to 0 and determines the distance of a widget from its neighbours.
- Unsurprisingly,
A less confusing way to name the function parameters would be something like:
1 |
box.pack_start(widget, arrange, stretch, padding) |
The Basic Code
The code I am using produces 4 objects (a Button, a CheckButton, a Label and a ComboBox) and puts them all in a VBox that fills the whole main window. As a consequence, the pack_start function is called 4 times – once each for placing the 4 objects.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk win = Gtk.Window(title='Demo') win.set_default_size(200, 300) win.connect('delete-event', Gtk.main_quit) vbox = Gtk.VBox(spacing=10) win.add(vbox) btn = Gtk.Button("Do not click here") chk = Gtk.CheckButton("Mit alles...") lbl = Gtk.Label("Alles für den Dackel") cmb = Gtk.ComboBox() vbox.pack_start(chk, False, True, 0) vbox.pack_start(btn, False, True, 0) vbox.pack_start(lbl, False, True, 0) vbox.pack_start(cmb, False, True, 0) win.show_all() Gtk.main() |
Parameter Testing
arrange = False
We start with calling pack_start
with arrange=False
as in the above base example:
1 2 3 4 |
vbox.pack_start(chk, True, False, 0) vbox.pack_start(btn, True, False, 0) vbox.pack_start(lbl, True, False, 0) vbox.pack_start(cmb, True, False, 0) |
Note without any arranging along the orientation of the Box object, the stretch
parameter is completely without any effect whether it’s set to True
or False
. The left Window in the image below is with padding=0
, the right image is with padding=20
for the second pack_start
command that packs the Button.
As expected, each widget is packed along the vertical orientation of the VBox. Note that pack_start
by enforces stretching each widget in its width to match the full width of the VBox. In case an HBox, pack_start
would stuff any widget without any horizontal space from left to right but would stretch any widget vertically to meet the height of the HBox.
We also see, that setting padding to a non-zero value enforces the space to the neighboring items before and after the widget that was packed with that padding value. The (vertical) distance between the preceding CheckBox and the Button has increased as well as the (vertical) distance between the Button and the following Label.
arrange = True, stretch = False
When calling pack_start
with arrange=True
and stretch=False
, Gtk spreads the widgets evenly on the vertical axis (in case of a VBox), with equal vertical white space being put before and after each widget.
Again to test for the effect of a non-zero padding
parameter, we have set padding=20
(this time for the first element packed which is the CheckBox). This increases the vertical space above and below the CheckBox by 20px while the remaining 3 widgets are equally spaced apart along the remaining vertical space.
arrange = True, stretch = True
Setting both arrange
and stretch
to True
will first distribute all widgets evenly spaced along the orientation of the box (i.e. vertically in case of a VBox and horizontally in case of an Hbox) and then stretch any widgets to fill the gaps left arranging the widgets with equal spacing.
Again, in order to observe the effect of the padding
parameter, padding
was set to 20
for one single widget (this time the Label widget, i.e. the 3rd element to be placed in the containing VBox) while all the others were set to 0
.
As expected setting padding=20
for the Label widget with arrange=True
will first align all widgets with equal vertical free space among them, then stretch=True
will stretch each widget equally in height (for VBox, width for Hbox) until all empty space between the widgets is consumed. Finally the Label will be extended 20px up and 20px down at the expanse of shrinking all remaining Labels proportionally.