4.3. Packing Demonstration Program

Here is the code used to create the above images. It's commented fairly heavily so I hope you won't have any problems following it. Run it yourself and play with it.

    1	#!/usr/bin/env python
    2	
    3	# example packbox.py
    4	
    5	import pygtk
    6	pygtk.require('2.0')
    7	import gtk
    8	import sys, string
    9	
   10	# Helper function that makes a new hbox filled with button-labels. Arguments
   11	# for the variables we're interested are passed in to this function.  We do
   12	# not show the box, but do show everything inside.
   13	
   14	def make_box(homogeneous, spacing, expand, fill, padding):
   15	
   16	    # Create a new hbox with the appropriate homogeneous
   17	    # and spacing settings
   18	    box = gtk.HBox(homogeneous, spacing)
   19	
   20	    # Create a series of buttons with the appropriate settings
   21	    button = gtk.Button("box.pack")
   22	    box.pack_start(button, expand, fill, padding)
   23	    button.show()
   24	
   25	    button = gtk.Button("(button,")
   26	    box.pack_start(button, expand, fill, padding)
   27	    button.show()
   28	
   29	    # Create a button with the label depending on the value of
   30	    # expand.
   31	    if expand == True:
   32	        button = gtk.Button("True,")
   33	    else:
   34	        button = gtk.Button("False,")
   35	
   36	    box.pack_start(button, expand, fill, padding)
   37	    button.show()
   38	
   39	    # This is the same as the button creation for "expand"
   40	    # above, but uses the shorthand form.
   41	    button = gtk.Button(("False,", "True,")[fill==True])
   42	    box.pack_start(button, expand, fill, padding)
   43	    button.show()
   44	
   45	    padstr = "%d)" % padding
   46	
   47	    button = gtk.Button(padstr)
   48	    box.pack_start(button, expand, fill, padding)
   49	    button.show()
   50	    return box
   51	
   52	class PackBox1:
   53	    def delete_event(self, widget, event, data=None):
   54	        gtk.main_quit()
   55	        return False
   56	
   57	    def __init__(self, which):
   58	
   59	        # Create our window
   60	        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
   61	
   62	        # You should always remember to connect the delete_event signal
   63	        # to the main window. This is very important for proper intuitive
   64	        # behavior
   65	        self.window.connect("delete_event", self.delete_event)
   66	        self.window.set_border_width(10)
   67	    
   68	        # We create a vertical box (vbox) to pack the horizontal boxes into.
   69	        # This allows us to stack the horizontal boxes filled with buttons one
   70	        # on top of the other in this vbox.
   71	        box1 = gtk.VBox(False, 0)
   72	    
   73	        # which example to show. These correspond to the pictures above.
   74	        if which == 1:
   75	            # create a new label.
   76	            label = gtk.Label("HBox(False, 0)")
   77		
   78	            # Align the label to the left side.  We'll discuss this method
   79	            # and others in the section on Widget Attributes.
   80	            label.set_alignment(0, 0)
   81	
   82	            # Pack the label into the vertical box (vbox box1).  Remember that 
   83	            # widgets added to a vbox will be packed one on top of the other in
   84	            # order.
   85	            box1.pack_start(label, False, False, 0)
   86		
   87	            # Show the label
   88	            label.show()
   89		
   90	            # Call our make box function - homogeneous = False, spacing = 0,
   91	            # expand = False, fill = False, padding = 0
   92	            box2 = make_box(False, 0, False, False, 0)
   93	            box1.pack_start(box2, False, False, 0)
   94	            box2.show()
   95	
   96	            # Call our make box function - homogeneous = False, spacing = 0,
   97	            # expand = True, fill = False, padding = 0
   98	            box2 = make_box(False, 0, True, False, 0)
   99	            box1.pack_start(box2, False, False, 0)
  100	            box2.show()
  101		
  102	            # Args are: homogeneous, spacing, expand, fill, padding
  103	            box2 = make_box(False, 0, True, True, 0)
  104	            box1.pack_start(box2, False, False, 0)
  105	            box2.show()
  106		
  107	            # Creates a separator, we'll learn more about these later, 
  108	            # but they are quite simple.
  109	            separator = gtk.HSeparator()
  110		
  111	            # Pack the separator into the vbox. Remember each of these
  112	            # widgets is being packed into a vbox, so they'll be stacked
  113	            # vertically.
  114	            box1.pack_start(separator, False, True, 5)
  115	            separator.show()
  116		
  117	            # Create another new label, and show it.
  118	            label = gtk.Label("HBox(True, 0)")
  119	            label.set_alignment(0, 0)
  120	            box1.pack_start(label, False, False, 0)
  121	            label.show()
  122		
  123	            # Args are: homogeneous, spacing, expand, fill, padding
  124	            box2 = make_box(True, 0, True, False, 0)
  125	            box1.pack_start(box2, False, False, 0)
  126	            box2.show()
  127		
  128	            # Args are: homogeneous, spacing, expand, fill, padding
  129	            box2 = make_box(True, 0, True, True, 0)
  130	            box1.pack_start(box2, False, False, 0)
  131	            box2.show()
  132		
  133	            # Another new separator.
  134	            separator = gtk.HSeparator()
  135	            # The last 3 arguments to pack_start are:
  136	            # expand, fill, padding.
  137	            box1.pack_start(separator, False, True, 5)
  138	            separator.show()
  139	        elif which == 2:
  140	            # Create a new label, remember box1 is a vbox as created 
  141	            # near the beginning of __init__()
  142	            label = gtk.Label("HBox(False, 10)")
  143	            label.set_alignment( 0, 0)
  144	            box1.pack_start(label, False, False, 0)
  145	            label.show()
  146		
  147	            # Args are: homogeneous, spacing, expand, fill, padding
  148	            box2 = make_box(False, 10, True, False, 0)
  149	            box1.pack_start(box2, False, False, 0)
  150	            box2.show()
  151		
  152	            # Args are: homogeneous, spacing, expand, fill, padding
  153	            box2 = make_box(False, 10, True, True, 0)
  154	            box1.pack_start(box2, False, False, 0)
  155	            box2.show()
  156		
  157	            separator = gtk.HSeparator()
  158	            # The last 3 arguments to pack_start are:
  159	            # expand, fill, padding.
  160	            box1.pack_start(separator, False, True, 5)
  161	            separator.show()
  162		
  163	            label = gtk.Label("HBox(False, 0)")
  164	            label.set_alignment(0, 0)
  165	            box1.pack_start(label, False, False, 0)
  166	            label.show()
  167		
  168	            # Args are: homogeneous, spacing, expand, fill, padding
  169	            box2 = make_box(False, 0, True, False, 10)
  170	            box1.pack_start(box2, False, False, 0)
  171	            box2.show()
  172		
  173	            # Args are: homogeneous, spacing, expand, fill, padding
  174	            box2 = make_box(False, 0, True, True, 10)
  175	            box1.pack_start(box2, False, False, 0)
  176	            box2.show()
  177		
  178	            separator = gtk.HSeparator()
  179	            # The last 3 arguments to pack_start are:
  180	            # expand, fill, padding.
  181	            box1.pack_start(separator, False, True, 5)
  182	            separator.show()
  183	
  184	        elif which == 3:
  185	
  186	            # This demonstrates the ability to use pack_end() to
  187	            # right justify widgets. First, we create a new box as before.
  188	            box2 = make_box(False, 0, False, False, 0)
  189	
  190	            # Create the label that will be put at the end.
  191	            label = gtk.Label("end")
  192	            # Pack it using pack_end(), so it is put on the right
  193	            # side of the hbox created in the make_box() call.
  194	            box2.pack_end(label, False, False, 0)
  195	            # Show the label.
  196	            label.show()
  197		
  198	            # Pack box2 into box1
  199	            box1.pack_start(box2, False, False, 0)
  200	            box2.show()
  201		
  202	            # A separator for the bottom.
  203	            separator = gtk.HSeparator()
  204	            
  205	            # This explicitly sets the separator to 400 pixels wide by 5
  206	            # pixels high. This is so the hbox we created will also be 400
  207	            # pixels wide, and the "end" label will be separated from the
  208	            # other labels in the hbox. Otherwise, all the widgets in the
  209	            # hbox would be packed as close together as possible.
  210	            separator.set_size_request(400, 5)
  211	            # pack the separator into the vbox (box1) created near the start 
  212	            # of __init__()
  213	            box1.pack_start(separator, False, True, 5)
  214	            separator.show()
  215	    
  216	        # Create another new hbox.. remember we can use as many as we need!
  217	        quitbox = gtk.HBox(False, 0)
  218	    
  219	        # Our quit button.
  220	        button = gtk.Button("Quit")
  221	    
  222	        # Setup the signal to terminate the program when the button is clicked
  223	        button.connect("clicked", lambda w: gtk.main_quit())
  224	        # Pack the button into the quitbox.
  225	        # The last 3 arguments to pack_start are:
  226	        # expand, fill, padding.
  227	        quitbox.pack_start(button, True, False, 0)
  228	        # pack the quitbox into the vbox (box1)
  229	        box1.pack_start(quitbox, False, False, 0)
  230	    
  231	        # Pack the vbox (box1) which now contains all our widgets, into the
  232	        # main window.
  233	        self.window.add(box1)
  234	    
  235	        # And show everything left
  236	        button.show()
  237	        quitbox.show()
  238	    
  239	        box1.show()
  240	        # Showing the window last so everything pops up at once.
  241	        self.window.show()
  242	
  243	def main():
  244	    # And of course, our main loop.
  245	    gtk.main()
  246	    # Control returns here when main_quit() is called
  247	    return 0         
  248	
  249	if __name__ =="__main__":
  250	    if len(sys.argv) != 2:
  251	        sys.stderr.write("usage: packbox.py num, where num is 1, 2, or 3.\n")
  252	        sys.exit(1)
  253	    PackBox1(string.atoi(sys.argv[1]))
  254	    main()

A brief tour of the packbox.py code starts with lines 14-50 which define a helper function make_box() that creates a horizontal box and populates it with buttons according to the specified parameters. A reference to the horizontal box is returned.

Lines 52-241 define the PackBox1 class initialization method __init__() that creates a window and a child vertical box that is populated with a different widget arrangement depending on the argument passed to it. If a 1 is passed, lines 75-138 create a window displaying the five unique packing arrangements that are available when varying the homogeneous, expand and fill parameters. If a 2 is passed, lines 140-182 create a window displaying the various combinations of fill with spacing and padding. Finally, if a 3 is passed, lines 188-214 create a window displaying the use of the pack_start() method to left justify the buttons and pack_end() method to right justify a label. Lines 215-235 create a horizontal box containing a button that is packed into the vertical box. The button "clicked" signal is connected to the PyGTK main_quit() function to terminate the program.

Lines 250-252 check the command line arguments and exit the program using the sys.exit() function if there isn't exactly one argument. Line 253 creates a PackBox1 instance. Line 254 invokes the main() function to start the GTK event processing loop.

In this example program, the references to the various widgets (except the window) are not saved in the object instance attributes because they are not needed later.