4.3. Programa de Ejemplo de Empaquetado

Aquí está el código usado para crear la imagen anterior. Está profusamente comentado, así que no resultará complicado seguirlo. Es recomendable su ejecución y jugar posteriormente con él.

    1	#!/usr/bin/env python
    2	
    3	# ejemplo packbox.py
    4	
    5	import pygtk
    6	pygtk.require('2.0')
    7	import gtk
    8	import sys, string
    9	
   10	# Función auxiliar que crea una nueva HBox llena de botones con etiqueta. Los argumentos
   11	# de las variables en las que tenemos interés se pasan a esta función. No mostramos la
   12	# caja pero sí todo lo que contiene.
   13	
   14	def make_box(homogeneous, spacing, expand, fill, padding):
   15	
   16	    # Creamos una nueva HBox con los parámetros homogeneous
   17	    # y spacing adecuados.
   18	    box = gtk.HBox(homogeneous, spacing)
   19	
   20	    # Creamos una serie de botones con los parámetros adecuados
   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	    # Creamos un botón con una etiqueta que depende del valor de
   30	    # expand.
   31	    if expand == gtk.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	    # Aquí hacemos lo mismo que en la creación del botón de "expand"
   40	    # anterior, pero usa la forma abreviada.
   41	    button = gtk.Button(("FALSE,", "TRUE,")[fill==gtk.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 gtk.FALSE
   56	
   57	    def __init__(self, which):
   58	
   59	        # Creamos nuestra ventana
   60	        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
   61	
   62	        # Siempre debemos recordar la conexión de la señal delete_event
   63	        # a la ventana principal. Esto es muy importante de cara a un comportamiento
   64	        # intuitivo adecuado
   65	        self.window.connect("delete_event", self.delete_event)
   66	        self.window.set_border_width(10)
   67	    
   68	        # Creamos una caja vertical (vbox) en la que empaquetar las cajas horizontales.
   69	        # Esto nos permite apilar las cajas horizontales llenas de botones
   70	        # una encima de otra en esta vbox.
   71	        box1 = gtk.VBox(gtk.FALSE, 0)
   72	    
   73	        # qué ejemplo mostramos. Éstos se corresponden a las imágenes anteriores.
   74	        if which == 1:
   75	            # creamos una etiqueta nueva.
   76	            label = gtk.Label("HBox(FALSE, 0)")
   77		
   78	            # Alineamos la etiqueta al lado izquierdo. Comentaremos este y otros
   79	            # métodos en la sección sobre Atributos de los Controles.
   80	            label.set_alignment(0, 0)
   81	
   82	            # Empaquetamos la etiqueta en la caja vertical (vbox box1).  Recuérdese que
   83	            # los controles que se añaden a una caja vertical se apilan uno encima del otro
   84	            # en orden.
   85	            box1.pack_start(label, gtk.FALSE, gtk.FALSE, 0)
   86		
   87	            # Mostramos la etiqueta
   88	            label.show()
   89		
   90	            # Llamamos a nuestra función de crear caja - homogeneous = FALSE, spacing = 0,
   91	            # expand = FALSE, fill = FALSE, padding = 0
   92	            box2 = make_box(gtk.FALSE, 0, gtk.FALSE, gtk.FALSE, 0)
   93	            box1.pack_start(box2, gtk.FALSE, gtk.FALSE, 0)
   94	            box2.show()
   95	
   96	            # Llamamos a nuestra función de crear caja - homogeneous = FALSE, spacing = 0,
   97	            # expand = TRUE, fill = FALSE, padding = 0
   98	            box2 = make_box(gtk.FALSE, 0, gtk.TRUE, gtk.FALSE, 0)
   99	            box1.pack_start(box2, gtk.FALSE, gtk.FALSE, 0)
  100	            box2.show()
  101		
  102	            # Los argumentos son: homogeneous, spacing, expand, fill, padding
  103	            box2 = make_box(gtk.FALSE, 0, gtk.TRUE, gtk.TRUE, 0)
  104	            box1.pack_start(box2, gtk.FALSE, gtk.FALSE, 0)
  105	            box2.show()
  106		
  107	            # Crea un separador, que veremos qué hacen más adelante,
  108	            # aunque son muy simples.
  109	            separator = gtk.HSeparator()
  110		
  111	            # Empaquetamos el separador en la vbox. Recuérdese que empaquetamos todos estos
  112	            # controles en una vbox, por lo que se apilarán
  113	            # verticalmente.
  114	            box1.pack_start(separator, gtk.FALSE, gtk.TRUE, 5)
  115	            separator.show()
  116		
  117	            # Creamos otra etiqueta y la mostramos.
  118	            label = gtk.Label("HBox(TRUE, 0)")
  119	            label.set_alignment(0, 0)
  120	            box1.pack_start(label, gtk.FALSE, gtk.FALSE, 0)
  121	            label.show()
  122		
  123	            # Los argumentos son: homogeneous, spacing, expand, fill, padding
  124	            box2 = make_box(gtk.TRUE, 0, gtk.TRUE, gtk.FALSE, 0)
  125	            box1.pack_start(box2, gtk.FALSE, gtk.FALSE, 0)
  126	            box2.show()
  127		
  128	            # Los argumentos son: homogeneous, spacing, expand, fill, padding
  129	            box2 = make_box(gtk.TRUE, 0, gtk.TRUE, gtk.TRUE, 0)
  130	            box1.pack_start(box2, gtk.FALSE, gtk.FALSE, 0)
  131	            box2.show()
  132		
  133	            # Otro separador.
  134	            separator = gtk.HSeparator()
  135	            # Los últimos 3 argumentos de pack_start son:
  136	            # expand, fill, padding.
  137	            box1.pack_start(separator, gtk.FALSE, gtk.TRUE, 5)
  138	            separator.show()
  139	        elif which == 2:
  140	            # Creamos una etiqueta nueva, recordando que box1 es una vbox creada
  141	            # cerca del comienzo de __init__()
  142	            label = gtk.Label("HBox(FALSE, 10)")
  143	            label.set_alignment( 0, 0)
  144	            box1.pack_start(label, gtk.FALSE, gtk.FALSE, 0)
  145	            label.show()
  146		
  147	            # Los argumentos son: homogeneous, spacing, expand, fill, padding
  148	            box2 = make_box(gtk.FALSE, 10, gtk.TRUE, gtk.FALSE, 0)
  149	            box1.pack_start(box2, gtk.FALSE, gtk.FALSE, 0)
  150	            box2.show()
  151		
  152	            # Los argumentos son: homogeneous, spacing, expand, fill, padding
  153	            box2 = make_box(gtk.FALSE, 10, gtk.TRUE, gtk.TRUE, 0)
  154	            box1.pack_start(box2, gtk.FALSE, gtk.FALSE, 0)
  155	            box2.show()
  156		
  157	            separator = gtk.HSeparator()
  158	            # Los últimos 3 argumentos de pack_start son:
  159	            # expand, fill, padding.
  160	            box1.pack_start(separator, gtk.FALSE, gtk.TRUE, 5)
  161	            separator.show()
  162		
  163	            label = gtk.Label("HBox(FALSE, 0)")
  164	            label.set_alignment(0, 0)
  165	            box1.pack_start(label, gtk.FALSE, gtk.FALSE, 0)
  166	            label.show()
  167		
  168	            # Los argumentos son: homogeneous, spacing, expand, fill, padding
  169	            box2 = make_box(gtk.FALSE, 0, gtk.TRUE, gtk.FALSE, 10)
  170	            box1.pack_start(box2, gtk.FALSE, gtk.FALSE, 0)
  171	            box2.show()
  172		
  173	            # Los argumentos son: homogeneous, spacing, expand, fill, padding
  174	            box2 = make_box(gtk.FALSE, 0, gtk.TRUE, gtk.TRUE, 10)
  175	            box1.pack_start(box2, gtk.FALSE, gtk.FALSE, 0)
  176	            box2.show()
  177		
  178	            separator = gtk.HSeparator()
  179	            # Los últimos 3 argumentos de pack_start son:
  180	            # expand, fill, padding.
  181	            box1.pack_start(separator, gtk.FALSE, gtk.TRUE, 5)
  182	            separator.show()
  183	
  184	        elif which == 3:
  185	
  186	            # Esto ilustra la posibilidad de usar pack_end() para
  187	            # alinear los controles a la derecha. Primero creamos una caja nueva, como antes.
  188	            box2 = make_box(gtk.FALSE, 0, gtk.FALSE, gtk.FALSE, 0)
  189	
  190	            # Creamos la etiqueta que pondremos al final.
  191	            label = gtk.Label("end")
  192	            # La empaquetamos con pack_end(), por lo que se pone en el extremo derecho
  193	            # de la hbox creada en la llamada a make_box().
  194	            box2.pack_end(label, gtk.FALSE, gtk.FALSE, 0)
  195	            # Mostramos la etiqueta.
  196	            label.show()
  197		
  198	            # Empaquetamos la box2 en box1
  199	            box1.pack_start(box2, gtk.FALSE, gtk.FALSE, 0)
  200	            box2.show()
  201		
  202	            # Un separador para la parte de abajo.
  203	            separator = gtk.HSeparator()
  204	            
  205	            # Esto establece explícitamente el ancho del separador a 400 píxeles y 5
  206	            # píxeles de alto. Así la hbox que creamos también tendría 400
  207	            # píxeles de ancho, y la etiqueta "end" estará separada de las otras
  208	            # de la hbox. En otro caso, todos los controles de la
  209	            # hbox estarían empaquetados lo más juntos posible.
  210	            separator.set_size_request(400, 5)
  211	            # empaquetamos el separador en la vbox (box1) creada cerca del principio
  212	            # de __init__()
  213	            box1.pack_start(separator, gtk.FALSE, gtk.TRUE, 5)
  214	            separator.show()
  215	    
  216	        # Creamos otra hbox nueva. ¡Recordemos que podríamos usar cuantas queramos!
  217	        quitbox = gtk.HBox(gtk.FALSE, 0)
  218	    
  219	        # Nuestro botón de salida.
  220	        button = gtk.Button("Quit")
  221	    
  222	        # Configuramos la señal que finalice el programa al pulsar el botón
  223	        button.connect("clicked", lambda w: gtk.main_quit())
  224	        # Empaquetamos el botón en la quitbox.
  225	        # Los 3 últimos argumentos de pack_start son:
  226	        # expand, fill, padding.
  227	        quitbox.pack_start(button, gtk.TRUE, gtk.FALSE, 0)
  228	        # empaquetamos la quitbox en la vbox (box1)
  229	        box1.pack_start(quitbox, gtk.FALSE, gtk.FALSE, 0)
  230	    
  231	        # Empaquetamos la vbox (box1), que ahora contiene todos los controles,
  232	        # en la ventana principal.
  233	        self.window.add(box1)
  234	    
  235	        # Y mostramos todo lo que queda
  236	        button.show()
  237	        quitbox.show()
  238	    
  239	        box1.show()
  240	        # Mostrando la ventana al final de forma que todo aparezca de una vez.
  241	        self.window.show()
  242	
  243	def main():
  244	    # y, naturalmente, el bucle de eventos principal.
  245	    gtk.main()
  246	    # El control se devuelve a este punto cuando se llama a main_quit().
  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()

El pequeño tour por el código packbox.py empieza por las lineas 14-50 que definen una función auxiliar make_box que crea una caja horizontal y la rellena con botones según los parámetros específicados. Devuelve una referencia a la caja horizontal.

Las lineas 52-241 definen el método de inicialización __init__() de la clase PackBox1 que crea una ventana y una caja vertical en ella que se rellena con una configuración de controles que depende del argumento que recibe. Si se le pasa un 1, las lineas 75-138 crean una ventana que muestra las cinco únicas posibilidades que resultan de variar los parámetros homogeneous, expand y fill. Si se le pasa un 2, las lineas 140-182 crean una ventana que muesstra las diferentes combinaciones de fill con spacing y padding. Finalmente, si se le pasa un 3, las lineas 188-214 crean una ventana que muestra el uso del método pack_start() para justificar los botones a la izquierda y el método pack_end() para justificar una etiqueta a la derecha. Las lineas 215-235 crean una caja horizontal que contiene un botón que se empaqueta dentro de la caja vertical. La señal 'clicked' del botón está conectada a la función PyGTK gtk.main_quit() para terminar el programa.

Las lineas 250-252 comprueban los argumentos de la línea de comandos y terminan el programa usando la función sys.exit() si no hay exactamente un argumento. La línea 251 crea una instancia de PackBox1. La línea 253 llama a la función gtk.main() para empezar el bucle de procesamiento de eventos GTK+.

En este programa de ejemplo, las referencias a los controles (excepto a la ventana) no se guardan en los atributos de instancia del objeto porque no se necesitan más tarde.