Manual Poo Pygtk
Manual Poo Pygtk
Manual Poo Pygtk
3
John Finlay
Rafael Villar Burke
Lorenzo Gil Sánchez
Iñigo Serna
Fernando San Martín Woerner
Resumen
Este tutorial describe el uso del módulo de Python PyGTK.
Tabla de contenidos
1. Introducción
1.1. Exploración de PyGTK
2. Primeros Pasos
2.1. Hola Mundo en PyGTK
2.2. Teoría de Señales y Retrollamadas
2.3. Eventos
2.4. Hola Mundo Paso a Paso
3. Avanzando
3.1. Más sobre manejadores de señales
3.2. Un Hola Mundo Mejorado
4. Empaquetado de Controles
4.1. Teoría de Cajas Empaquetadoras
4.2. Las Cajas en detalle
4.3. Programa de Ejemplo de Empaquetado
4.4. Uso de Tablas para el Empaquetado
4.5. Ejemplo de Empaquetado con Tablas
5. Perspectiva General de Controles
5.1. Jerarquía de Controles
5.2. Controles sin Ventana
6. El Control de Botón
6.1. Botones Normales
6.2. Botones Biestado (Toggle Buttons)
6.3. Botones de Activación (Check Buttons)
6.4. Botones de Exclusión Mútua (Radio Buttons)
7. Ajustes
7.1. Creación de un Ajuste
7.2. Utilización de Ajustes de la Forma Fácil
7.3. Interioridades de un Ajuste
8. Controles de Rango
8.1. Barras de Desplazamiento
8.2. Controles de Escala
8.2.1. Creación de un Control de Escala
8.2.2. Métodos y Señales (bueno, al menos métodos)
8.3. Métodos Comunes de los Rangos
8.3.1. Establecimiento de la Política de Actualización
8.3.2. Obtención y Cambio de Ajustes
8.4. Atajos de Teclas y Ratón
8.5. Ejemplo de Control de Rango
9. Miscelánea de Controles
9.1. Etiquetas
9.2. Flechas (Arrow)
9.3. El Objeto Pistas (Tooltip)
9.4. Barras de Progreso (ProgressBar)
9.5. Diálogos
9.6. Imágenes
9.6.1. Pixmaps
9.7. Reglas
9.8. Barras de Estado
9.9. Entradas de Texto (Entry)
9.10. Botones Aumentar/Disminuir
9.11. Lista Desplegable (Combo)
9.12. Calendario
9.13. Selección de Color
9.14. Selectores de Fichero
9.15. Diálogo de Selección de Fuentes
10. Controles Contenedores
10.1. La Caja de Eventos (EventBox)
10.2. El control Alineador
10.3. Contenedor Fijo (Fixed)
10.4. Contenedor de Disposición (Layout)
10.5. Marcos (Frame)
10.6. Marcos Proporcionales (AspectFrame)
10.7. Controles de Panel (HPaned y VPaned)
10.8. Vistas (Viewport)
10.9. Ventanas de Desplazamiento (ScrolledWindow)
10.10. Cajas de Botones (ButtonBoxes)
10.11. Barra de Herramientas (Toolbar)
10.12. Fichas (Notebook)
10.13. Elementos incrustables y puntos de conexión (Plugs y Sockets)
10.13.1. Elementos incrustables (Plugs)
10.13.2. Puntos de Conexión (Sockets)
11. Control Menú
11.1. Creación Manual de Menús
11.2. Ejemplo de Menú Manual
11.3. Uso de la Factoria de Elementos
11.4. Ejemplo de Factoria de Elementos - ItemFactory
12. Área de Dibujo
12.1. Contexto Gráfico
12.2. Métodos de Dibujo
13. Control de Vista de Texto
13.1. Perspectiva general de la Vista de Texto
13.2. Vistas de Texto
13.3. Buffers de Texto
13.3.1. Información de estado de un Buffer de Texto
13.3.2. Creación de Iteradores de Texto
13.3.3. Inserción, Obtención y Eliminación de Texto
13.3.4. Marcas de Texto (TextMark)
13.3.5. Creación y Uso de Etiquetas de Texto
13.3.6. Inserción de Imágenes y Controles
13.4. Iteradores de Texto
13.4.1. Atributos de los Iteradores de Texto
13.4.2. Atributos de Texto de un Iterador de Texto
13.4.3. Copiar un Iterador de Texto
13.4.4. Recuperar Texto y Objetos
13.4.5. Comprobar Condiciones en un Iterador de Texto
13.4.6. Comprobar la posición en un Texto
13.4.7. Movimiento a través del Texto
13.4.8. Moverse a una Posición Determinada
13.4.9. Búsqueda en el Texto
13.5. Marcas de Texto
13.6. Etiquetas de Texto y Tablas de Etiquetas
13.6.1. Etiquetas de Texto
13.6.2. Tablas de Etiquetas de Texto
13.7. Un ejemplo de Vista de Texto
14. Control de Vista de Árbol (TreeView)
14.1. Introducción
14.2. La Interfaz y Almacén de Datos TreeModel
14.2.1. Introducción
14.2.2. Creación de Objetos TreeStore (árbol) y ListStore (lista)
14.2.3. Cómo referirse a las filas de un modelo TreeModel
14.2.4. Adición de filas
14.2.5. Eliminación de Filas
14.2.6. Gestión de los datos de las filas
14.2.7. Soporte del protocolo de Python
14.2.8. Señales de TreeModel
14.2.9. Ordenación de filas de modelos TreeModel
14.3. TreeViews (Vistas de árbol)
14.3.1. Creación de un TreeView (vista de árbol)
14.3.2. Obtención y establecimiento del Modelo de un TreeView
14.3.3. Definición de las propiedades de un TreeView
14.4. Visualizadores de Celda (CellRenderer)
14.4.1. Introducción
14.4.2. Tipos de Visualizadores CellRenderer
14.4.3. Propiedade de un CellRenderer
14.4.4. Atributos de un CellRenderer
14.4.5. Función de Datos de Celda
14.4.6. Etiquetas de Marcado en CellRendererText
14.4.7. Celdas de Texto Editables
14.4.8. Celdas Biestado Activables
14.4.9. Programa de Ejemplo de Celda Editable and Activable
14.5. TreeViewColumns (columnas de vista de árbol)
14.5.1. Creación de TreeViewColumns (columnas de vista de árbol)
14.5.2. Gestión de los CellRenderers (Intérpretes de celda)
14.6. Manipulación de TreeViews
14.6.1. Gestión de las Columnas
14.6.2. Expansión y Contracción de Filas Hijas
14.7. Señales de TreeView
14.8. Selecciones TreeSelections
14.8.1. Obtención de TreeSelection
14.8.2. Modos de una selección TreeSelection
14.8.3. Obtención de la Selección
14.8.4. Uso de una Función de TreeSelection
14.8.5. Selección y Deselección de Filas
14.9. Arrastrar y Soltar en TreeView
14.9.1. Reordenación mediante Arrastrar y Soltar
14.9.2. Arrastar y Soltar Externo
14.9.3. Ejemplo de Arrastrar y Soltar en TreeView
14.10. TreeModelSort y TreeModelFilter
14.10.1. TreeModelSort (Modelo de Árbol Ordenado)
14.10.2. TreeModelFilter (Modelo de árbol filtrado)
14.11. El Modelo de Árbol Genérico (GenericTreeModel)
14.11.1. Visión general de GenericTreeMode
14.11.2. La Interfaz GenericTreeModel
14.11.3. Adición y Eliminación de Filas
14.11.4. Gestión de Memoria
14.11.5. Otras Interfaces
14.11.6. Utilización de GenericTreeModel
14.12. El Visualizador de Celda Genérico (GenericCellRenderer)
15. Nuevos Controles de PyGTK 2.2
15.1. Portapapeles (Clipboard)
15.1.1. Creación de un objeto Clipboard (Portapapeles)
15.1.2. Utilización de Clipboards con elementos Entry, Spinbutton y TextView
15.1.3. Incorporación de datos en un portapapeles
15.1.4. Obtención de los Contenidos del Portapapeles
15.1.5. Ejemplo de Portapapeles
16. Nuevos Controles de PyGTK 2.4
16.1. Objetos de Acción (Action) y Grupo de Acciones (ActionGroup)
16.1.1. Acciones (Actions)
16.1.2. Grupos de Acciones (ActionGroups)
16.2. Controles de Lista Desplegable (ComboBox) y Lista Desplegable con Entrada
(ComboBoxEntry)
16.2.1. Controles ComboBox
16.2.2. Controles ComboBoxEntry
16.3. Controles Botón de Color y de Fuente (ColorButton y FontButton)
16.3.1. Control Botón de Color (ColorButton)
16.3.2. Control Botón de Fuente (FontButton)
16.4. Controles de Entrada con Completado (EntryCompletion)
16.5. Controles de Expansión (Expander)
16.6. Selecciones de Archivos mediante el uso de Controles basados en el Selector
de Archivos FileChooser
16.7. El gestor de Interfaces de Usuario UIManager
16.7.1. Perspectiva general
16.7.2. Creación de un gestor UIManager
16.7.3. Adición y Eliminación de Grupos de Acciones (ActionGroups)
16.7.4. Descripciones de la Interfaz de Usuario
16.7.5. Adición y Eliminación de Descripciones de Interfaz de Usuario
16.7.6. Acceso a los Controles de la Interfaz de Usuario
16.7.7. Ejemplo sencillo de Gestor de Interfaz UIManager
16.7.8. Combinación de Descripciones de Interfaz de Usuario
16.7.9. Señales de UIManager
17. Controles sin documentar
17.1. Etiqueta de Aceleración (Atajo)
17.2. Menú de Opciones
17.3. Elementos de Menú
17.3.1. Elemento de Menú de Activación
17.3.2. Elemento de Menú de Exclusión Mútua
17.3.3. Elemento de Menú de Separación
17.3.4. Elemento de Menú de Cascada
17.4. Curvas
17.5. Diálogo de Mensaje
17.6. Curva Gamma
18. Establecimiento de Atributos de Controles
18.1. Métodos de Banderas de los Controles
18.2. Métodos de Visualización de Controles
18.3. Atajos de Teclado de los Controles
18.4. Métodos relacionados con el Nombre de los Controles
18.5. Estilo de los Controles
19. Temporizadores, Entrada/Salida y Funciones de Inactividad
19.1. Temporizadores
19.2. Monitorizar la Entrada/Salida
19.3. Funciones de Inactividad
20. Procesamiento Avanzado de Eventos y Señales
20.1. Métodos de Señales
20.1.1. Conectar y Desconectar Manejadores de Señal
20.1.2. Bloqueo y Desbloqueo de Manejadores de Señal
20.1.3. Emisión y Parada de Señales
20.2. Emisión y Propagación de Señales
21. Tratamiento de Selecciones
21.1. Descripción General de la Selección
21.2. Recuperar la Selección
21.3. Proporcionar la Selección
22. Arrastrar y Soltar
22.1. Descripción General de Arrastrar y Soltar
22.2. Propiedades de Arrastrar y Soltar
22.3. Métodos de Arrastrar y Soltar
22.3.1. Configuración del Control Origen
22.3.2. Señales en el Control Fuente
22.3.3. Configuración de un Control Destino
22.3.4. Señales en el Control Destino
23. Ficheros rc de GTK+
23.1. Funciones para Ficheros rc
23.2. Formato de los Ficheros rc de GTK+
23.3. Ejemplo de fichero rc
24. Scribble: Un Ejemplo Sencillo de Programa de Dibujo
24.1. Perspectiva General de Scribble
24.2. Manejo de Eventos
24.2.1. Scribble - Manejo de Eventos
24.3. El Control del Área de Dibujo, y Dibujar
25. Trucos para Escribir Aplicaciones PyGTK
25.1. El usario debería manejar la interfaz, no al contrario
25.2. Separa el modelo de datos de la interfaz
25.3. Cómo separar los Métodos de Retrollamada de los Manejadores de Señal
25.3.1. Introducción
25.3.2. Herencia
25.3.3. Herencia aplicada a PyGTK
26. Contribuir
27. Créditos
27.1. Créditos Original de GTK+
28. Copyright del Tutorial y Nota de Permisos
A. Señales de GTK
A.1. gtk.Object
A.2. gtk.Widget
A.3. GtkData
A.4. gtk.Container
A.5. gtk.Calendar
A.6. gtk.Editable
A.7. gtk.Notebook
A.8. gtk.List
A.9. gtk.MenuShell
A.10. gtk.Toolbar
A.11. gtk.Button
A.12. gtk.Item
A.13. gtk.Window
A.14. gtk.HandleBox
A.15. gtk.ToggleButton
A.16. gtk.MenuItem
A.17. gtk.CheckMenuItem
A.18. gtk.InputDialog
A.19. gtk.ColorSelection
A.20. gtk.StatusBar
A.21. gtk.Curve
A.22. gtk.Adjustment
B. Ejemplos de Código
B.1. scribblesimple.py
C. ChangeLog
Capítulo 1. Introducción
Tabla de contenidos
1.1. Exploración de PyGTK
PyGTK 2.0 es un conjunto de módulos que componen una interfaz Python para GTK+
2.0. En el resto de este documento cuando se menciona PyGTK se trata de la versión 2.0
o posterior de PyGTK, y en el caso de GTK+, también a su versión 2.0 y siguientes. El
sitio web de referencia sobre PyGTK es www.pygtk.org. El autor principal de PyGTK es:
James Henstridge [email protected]
GTK+ (GIMP Toolkit) es una librería que permite crear interfaces gráficas de usuario.
Se distribuye bajo la licencia LGPL, por lo que posibilita el desarrollo de software
abierto, software libre, e incluso software comercial no libre que use GTK sin necesidad
de pagar licencias o derechos.
Se le conoce como el toolkit de GIMP porque originalmente se escribió para desarrollar
el Programa de Manipulación de Imágenes de GNU GIMP, pero GTK+ se usa ya en
numerosos proyectos de software, incluído el proyecto de escritorio GNOME (Entorno
de Modelo de Objetos orientados a Red). GTK+ está diseñada sobre GDK (Kit de
Dibujo de GIMP) que, básicamente, es una abstracción de las funciones de bajo nivel
que acceden al sistema de ventanas (Xlib en el caso del sistema de ventanas X). Los
principales autores de GTK+ son:
Peter Mattis [email protected]
Spencer Kimball [email protected]
Josh MacDonald [email protected]
Actualmente GTK+ es mantenida por:
Owen Taylor [email protected]
Tim Janik [email protected]
En este ejemplo se crea una ventana que contiene un botón que imprime un mensaje
('¡Hola Mundo!') cuando se hace clic en él. El programa permite probar así fácilmente
los diversos controles de GTK+ y sus interfaces PyGTK.
También es útil el programa desarrollado por Brian McErlean para la receta de Activestate
65109 junto con algunas modificaciones para que funcione con PyGTK 2.X. En este
curso lo llamamos gpython.py y funciona de forma parecida al programa
pygtkconsole.py.
Nota
Estos dos programas no funcionan en Microsoft Windows porque necesitan
funciones específicas de Unix.
Capítulo 2. Primeros Pasos
Tabla de contenidos
2.1. Hola Mundo en PyGTK
2.2. Teoría de Señales y Retrollamadas
2.3. Eventos
2.4. Hola Mundo Paso a Paso
En este caso, la línea 1 pedirá al intérprete de Python que ejecute base.py. Las líneas 5-6
ayudan a diferenciar entre las distintas versiones de PyGTK que puedan estar instaladas
en el equipo. Estas líneas indican que se desea usar la versión 2.0 de PyGTK, que
comprende todas las versiones de PyGTK con 2 como número principal. Ello impide
que el programa utilice versiones anteriores de PyGTK, en caso de que se encuentren
instaladas en el sistema. Las líneas 18-20 comprueban si la variable __name__ es
"__main__", lo cual indica que el programa está siendo ejecutado directamente por
python y no está siendo importado en un intérprete Python. En el primer caso el
programa crea una nueva instancia de la clase Base y guarda una referencia a ella en la
variable base. Después llama la función main() para iniciar el bucle de procesamiento de
eventos de GTK.
Una ventana similar a Figura 2.1, “Ventana Simple PyGTK” debería aparecer en tu pantalla.
Figura 2.1. Ventana Simple PyGTK
La primera línea permite al programa base.py ser invocado desde una consola Linux o
Unix asumiendo que python se encuentre en el PATH. Esta línea aparecerá como
primera línea en todos los programas de ejemplo.
Las líneas 5-7 importan el módulo PyGTK 2 e inicializan el entorno GTK+. El módulo
PyGTK define las interfaces Python de las funciones GTK+ que se usarán en el
programa. Para quienes estén familiarizados con GTK+ hay que advertir que la
inicialización incluye la llamada a la función gtk_init(). También se configuran algunas
cosas por nosotros, tales como el visual por defecto, el mapa de colores, manejadores de
señales predeterminados. Asimismo comprueba los argumentos que se pasan al
programa desde la línea de comandos, en busca de alguno entre:
--gtk-module
--g-fatal-warnings
--gtk-debug
--gtk-no-debug
--gdk-debug
--gdk-no-debug
--display
--sync
--name
--class
En este caso, los borra de la lista de argumentos y deja los no coincidentes que no
reconoce para que el programa lo procese o ignore. El anterior conjunto de argumentos
son los que aceptan de forma estándar todos los programas GTK+.
Las líneas 9-15 definen una clase de Python llamada Base que define un método de
inicialización de instancia __init__(). La función __init__() crea una ventana de nivel
superior (línea 11) y ordena a GTK+ que la muestre (línea 12). La gtk.Window se crea
en la línea 11 con el argumentogtk.WINDOW_TOPLEVEL que indica que se desea una
ventana sometida a las decoraciones y posicionamiento del manejador de ventanas. En
vez de crear una ventana de tamaño 0x0, una ventana sin hijos tiene un tamaño
predeterminado de 200x200 de forma que se pueda manipular.
Las líneas 14-15 definen el método main() que llama a la función PyGTK main(), que
invoca el bucle principal de procesamiento de eventos de GTK+ para manejar eventos
de ratón y de teclado, así como eventos de ventana.
Las líneas 18-20 permiten al programa comenzar automáticamente si es llamado
directamente o pasado como argumento al intérprete de Python. En estos casos, el
nombre de programa que hay en la variable __name__ será la cadena "__main__" y el
código entre las líneas 18-20 se ejecutará. Si el programa se carga en un intérprete de
Python en ejecución, las líneas 18-20 no serán ejecutadas.
La línea 19 crea una instancia de la clase Base llamada base. Crea una gtk.Window y la
muestra como resultado.
La línea 20 llama al método main() de la clase Base, la cual comienza el bucle de
procesamiento de eventos de GTK+. Cuando el control llega a este punto, GTK+ se
dormirá a la espera de eventos de las X (como pulsaciones de teclas o botones), alarmas,
o notificaciones de entrada/salida de ficheros. En el ejemplo, sin embargo, los eventos
son ignorados.
2.1. Hola Mundo en PyGTK
Ahora seguimos con un programa con un control (un botón). Es la versión PyGTK del
clásico programa hola mundo (helloworld.py ).
1 #!/usr/bin/env python
2
3 # ejemplo helloworld.py
4
5 import pygtk
6 pygtk.require('2.0')
7 import gtk
8
9 class HelloWorld:
10
11 # Esta es una función de retrollamada. Se ignoran los argumentos de datos
12 # en este ejemplo. Más sobre retrollamadas más abajo.
13 def hello(self, widget, data=None):
14 print "Hello World"
15
16 def delete_event(self, widget, event, data=None):
17 # Si se devuelve FALSE en el gestor de la señal "delete_event",
18 # GTK emitirá la señal "destroy". La devolución de TRUE significa
19 # que no se desea la destrucción de la ventana.
20 # Esto sirve para presentar diálogos como: '¿Está seguro de que desea salir?'
21 #
22 print "delete event occurred"
23
24 # Si se cambia FALSE a TRUE la ventana principal no se
25 # destruirá con "delete_event".
26 return gtk.FALSE
27
28 # Otra retrollamada
29 def destroy(self, widget, data=None):
30 gtk.main_quit()
31
32 def __init__(self):
33 # se crea una ventana nueva
34 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
35
36 # Cuando se envía a una ventana la señal "delete_event" (esto lo hace
37 # generalmente el gestor de ventanas, usualmente con "cerrar", o con el
icono
38 # de la ventana de título), pedimos que llame la función delete_event ()
39 # definida arriba. Los datos pasados a la retrollamada son
40 # NULL y se ignoran en la función de retrollamada.
41 self.window.connect("delete_event", self.delete_event)
42
43 # Conectamos el evento "destroy" a un manejador de señal.
44 # Este evento sucede cuando llamamos gtk_widget_destroy() para la
ventana,
45 # o si devolvemos FALSE en la retrollamada "delete_event".
46 self.window.connect("destroy", self.destroy)
47
48 # Establece el grosor del borde de la ventana.
49 self.window.set_border_width(10)
50
51 # Crea un nuevo botón con la etiqueta "Hello World".
52 self.button = gtk.Button("Hello World")
53
54 # Cuando el botón recibe la señal "clicked", llamará la
55 # función hello() a la que pasa None como argumento. La función hello()
56 # se define más arriba.
57 self.button.connect("clicked", self.hello, None)
58
59 # Esto causará la destrucción de la ventana al llamar a
60 # gtk_widget_destroy(window) cuando se produzca "clicked". De nuevo,
61 # la señal podría venir de aquí o del gestor de ventanas.
62 self.button.connect_object("clicked", gtk.Widget.destroy, self.window)
63
64 # Esto empaqueta el botón en la ventana (un contenedor de GTK+).
65 self.window.add(self.button)
66
67 # El paso final es mostrar el control recién creado.
68 self.button.show()
69
70 # y la ventana
71 self.window.show()
72
73 def main(self):
74 # Todas las aplicaciones de PyGTK deben tener una llamada a gtk.main().
Aquí se deja
75 # el control y se espera que suceda un evento (como un evento de teclado o
ratón).
76 gtk.main()
77
78 # Si el programa se ejecuta directamente o se pasa como argumento al intérprete
79 # de Python, entonces se crea una instancia de HelloWorld y se muestra
80 if __name__ == "__main__":
81 hello = HelloWorld()
82 hello.main()
Figura 2.2, “Programa de ejemplo: Hola Mundo” muestra la ventana creada por helloworld.py.
del módulo PyGTK. En futuras secciones no se especificará el prefijo del módulo gtk,
pero se dará por asumido. Naturalmente, los programas de ejemplo usarán los prefijos
del módulo.
Nota
En la versión 2.0 de GTK+, el sistema de señales se ha movido de GTK+ a GLib. No
entraremos en detalles sobre las extensiones que GLib 2.0 tiene en relación con el
sistema de señales de GTK 1.2. Las diferecias no deberían notarse en el uso de PyGTK.
Antes de entrar en detalle en helloworld.py, discutiremos las señales y las retrollamadas.
GTK+ es una biblioteca orientada a eventos, lo que significa que se dormirá en la
función gtk.main() hasta que un evento ocurra y el control pase a la función apropiada.
Esta delegación del control se realiza usando la idea de "señales". (Nótese que estas
señales no son las mismas que las señales de los sistemas Unix, y no se implementan
usando éstas, aunque la terminología es casi idéntica) Cuando ocurre un evento, como
cuando presionamos un botón del ratón, la señal apropiada se "emite" por el el control
que fué presionado. Así es cómo GTK+ hace la mayoría de su trabajo útil. Hay señales
que todos los controles heredan, como "destroy", y hay señales que son específicas de
cada control, como "toggled" en el caso de un botón de activación.
Para hacer que un botón realice una acción, debemos configurar un manejador de
señales que capture estas señales y llame a la función apropiada. Esto se hace usando un
método de gtk.Widget (heredado de la clase GObject) como por ejemplo:
handler_id = object.connect(name, func, func_data)
donde object es la instancia de gtk.Widget (un control) que estará emitiendo la señal, y
el primer argumento name es una cadena que contiene el nombre de la señal que se
desea capturar. El segundo argumento, func, es la función que se quiere llamar cuando se
produce el evento. El tercer argumento,func_data, son los datos que se desean pasar a la
función func. El método devuelve un handler_id que se puede usar para desconectar o
bloquear el uso del manejador.
La función especificada en el tercer argumento se llama "función de retrollamada", y
generalmente tiene la forma:
def callback_func(widget, callback_data):
donde el primer argumento será una referencia al widget (control) que emitió la señal, y
el segundo (callback_data) una referencia a los datos dados como último argumento en
el método connect() mostrado antes.
Si la función de retrollamada es un método de un objeto entonces tendrá la forma
general siguiente:
def callback_meth(self, widget, callback_data):
donde self es la instancia del objeto que invoca este método. Esta es la forma usada en el
programa de ejemplo helloworld.py.
Nota
La forma anterior de declaración de una función de retrollamada a señales es sólo una
guía general, ya que las señales específicas de los distintos controles generan diferentes
parámetros de llamada.
Otra llamada que se usa en el ejemplo helloworld.py es:
handler_id = object.connect_object(name, func, slot_object)
2.3. Eventos
Además del mecanismo de señales descrito anteriormente, hay un conjunto de eventos
que reflejan el mecanismo de eventos de X. Las retrollamadas también se pueden
conectar a estos eventos. Estos eventos son:
event
button_press_event
button_release_event
scroll_event
motion_notify_event
delete_event
destroy_event
expose_event
key_press_event
key_release_event
enter_notify_event
leave_notify_event
configure_event
focus_in_event
focus_out_event
map_event
unmap_event
property_notify_event
selection_clear_event
selection_request_event
selection_notify_event
proximity_in_event
proximity_out_event
visibility_notify_event
client_event
no_expose_event
window_state_event
Para conectar una función de retrollamada a uno de estos eventos se usa el método
connect(), como se ha dicho anteriormente, usando uno de los nombres de eventos
anteriores en el parámetro name. La función (o método) de retrollamada para eventos es
ligeramente diferente de la usada para señales:
def callback_func(widget, event, callback_data):
gdk.Event es un tipo de objetos Python cuyos atributos de tipo indicarán cuál de los
eventos anteriores ha ocurrido. Los otros atributos del evento dependerán del tipo de
evento. Los valores posibles para los tipos son:
NOTHING
DELETE
DESTROY
EXPOSE
MOTION_NOTIFY
BUTTON_PRESS
_2BUTTON_PRESS
_3BUTTON_PRESS
BUTTON_RELEASE
KEY_PRESS
KEY_RELEASE
ENTER_NOTIFY
LEAVE_NOTIFY
FOCUS_CHANGE
CONFIGURE
MAP
UNMAP
PROPERTY_NOTIFY
SELECTION_CLEAR
SELECTION_REQUEST
SELECTION_NOTIFY
PROXIMITY_IN
PROXIMITY_OUT
DRAG_ENTER
DRAG_LEAVE
DRAG_MOTION
DRAG_STATUS
DROP_START
DROP_FINISHED
CLIENT_EVENT
VISIBILITY_NOTIFY
NO_EXPOSE
SCROLL
WINDOW_STATE
SETTING
Para acceder a estos valores se añade el prefijo gtk.gdk. al tipo de evento. Por ejemplo,
gtk.gdk.DRAG_ENTER.
Por tanto, para conectar una función de retrollamada a uno de estos eventos se usaría
algo como:
button.connect("button_press_event", button_press_callback)
Esto asume que button es un control gtk.Button. Entonces, cuando el ratón esté sobre el
botón y se pulse un botón del ratón, se llamará a la funciónbutton_press_callback. Esta
función se puede definir así:
def button_press_callback(widget, event, data):
El valor que devuelve esta función indica si el evento debe ser propagado por el sistema
de manejo de eventos GTK+. Devolviendo gtk.TRUE indicamos que el evento ha sido
procesado, y que no debe ser propagado. Devolviendo gtk.FALSE se continua el
procesamiento normal del evento. Es aconsejable consultar la sección Procesamiento
Avanzado de Eventos y Señales para obtener más detalles sobre el sistema de propagación.
Las APIs de selección y arrastrar y soltar de GDK también emiten unos cuantos eventos
que se reflejan en GTK+ por medio de señales. Consulta Señales en el Control de Orígen y
Señales en el Control de Destino para obtener más detalles sobre la sintaxis de las funciones
de retrollamada para estas señales:
selection_received
selection_get
drag_begin_event
drag_end_event
drag_data_delete
drag_motion
drag_drop
drag_data_get
drag_data_received
Las líneas 9-76 definen la clase HelloWorld, que contiene todas las retrollamadas como
métodos de objeto y el método de inicialización de objetos. Examinemos los métodos de
retrollamada:
Las líneas 13-14 definen el método de retrollamada hello() que será llamado al pulsar el
botón. Cuando se llama a este método, se imprime "Hello World" en la consola. En el
ejemplo ignoramos los parámetros de la instancia del objeto, el control y los datos, pero
la mayoría de las retrollamadas los usan. El parámetro data se define con un valor
predeterminado igual a None porque PyGTK no pasará ningún valor para los datos si no
son incluidos en la llamada a connect(); esto produciría un error ya que la retrollamada
espera tres argumentos y únicamente recibe dos. La definición de un valor por defecto
None permite llamar a la retrollamada con dos o tres parámetros sin ningún error. En
este caso el parámetro de datos podría haberse omitido, ya que el método hello() siempre
será llamado con sólo dos parámetros (nunca se usan los datos de usuario). En el
siguiente ejemplo usaremos el argumento de datos para saber qué botón fue pulsado.
def hello(self, widget, data=None):
print "Hello World"
Las líneas 32-71 definen el método de inicialización de instancia __init__() del objeto
HelloWorld, el cual crea la ventana y los controles que se usan en el programa.
La línea 34 crea una nueva ventana, pero no se muestra directamente hasta que
comunicamos a GTK+ que lo haga, casi al final del programa. La referencia a la ventana
se guarda en un atributo de instancia (self.window) para poder acceder a ella después.
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
Las líneas 41 y 46 ilustran dos ejemplos de cómo conectar un manejador de señal a un
objeto, en este caso a window. Aquí se captura el evento "delete_event" y la señal
"destroy". El primero se emite cuando cerramos la ventana a través del manejador de
ventanas o cuando usamos la llamada al método destroy() de gtk.Widget. La segunda se
emite cuando, en el manejador de "delete_event", devolvemos FALSE.
self.window.connect("delete_event", self.delete_event)
self.window.connect("destroy", self.destroy)
La línea 49 establece un atributo de un objeto contenedor (en este caso window) para
que tenga un área vacía de 10 píxeles de ancho a su alrededor en donde no se sitúe
ningún control. Hay otras funciones similares que se tratarán en la sección Establecimiento
de Atributos de Controles
self.window.set_border_width(10)
También vamos a usar este botón para salir del programa. La línea 62 muestra cómo la
señal "destroy" puede venir del manejador de ventanas, o de nuestro programa. Al hacer
clic en el botón, al igual que antes, se llama primero a la retrollamada hello(), y después
a la siguiente en el orden en el que han sido configuradas. Se pueden tener todas las
retrollamadas que sean necesarias, y se ejecutarán en el orden en el que se hayan
conectado.
Como queremos usar el método destroy() de la clase gtk.Widget que acepta un
argumento (el control que se va a destruir - en este caso window), utilizamos el método
connect_object() y le pasamos la referencia a la ventana. El método connect_object()
organiza el primer argumento de la retrollamada para que sea window en vez del botón.
Cuando se llama el método destroy() de la clase gtk.Widget se emite la señal "destroy"
desde la ventana, lo que a su vez provocará la llamada al métododestroy() de la clase
HelloWorld que termina el programa.
self.button.connect_object("clicked", gtk.Widget.destroy, self.window)
Ahora lo tenemos todo configurado como queremos. Con todos los manejadores de
señales, y el botón situado en la ventana donde debería estar, pedimos a GTK (líneas 66
y 69) que muestre los controles en pantalla. El control de ventana se muestra en último
lugar, para que la ventana entera aparezca de una vez y no primero la ventana y luego el
botón dentro de ella dibujándose. Sin embargo, con un ejemplo tan simple, sería difícil
apreciar la diferencia.
self.button.show()
self.window.show()
Las líneas 73-75 definen el método main() que llama a la función gtk.main()
def main(self):
gtk.main()
Ahora, cuando hagamos clic con el botón del ratón en el botón GTK, el control emitirá
una señal "clicked". Para poder usar esta información, nuestro programa configura un
manejador de señal que capture esta señal, la cual llama a la función que decidamos. En
nuestro ejemplo, cuando se pulsa el botón que hemos creado, se llama el método hello()
con un argumento None, y después se llama el siguiente manejador para esta señal. El
siguiente manejador llama a la función destroy() del control con la ventana como su
argumento y de esta manera causa que la ventana emita la señal "destroy", que es
capturada y llama al método destroy() de la clase HelloWorld
Otra función de los eventos es usar el manejador de ventanas para eliminar la ventana, lo
que causará que se emita "delete_event". Esto llamará a nuestro manejador de
"delete_event". Si devolvemos TRUE aquí, la ventana se quedará como si nada hubiera
pasado. Devolviendo FALSE hará que GTK+ emita la señal "destroy", que llama a la
retrollamada "destroy" de la clase HelloWorld cerrando GTK+.
Capítulo 3. Avanzando
Tabla de contenidos
3.1. Más sobre manejadores de señales
3.2. Un Hola Mundo Mejorado
Esta vez se puede ver que no hay forma fácil de salir del programa, y resulta necesario
usar el gestor de ventanas o la línea de comandos para eliminarlo. Un buen ejercicio para
el lector sería insertar un tercer botón "Salir" que cerrara el programa. Sería interesante
jugar con las opciones de pack_start() al tiempo que se lee la siguiente sección, así como
probar a cambiar de tamaño la ventana y observar qué sucede.
Como nota, hay que mencionar otra constante útil para gtk.Window()
- WINDOW_DIALOG. Este tipo de ventana interactúa de forma distinta con el gestor
de ventanas y debe usarse en ventanas de uso transitorio.
A continuación se describen en orden las pequeñas diferencias del código respecto a la
versión inicial del programa "Hola Mundo":
Como ya se ha dicho, no existe manejador del evento "destroy" en esta versión mejorada
de "Hola Mundo".
Las líneas 13-14 definen un método de retrollamada similar a la retrollamada hello() del
ejemplo inicial. La diferencia reside en que ahora la retrollamada imprime un mensaje
que incluye los datos que se le suministran.
La línea 27 pone título a la barra de título de la ventana (véase la Figura 3.1, “Ejemplo
mejorado de Hola Mundo”).
La línea 39 crea una caja horizontal (gtk.HBox) que almacena los dos botones que se
crean en las líneas 45 y 60. La línea 42 añade la caja horizontal al contenedor de la
ventana.
Las líneas 49 y 64 conectan el método callback() a la señal "clicked" de los botones. Y
cada botón establece una cadena diferente que se pasa al métodocallback() al ser
invocado.
Las líneas 53 y 66 empaquetan los botones en la caja horizontal. Y, finalmente, las líneas
57 y 70 indican a GTK+ que muestre los botones.
Las líneas 71-72 piden finalmente a GTK+ que muestre la caja y la ventana.
Capítulo 4. Empaquetado de Controles
Tabla de contenidos
4.1. Teoría de Cajas Empaquetadoras
4.2. Las Cajas en detalle
4.3. Programa de Ejemplo de Empaquetado
4.4. Uso de Tablas para el Empaquetado
4.5. Ejemplo de Empaquetado con Tablas
Cada línea contiene una caja horizontal (hbox) con varios botones. La llamada a pack es
una copia de la llamada a pack en cada uno de los botones de laHbox. Cada botón se
empaqueta en la hbox de la misma manera (con los mismos argumentos al método
pack_start() ).
Este es un ejemplo del método pack_start():
box.pack_start(child, expand, fill, padding)
box es la caja donde se empaqueta el objeto. El primer argumento, child, es el objeto que
se va a empaquetar. Por ahora los objetos serán botones, con lo que estaríamos
empaquetando botones dentro de cajas.
El argumento expand de pack_start() y pack_end() controla si los controles se disponen
de forma que ocupen todo el espacio extra de la caja y, de esta manera, ésta se expande
hasta ocupar todo el área reservada para ella (TRUE); o si se encoge para ocupar el
espacio justo de los controles (FALSE). Poner expand a FALSE permite justificar a la
derecha y a la izquierda los controles. Si no, se expandirán para llenar la caja, y el
mismo efecto podría obtenerse usando sólo o pack_start() o pack_end().
El argumento fill controla si el espacio extra se utiliza en los propios objetos (TRUE) o
como espacio extra en la caja alrededor de los objetos (FALSE). Sólo tiene efecto si el
argumento expand también es TRUE.
Python permite definir un método o función con valores de argumento predeterminados
y argumentos con nombre. A lo largo de este tutorial se verá la definición de las
funciones y métodos con valores predeterminados y argumentos con nombre cuando
sean de aplicación. Por ejemplo, el métodopack_start se define así:
box.pack_start(child, expand=gtk.TRUE, fill=gtk.TRUE, padding=0)
child, expand, fill y padding son palabras clave (argumentos con nombre). Los
argumentos expand, fill y padding tienen los valores predeterminados (o "por defecto")
mostrados arriba. El argumento child debe especificarse obligatoriamente al no tener un
valor predeterminado.
Las funciones que nos permiten crear una caja nueva son:
hbox = gtk.HBox(homogeneous=gtk.FALSE, spacing=0)
La instancia table es la tabla que se creó con gtk.Table(). El primer parámetro ("child")
es el control que se desea introducir en la tabla.
Los argumentos left_attach, right_attach, top_attach y bottom_attach especifican dónde
situar el control, y cuántas cajas usar. Si se quiere poner un botón en la esquina inferior
derecha de una tabla 2x2, y se quiere que ocupe SÓLO ese espacio, left_attach sería = 1,
right_attach = 2,top_attach = 1, bottom_attach = 2.
Ahora, si se desea que un control ocupe la fila entera de la tabla 2x2, se
pondría left_attach = 0, right_attach = 2, top_attach = 0, bottom_attach = 1.
Los argumentos xoptions e yoptions se usan para especificar opciones de colocación y
pueden unirse mediante la operación OR, permitiendo así múltiples opciones.
Estas opciones son:
Si la caja es más grande que el control, y se especificaFILL, el
FILL
control se expandirá hasta usar todo el espacio disponible.
Si se le asigna menos espacio a la tabla del que solicitó
(normalmente porque el usuario ha redimensionado la ventana),
SHRINK entonces los controles normalmente sería empujados a la parte
inferior de la ventana y desaparecerían. Si se especificaSHRINK,
los controles se encojerán con la tabla.
EXPAND Esto hará que la tabla se expanda para usar el espacio sobrante en
la ventana.
El Padding es igual que en las cajas, ya que crea un espacio vacío especificado en
píxeles alrededor del control.
También tenemos los métodos set_row_spacing() y set_col_spacing(), que añaden
espacio entre las filas en la columna o fila especificada.
table.set_row_spacing(row, spacing)
y
table.set_col_spacing(column, spacing)
Obsérvese que, para las columnas, el espacio va a la derecha de la columna, y, para las
filas, el espacio va debajo de la fila.
También se puede poner un espacio igual en todas las filas y/o columnas con:
table.set_row_spacings(spacing)
y,
table.set_col_spacings(spacing)
Obsérvese que con éstas funciones, la última fila y la última columna no obtienen
ningún espacio.
4.5. Ejemplo de Empaquetado con Tablas
El programa de ejemplo table.py crea una ventana con tres botones en una tabla 2x2.
Los primeros dos botones se colocarán en la fila superior. Un tercer botón, para salir, se
coloca en la fila inferior, y ocupa las dos columnas. La Figura 4.4, “Empaquetado haciendo
uso de una Tabla” ilustra la ventana resultante:
La clase Table se define en las líneas 9-78. Las líneas 12-13 definen el
método callback() que se llama al hacer "click" en dos de los botones. La retrollamada
sólo imprime un mensaje en la consola indicando qué botón se pulsó usando los datos
que se le pasan.
Las lineas 16-18 definen el método delete_event() que se llama cuando el manejador de
ventanas le pide a la ventana que se elimine.
Las líneas 20-78 definen el constructor de la clase Table __init__(). Crea una ventana
(línea 22), le pone el título (línea 25), conecta la retrollamadadelete_event() a la señal
"delete_event" (línea 29), y le pone el ancho al borde (línea 32). Se crea
una gtk.Table en la línea 35 y se añade a la ventana en la línea 38.
Los dos botones superiores se crean en las líneas 41 y 55, sus señales "clicked" se
conectan al método callback() en las líneas 45 y 59; y se añaden a la tabla en la primera
fila en las líneas 49 y 61. Las líneas 66-72 crean el botón "Quit", conectan su señal
"clicked" a la función mainquit() y lo añaden a la tabla ocupando la fila inferior
completa.
Capítulo 5. Perspectiva General de Controles
Tabla de contenidos
5.1. Jerarquía de Controles
5.2. Controles sin Ventana
show() le permite saber a GTK que hemos terminado de configurar los atributos del
control, y está listo para ser mostrado. También se puede usargtk.Widget.hide() para que
desaparezca otra vez. El orden en el que se muestran los controles no es importante, pero
es conveniente que se muestre la ventana al final de modo que la toda la ventana
aparezca de una vez y no se vea como van apareciendo los controles individuales en la
ventana a medida que se van formando. Los hijos de un control (una ventana también es
un control) no se mostrarán hasta que la propia ventana se muestre usando el
método show() .
si se especifica una etiqueta ésta se usa como texto del botón.Si se especifica stock éste
se usa para elegir un icono de serie y una etiqueta para el botón. Los elementos de serie
son:
STOCK_DIALOG_INFO
STOCK_DIALOG_WARNING
STOCK_DIALOG_ERROR
STOCK_DIALOG_QUESTION
STOCK_DND
STOCK_DND_MULTIPLE
STOCK_ADD
STOCK_APPLY
STOCK_BOLD
STOCK_CANCEL
STOCK_CDROM
STOCK_CLEAR
STOCK_CLOSE
STOCK_CONVERT
STOCK_COPY
STOCK_CUT
STOCK_DELETE
STOCK_EXECUTE
STOCK_FIND
STOCK_FIND_AND_REPLACE
STOCK_FLOPPY
STOCK_GOTO_BOTTOM
STOCK_GOTO_FIRST
STOCK_GOTO_LAST
STOCK_GOTO_TOP
STOCK_GO_BACK
STOCK_GO_DOWN
STOCK_GO_FORWARD
STOCK_GO_UP
STOCK_HELP
STOCK_HOME
STOCK_INDEX
STOCK_ITALIC
STOCK_JUMP_TO
STOCK_JUSTIFY_CENTER
STOCK_JUSTIFY_FILL
STOCK_JUSTIFY_LEFT
STOCK_JUSTIFY_RIGHT
STOCK_MISSING_IMAGE
STOCK_NEW
STOCK_NO
STOCK_OK
STOCK_OPEN
STOCK_PASTE
STOCK_PREFERENCES
STOCK_PRINT
STOCK_PRINT_PREVIEW
STOCK_PROPERTIES
STOCK_QUIT
STOCK_REDO
STOCK_REFRESH
STOCK_REMOVE
STOCK_REVERT_TO_SAVED
STOCK_SAVE
STOCK_SAVE_AS
STOCK_SELECT_COLOR
STOCK_SELECT_FONT
STOCK_SORT_ASCENDING
STOCK_SORT_DESCENDING
STOCK_SPELL_CHECK
STOCK_STOP
STOCK_STRIKETHROUGH
STOCK_UNDELETE
STOCK_UNDERLINE
STOCK_UNDO
STOCK_YES
STOCK_ZOOM_100
STOCK_ZOOM_FIT
STOCK_ZOOM_IN
STOCK_ZOOM_OUT
Las líneas 12-34 definen la función auxiliar xpm_label_box() que crea una caja
horizontal con un borde de ancho 2 (lineas 14-15) y le pone una imagen (lineas 22-23) y
una etiqueta (linea 26).
Las líneas 36-70 definen la clase Buttons. Las líneas 41-70 definen el método de
inicialización de instancia que crea una ventana (linea 43), le pone el título (linea 45), le
conecta las señales "delete_event" y "destroy" (lineas 48-49). La linea 55 crea el botón
sin etiqueta. Su señal "clicked" se conecta al método callback() en la linea 58. La
función xpm_label_box() se llama en la linea 61 para crear la imagen y la etiqueta que
se pondrán en el botón en la linea 64.
La función xpm_label_box() podría usarse para empaquetar archivos xpm y etiquetas en
cualquier control que pueda ser un contenedor.
El control Botón tiene las siguientes señales:
pressed - se emite cuando el botón del puntero se presiona en el control Botón
released - se emite cuando el botón del puntero se suelta en el control Botón
clicked - se emite cuando el botón del puntero se presiona y luego se
suelta sobre el control Botón
enter - se emite cuando el puntero entra en el control Botón
leave - se emite cuando el puntero sale del control Botón
Como se puede imaginar, estas llamadas funcionan igual que las llamadas al control de
botón normal. Si no se especifica etiqueta el botón estará vacio. El texto de la etiqueta se
analiza para comprobar si contiene caracteres mnemotécnicos con el prefijo '_'
Para obtener el estado de un botón biestado, incluyendo los botones de exclusión mútua
y los botones de activación, se utiliza el mecanismo del ejemplo anterior. Así se
comprueba el estado del biestado, llamando al método get_active() del objeto botón
biestado. La señal que nos interesa que emiten los botones biestado (el botón biestado, el
botón de activación y el botón de exclusión mútua) es la señal "toggled". Para
comprobar el estado de estos botones, se configura un manejador de señales para
capturar la señal toggled, y se accede a los atributos del objeto para determinar su
estado. La retrollamada será parecida a:
def toggle_button_callback(widget, data):
if widget.get_active():
# Si estamos aqui, el botón biestado está pulsado
else:
# Si estamos aqui, el botón biestado está levantado
Para forzar el estado de un botón biestado, y de sus hijos, el botón de exclusión mútua y
el botón de activación, se utiliza este método:
toggle_button.set_active(is_active)
El método anterior puede usarse para forzar el estado del botón biestado, y sus hijos los
botones de activación y de exclusión mútua. Especificando un
argumento TRUE o FALSE para el parámetro is_active indicamos si el botón debería
estar pulsado o levantado. Cuando el botón biestado se crea, su valor predeterminado es
levantado o FALSE.
Hay que fijarse en que, cuando se usa el método set_active(), y cambia realmente el
estado del botón, se produce la emisión de las señales "clicked" y "toggled" por éste.
toggle_button.get_active()
Este método devuelve el estado actual del botón biestado como un valor
booleano TRUE o FALSE.
El programa togglebutton.py proporciona un ejemplo simple del uso de botones
biestado. La figura Figura 6.2, “Ejemplo de Botón Biestado” ilustra la ventana resultante con
el segundo botón biestado activo:
Figura 6.2. Ejemplo de Botón Biestado
Las lineas interesantes son la 12-13, que definen el método callback() que imprime la
etiqueta del botón biestado y su estado cuando es activado. Las lineas 45 y 59 conectan
la señal "toggled" de los botones biestado al método callback().
El código es bastante simple de seguir. Las lineas 63-64 hacen que el botón "close" sea
el control por defecto, de manera que, al pulsar la tecla "Enter" cuando la ventana está
activa, el botón "close" emitirá la señal "clicked".
Capítulo 7. Ajustes
Tabla de contenidos
7.1. Creación de un Ajuste
7.2. Utilización de Ajustes de la Forma Fácil
7.3. Interioridades de un Ajuste
GTK tiene varios controles que pueden ser ajustados visualmente por el usuario usando
el ratón o el teclado, tales como los controles de rango, descritos en la sección Controles
de Rango. También hay unos cuantos controles que visualizan una parte ajustable de un
área de datos mayor, tales como el control de texto y el control de vista.
Obviamente, una aplicación necesita ser capaz de reaccionar ante los cambios que el
usuario realiza en los controles de rango. Una forma de hacer esto sería que cada control
emitiera su propio tipo de señal cuando su ajuste cambiara y, o bien pasar el nuevo valor
al manejador de señal, o requerir que se mire dentro de la estructura de datos del control
para ver el nuevo valor. Pero puede que también se quiera conectar los ajustes de varios
controles juntos, para que ajustando uno se ajusten los otros. El ejemplo más obvio de
esto es conectar una barra de desplazamiento a una vista o a un área de texto
desplazable. Si cada control tuviera su propia manera de manipular el valor del ajuste,
entonces el programador tendría que escribir sus propios manejadores de señales para
traducir entre la salida de la señal de un control y la entrada del método de ajuste de otro
control.
GTK soluciona este problema mediante el objeto Adjustment, que no es un control sino
una manera de que los controles almacenen y pasen la información de ajuste de una
forma abstracta y flexible. El uso más obvio de Adjustment es almacenar los parámetros
de configuración y los valores de los controles de rango, tales como las barras de
desplazamiento y los controles de escala. Sin embargo, como la
clase Adjustments deriva de Object, también tiene unas características especiales más
alla de ser estructuras de datos normales. La más importante es que pueden emitir
señales, como los controles, y estas señales no sólo pueden ser usadas para permitir a tus
programas reaccionar a la entrada de usuario en controles ajustables, sino que pueden
propagar valores de ajuste de una forma transparente entre controles ajustables.
Se verá como encajan los ajustes en todo el sistema cuando se vean los controles que los
incorporan: Barras de Progreso, Vistas, Ventanas de Desplazamiento, y otros.
7.1. Creación de un Ajuste
Muchos de los controles que usan ajustes lo hacen automáticamente, pero más tarde se
mostrarán casos en los que puede ser necesario crearlos. Es posible crear un ajuste
usando:
adjustment = gtk.Adjustment(value=0, lower=0, upper=0, step_incr=0, page_incr=0,
page_size=0)
Dada una instancia adj de la clase gtk.Adjustment, cada uno de los atributos se obtienen
o modifican usando adj.lower, adj.value, etc.
Ya que, cuando se determina el valor de un ajuste, generalmente también se quiere que
el cambio afecte a todos los controles que usan este ajuste, PyGTK proporciona un
método para hacer esto mismo:
adjustment.set_value(value)
Los diversos controles que usan el objeto Adjustment emitirán esta señal en un ajuste
siempre que cambien su valor. Esto ocurre tanto cuando el usuario hace que el
deslizador se mueva en un control de rango, como cuando el programa explícitamente
cambia el valor con el método set_value(). Así, por ejemplo, si se tiene un control de
escala, y se quiere que cambie la rotación de una imagen siempre que su valor cambie,
se podría crear una retrollamada como esta:
def cb_rotate_picture(adj, picture):
set_picture_rotation (picture, adj.value)
...
Los controles Range normalmente conectan un manejador para esta señal, el cual
cambia su apariencia para reflejar el cambio - por ejemplo, el tamaño del deslizador de
una barra de desplazamiento aumentará o se reducirá en proporción inversa a la
diferencia entre el valor superior e inferior de su ajuste.
Probablemente nunca será necesario que se haga la conexión de un manejador a esta
señal, salvo que se esté escribiendo un nuevo tipo de control de rango. En cualquier
caso, si se cambia directamente alguno de los valores de un Adjustment, se debe emitir
esta señal para reconfigurar los controles que lo usan. Tal que así:
adjustment.emit("changed")
Capítulo 8. Controles de Rango
Tabla de contenidos
8.1. Barras de Desplazamiento
8.2. Controles de Escala
8.2.1. Creación de un Control de Escala
8.2.2. Métodos y Señales (bueno, al menos métodos)
8.3. Métodos Comunes de los Rangos
8.3.1. Establecimiento de la Política de Actualización
8.3.2. Obtención y Cambio de Ajustes
8.4. Atajos de Teclas y Ratón
8.5. Ejemplo de Control de Rango
El argumento adjustment puede ser bien un ajuste que ya haya sido creado
con gtk.Adjustment(), o bien nada, en cuyo caso se crea un Adjustmentanónimo con
todos sus valores puestos a 0.0 (lo cual no es demasiado útil). Para evitar confusiones,
probablemente sea mejor crear un ajuste con un valorpage_size de 0.0 para que su
valor upper realmente corresponda con el valor más alto que el usuario puede
seleccionar. (Si esto resulta confuso, la sección sobre Ajustes da una explicación
detallada sobre qué hacen exactamente los ajustes y cómo crearlos y manipularlos.)
8.2.2. Métodos y Señales (bueno, al menos métodos)
Los controles de escala pueden visualizar su valor como un número al lado del canal. El
comportamiento por defecto es mostrar el valor, pero esto se puede cambiar con el
método:
scale.set_draw_value(draw_value)
Si pones el valor en un "lado" del canal (por ejemplo, en la parte de arriba o de abajo de
un control de escala horizontal), entonces seguirá al deslizador en su desplazamiento
hacia arriba y hacia abajo del canal.
UPDATE_DISC La señal "value_changed" sólo se mite una vez que el deslizador ha parado de
ONTINUOUS moverse y el usuario ha soltado el botón del ratón.
UPDATE_DELA La señal "value_changed" se emite cuando el usuario suelta el botón del ratón, o si
YED el deslizador deja de moverse durante un corto período de tiempo.
9.1. Etiquetas
Las etiquetas son objetos de la clase Label y se usan mucho en GTK, siendo además
relativamente simples. Los objetos Label no emiten señales ya que no tienen una
ventana X asociada. Si se necesita capturar señales, o hacer recorte, se deben colocar
dentro de un control EventBox (Caja de Eventos) o de un control Button (Botón).
Para crear una nueva etiqueta se usa:
label = gtk.Label(str)
El único argumento es la cadena de texto que se quiere que visualice la etiqueta. Para
cambiar el texto de la etiqueta después de la creación se usa el método:
label.set_text(str)
label es la etiqueta que se creó previamente, y str es la nueva cadena. El espacio que
necesite la nueva cadena se ajustará automáticamente si es necesario. Se pueden hacer
etiquetas multilinea poniendo saltos de linea en la cadena de la etiqueta.
Para obtener la cadena actual, se usa:
str = label.get_text()
label es la etiqueta que se ha creado, y str es la cadena que devuelve. El texto de una
etiqueta en label se puede justificar usando:
label.set_justify(jtype)
Obsérvese que la etiqueta "Filled, wrapped label" no tiene justificación completa (fill
justified).
arrow.set(arrow_type, shadow_type)
La primera crea un control flecha con el tipo y apariencia indicados. La segunda permite
cambiar cualquiera de estos valores. El argumento arrow_typepuede tomar uno de lo
siguientes valores:
ARROW_UP #(Arriba)
ARROW_DOWN #(Abajo)
ARROW_LEFT #(Izquierda)
ARROW_RIGHT #(Derecha)
Una vez que se ha creado una nueva pista, y el control que se quiere que la use está
preparado, simplemente se utiliza esta llamada para asociarlos:
tooltips.set_tip(widget, tip_text, tip_private=None)
El objeto tooltips es la pista que se acaba de crear. El primer argumento (widget) es el
control que se quiere que muestre la pista; el segundo argumento (tip_text), el texto que
se quiere visualizar. El último argumento (tip_private) es una cadena de texto que puede
usarse como identificador.
El programa de ejemplo tooltip.py modifica el programa arrow.py para añadir una pista
a cada botón. La figura Figura 9.3, “Ejemplo de Pistas” ilustra la ventana resultante con la
pista del segundo botón flecha activada:
Figura 9.3. Ejemplo de Pistas
Hay otros métodos que se pueden usar con las pistas. Simplemente los listaremos, junto
con una breve descripción sobre su función.
tooltips.enable()
Fija los milisegundos que deben transcurrir con el puntero sobre el control antes de que
la pista aparezca. El valor predefinido es de 500 milisegundos (medio segundo).
Y esos son todos los métodos asociados con las pistas. Más de lo que siempre se querría
saber :-)
9.4. Barras de Progreso (ProgressBar)
Las barras de progreso se usan para mostrar el estado de una operación. Son bastante
fáciles de usar, como se verá en el código que sigue. Pero primero empecemos con una
llamada para crear una nueva barra de progreso.
progressbar = gtk.ProgressBar(adjustment=None)
El argumento orientation puede tomar uno de los siguientes valores para indicar la
dirección en la que la barra de progreso se mueve:
PROGRESS_LEFT_TO_RIGHT # izquierda a derecha
PROGRESS_RIGHT_TO_LEFT # derecha a izquierda
PROGRESS_BOTTOM_TO_TOP # abajo a arriba
PROGRESS_TOP_TO_BOTTOM # arriba a abajo
Nota
Téngase en cuenta que set_text() no soporta el formateo de texto al
estilo printf() como lo hacía la barra de progreso de GTK+ 1.2.
Se puede desactivar la visualización de la cadena llamando a set_text() de nuevo sin
argumentos.
La cadena de texto actual de la barra de progreso se puede obtener con el siguiente
método:
text = progressbar.get_text()
Normalmente las Barras de Progreso usan cronómetros u otras funciones parecidas (mira
la sección sobre Cronómetros, E/S y Funciones de Inactividad) para dar la ilusión de
multitarea. Todas usarán los métodos set_fraction() o pulse() de la misma forma.
El programa progressbar.py proporciona un ejemplo de barra de progreso, actualizada
usando cronómetros. Este código también muestra como reiniciar la Barra de Progreso.
La figura Figura 9.4, “Ejemplo de Barra de Progreso” muestra la ventana resultante:
Figura 9.4. Ejemplo de Barra de Progreso
9.5. Diálogos
El control Dialog (Diálogo) es muy simple, y realmente es sólo una ventana con unas
cuantas cosas ya empaquetadas. Simplemente crea una ventana, y luego empaqueta
una VBox en ella, que contiene un separador y luego una HBox llamada "action_area"
("área de acción").
El control Dialog (Diálogo) se puede usar para mensajes emergentes para el usuario, y
otras tareas similares. Es realmente básico, y sólo hay una función para la caja de
diálogo, que es:
dialog = gtk.Dialog(title=None, parent=None, flags=0, buttons=None)
donde title (título) es el texto usado en la barra de título, parent (padre) es la ventana
principal de la aplicación y flags establece varios modos de operación para el diálogo:
DIALOG_MODAL - hace el diálogo modal
DIALOG_DESTROY_WITH_PARENT - destruye el diálogo cuando su padre sea destruido
DIALOG_NO_SEPARATOR - omite el separador entre la vbox y el área de acción
El argumento buttons (botones) es una tupla de pares texto de botón y respuesta. Todos
los argumentos tienen valores predeterminados y pueden especificarse usando palabras
clave.
Esto creará la caja de diálogo, y ahora depende del desarrollador el usarla. Se podría
empaquetar un botón en el área de acción:
button = ...
dialog.action_area.pack_start(button, TRUE, TRUE, 0)
button.show()
Y se podría añadir, por ejemplo, una etiqueta, al área vbox usando el empaquetamiento,
con algo así:
label = gtk.Label("Los diálogos molan")
dialog.vbox.pack_start(label, TRUE, TRUE, 0)
label.show()
Como ejemplo del uso de una caja de diálogo, se podrían poner dos botones en el área
de acción, un botón de Cancelar, un botón de Aceptar y una etiqueta en el área vbox,
haciendo una pregunta al usuario, informando de un error, etc. Luego se podrían
conectar diferentes señales a cada botón y realizar la operación que el usuario
seleccione.
Si la funcionalidad básica que proporcionan las cajas verticales y horizontales
predeterminadas no dan el suficiente control para la aplicación, entonces se puede
sencillamente empaquetar otro control dentro de las cajas proporcionadas. Por ejemplo,
se podría empaquetar una tabla en la caja vertical.
9.6. Imágenes
Las Images (Imágenes) son estructuras de datos que contienen dibujos. Estos dibujos se
pueden usar en varios sitios.
Las Images (Imágenes) se pueden crear a partir de Pixbufs, Pixmaps, archivos que
contengan información de imagen (por ejemplo. XPM, PNG, JPEG, TIFF, etc.), e
incluso ficheros de animación.
Las Images (Imágenes) se crean usando la función:
image = gtk.Image()
La forma más fácil de crear una imagen es usar el método set_from_file() que
automáticamente determina el tipo de imagen y la carga.
El programa images.py muestra cómo cargar varios tipos de imagen (goalie.gif, apple-
red.png, chaos.jpg, important.tif, soccerball.gif) en imágenes que se colocan dentro de
botones:
Figura 9.5. Ejemplo de Imágenes en Botones
9.6.1. Pixmaps
Los Pixmaps son estructuras de datos que contienen dibujos. Estos dibujos se pueden
usar en varios sitios, pero lo más común es usarlos como iconos en un escritorio X, o
como cursores.
Un pixmap con sólo 2 colores se llama bitmap, y hay unas cuantas rutinas adicionales
para trabajar con este caso especial.
Para entender los pixmaps, es de ayuda entender cómo funciona el sistema X Window.
En X, las aplicaciones no necesitan ejecutarse en el mismo ordenador que interactua con
el usuario. En cambio, estas aplicaciones, llamadas "clientes", se comunican con un
programa que muestra los gráficos y maneja el teclado y el ratón. Este programa que
interactua directamente con el usuario se llama un "servidor de visualización" o
"servidor X". Ya que la comunicación puede tener lugar sobre una red, es importante
mantener alguna información en el servidor X. Los Pixmaps, por ejemplo, se almacenan
en la memoria del servidor X. Esto significa que, una vez que los valores de un pixmap
se establecen, no hay que seguir transmitiendolos por la red; en lugar de eso, se envía un
comando para "mostrar el pixmap número XYZ aqui." Incluso si no se está usando X
con GTK simultáneamente, usando construcciones como Pixmaps hará que los
programas funcionen de forma aceptable en X.
Para usar pixmaps en PyGTK, primero debemos construir un gtk.gdk.Pixmap usando las
funciones de gtk.gdk en PyGTK. Los Pixmaps se pueden crear a partir de datos en
memoria, o a partir de datos leídos desde un fichero. Veamos cada una de las llamadas
usadas para crear un pixmap.
pixmap = gtk.gdk.pixmap_create_from_data(window, data, width, height, depth, fg,
bg)
Esta rutina se usa para crear un pixmap con la profundidad de color dada por el
argumento depth a partir de los datos data en memoria. Si depth es -1 su valor se deduce
de la de la ventana window. Cada pixel usa un número de bits de datos para representar
el color que es igual a la profundidad de color. Elwidth(ancho) y el height (alto) son en
pixeles. El argumento window (ventana) debe referirse a una gtk.gdk.Window realizada,
ya que los recursos de un pixmap sólo tienen sentido en el contexto de la pantalla donde
se va a visualizar. fg y bg son los colores de frente y fondo del pixmap.
Se pueden crear pixmaps desde ficheros XPM usando:
pixmap, mask = gtk.gdk.pixmap_create_from_xpm(window, transparent_color,
filename)
La última forma para crear un pixmap en blanco disponible para operaciones de dibujo
es:
pixmap = gtk.gdk.Pixmap(window, width, height, depth=-1)
Una desventaja de usar pixmaps es que que el objeto mostrado siempre es rectangular,
independientemente de la imagen. Nos gustaría crear escritorios y aplicaciones con
iconos que tengan formas más naturales. Por ejemplo, para la interfaz de un juego, nos
gustaría tener botones redondos para pulsar. La forma de hacer esto es usar ventanas con
forma.
Una ventana con forma es simplemente un pixmap en el que los pixeles de fondo son
transparentes. De esta forma, cuando la imagen de fondo se colorea, no la
sobreescribimos con un borde rectangular y que no encaja, de nuestro icono. El
programa de ejemplo wheelbarrow.p muestra una imagen completa en el escritorio. La
figura Figura 9.7, “Ejemplo de Ventana con Forma” muestra la imagen sobre una ventana de
terminal:
Figura 9.7. Ejemplo de Ventana con Forma
9.7. Reglas
Los controles Ruler (Regla) se usan para indicar la posición del puntero del ratón en una
ventana determinada. Una ventana puede tener una regla vertical a lo largo del ancho y
una regla horizontal a lo largo del alto. Un pequeño triángulo indicador en la regla
muestra la posición exacta del puntero respecto a la regla.
Antes de nada es necesario crear una regla. Las reglas horizontales y verticales se crean
usando las siguientes funciones:
hruler = gtk.HRuler() # regla horizontal
vruler = gtk.VRuler() # regla vertical
Una vez que se crea una regla podemos definir la unidad de medida. Las unidades de
medida para las reglas pueden ser PIXELS (píxeles), INCHES(pulgadas)
o CENTIMETERS (centímetros). Esto se fija con el método:
ruler.set_metric(metric)
Las marcas mostradas en la regla irán desde 0 a 800, con un número cada 100 píxeles. Si
en lugar de eso quisieramos una regla de 7 a 16, escribiríamos:
vruler.set_range(7, 16, 0, 20)
El indicador de la regla es una pequeña marca triangular que indica la posición del
puntero relativa a la regla. Si la regla se usa para seguir el puntero del ratón, la señal
"motion_notify_event" debe conectarse al método "motion_notify_event" de la regla.
Hay que configurar una retrollamada para "motion_notify_event" para el área y
usar connect_object() para que la regla emita una señal "motion_notify_signal":
def motion_notify(ruler, event):
return ruler.emit("motion_notify_event", event)
area.connect_object("motion_notify_event", motion_notify, ruler)
El programa de ejemplo rulers.py crea un área de dibujo con una regla horizontal en la
parte de arriba y una regla vertical a su izquierda. El tamaño del área de dibujo es de 600
píxeles de ancho por 400 píxeles de alto. La regla horizontal va desde 7 hasta 13 con una
marca cada 100 píxeles, mientras que la regla vertical va de 0 a 400 con una marca cada
100 píxeles. La colocación del área de dibujo y las reglas se hace con una tabla. La
figura Figura 9.8, “Ejemplo de Reglas” ilustra el resultado:
Figura 9.8. Ejemplo de Reglas
El código fuente es rulers.py:
1 #!/usr/bin/env python
2
3 # ejemplo rulers.py
4
5 import pygtk
6 pygtk.require('2.0')
7 import gtk
8
9 class RulersExample:
10 XSIZE = 400
11 YSIZE = 400
12
13 # Esta rutina toma el control cuando se pulsa el botón de cerrar
14 def close_application(self, widget, event, data=None):
15 gtk.main_quit()
16 return gtk.FALSE
17
18 def __init__(self):
19 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
20 window.connect("delete_event", self.close_application)
21 window.set_border_width(10)
22
23 # Crea una tabla para colocar la regla y el área de dibujo
24 table = gtk.Table(3, 2, gtk.FALSE)
25 window.add(table)
26
27 area = gtk.DrawingArea()
28 area.set_size_request(self.XSIZE, self.YSIZE)
29 table.attach(area, 1, 2, 1, 2,
30 gtk.EXPAND|gtk.FILL, gtk.FILL, 0, 0 )
31 area.set_events(gtk.gdk.POINTER_MOTION_MASK |
32 gtk.gdk.POINTER_MOTION_HINT_MASK )
33
34 # La regla horizontal está arriba. Cuando el ratón se mueve por el
35 # área de dibujo se pasa un evento motion_notify_event al manejador
36 # adecuado para la regla
37 hrule = gtk.HRuler()
38 hrule.set_metric(gtk.PIXELS)
39 hrule.set_range(7, 13, 0, 20)
40 def motion_notify(ruler, event):
41 return ruler.emit("motion_notify_event", event)
42 area.connect_object("motion_notify_event", motion_notify, hrule)
43 table.attach(hrule, 1, 2, 0, 1,
44 gtk.EXPAND|gtk.SHRINK|gtk.FILL, gtk.FILL, 0, 0 )
45
46 # La regla vertical está a la izquierda. Cuando el ratón se mueve por el
47 # área de dibujo se pasa un evento motion_notify_event al manejador
48 # adecuado para la regla
49 vrule = gtk.VRuler()
50 vrule.set_metric(gtk.PIXELS)
51 vrule.set_range(0, self.YSIZE, 10, self.YSIZE)
52 area.connect_object("motion_notify_event", motion_notify, vrule)
53 table.attach(vrule, 0, 1, 1, 2,
54 gtk.FILL, gtk.EXPAND|gtk.SHRINK|gtk.FILL, 0, 0 )
55
56 # Ahora mostramos todo
57 area.show()
58 hrule.show()
59 vrule.show()
60 table.show()
61 window.show()
62
63 def main():
64 gtk.main()
65 return 0
66
67 if __name__ == "__main__":
68 RulersExample()
69 main()
El primero, push(), se usa para añadir un nuevo mensaje a la statusbar (barra de estado).
Devuelve un message_id (identificador de mensaje), que puede usarse con el
método remove() para borrar el mensaje que cumpla la combinación
de message_id y context_id en la pila de la statusbar (barra de estado).
El método pop() elimina el mensaje que esté en la posición más alta de la pila con el
identificador de contexto context_id.
El programa de ejemplo statusbar.py crea una barra de estado y dos botones, uno para
insertar elementos en la barra de estado, y otro para sacar el último elemento fuera. La
figura Figura 9.9, “Ejemplo de Barra de Estado” muestra el resultado:
Figura 9.9. Ejemplo de Barra de Estado
El método set_text() fija el contenido del control Entry a text, remplazando el contenido
actual. Obsérvese que la clase Entry implementa la interfazEditable (sí, gobject soporta
interfaces al estilo de Java) que contiene algunas funciones más para manipular los
contenidos. Por ejemplo, el método:
entry.insert_text(text, position=0)
El método anterior permite intercambiar el estado de edición del control Entry pasándole
un valor TRUE o FALSE en el argumento is_editable.
Si estamos usando el control Entry y no queremos que el texto que se introduzca sea
visible, por ejemplo cuando una contraseña se escribe, podemos usar el siguiente
método, que además acepta una bandera booleana.
entry.set_visibility(visible)
Una región del texto se puede poner como seleccionada usando el siguiente método.
Esto se usaría sobre todo cuando se ponga algún valor predeterminado en un Entry,
haciendo fácil para el usuario el borrado.
entry.select_region(start, end)
El valor actual de un SpinButton se puede recuperar como un valor real o como un valor
entero usando los siguientes métodos:
float_value = spin_button.get_value()
int_value = spin_button.get_value_as_int()
Antes de que se pueda hacer esto, hay que componer una lista con las opciones que se
deseen.
Aqui tenemos el típico código para crear un conjunto de opciones:
slist = [ "String 1", "String 2", "String 3", "String 4" ]
combo.set_popdown_strings(slist)
En este punto ya se tiene una lista desplegable funcionando. Hay unos cuantos aspectos
de su comportamiento que se pueden cambiar. Esto se consigue con los métodos:
combo.set_use_arrows(val)
combo.set_use_arrows_always(val)
combo.set_case_sensitive(val)
9.12. Calendario
El control Calendar (Calendario) es una forma efectiva para visualizar y obtener
información relativa a fechas mensuales. Es un control muy fácil de usar y trabajar con
él.
Crear un control GtkCalendar es tan simple como:
calendar = gtk.Calendar()
Funcionan exactamente igual que los métodos freeze/thaw de cualquier otro control
(desactivando los cambios y reanudándolos).
El control Calendar tiene unas cuantas opciones que permiten cambiar la manera en la
que el control se visualiza y se comporta usando el método:
calendar.display_options(flags)
El control Calendar puede generar varias señales que indican la selección y cambio de la
fecha. Los nombres de estas señales son autoexplicativos, y son:
month_changed # cambio de mes
day_selected # día seleccionado
day_selected_double_click # doble clic en día seleccionado
prev_month # mes anterior
next_month # mes siguiente
prev_year # año anterior
next_year # año siguiente
Esto nos deja con la necesidad de poner todo ello junto en el programa de
ejemplo calendar.py. La figura Figura 9.12, “Ejemplo de Calendario” muestra el resultado del
programa:
Figura 9.12. Ejemplo de Calendario
El código fuente es calendar.py:
1 #!/usr/bin/env python
2
3 # ejemplo calendar.py
4 #
5 # Copyright (C) 1998 Cesar Miquel, Shawn T. Amundson, Mattias Gronlund
6 # Copyright (C) 2000 Tony Gale
7 # Copyright (C) 2001-2004 John Finlay
8 #
9 # This program is free software; you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation; either version 2 of the License, or
12 # (at your option) any later version.
13 #
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
the
17 # GNU General Public License for more details.
18 #
19 # You should have received a copy of the GNU General Public License
20 # along with this program; if not, write to the Free Software
21 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22
23 import pygtk
24 pygtk.require('2.0')
25 import gtk, pango
26 import time
27
28 class CalendarExample:
29 DEF_PAD = 10
30 DEF_PAD_SMALL = 5
31 TM_YEAR_BASE = 1900
32
33 calendar_show_header = 0
34 calendar_show_days = 1
35 calendar_month_change = 2
36 calendar_show_week = 3
37
38 def calendar_date_to_string(self):
39 year, month, day = self.window.get_date()
40 mytime = time.mktime((year, month+1, day, 0, 0, 0, 0, 0, -1))
41 return time.strftime("%x", time.localtime(mytime))
42
43 def calendar_set_signal_strings(self, sig_str):
44 prev_sig = self.prev_sig.get()
45 self.prev2_sig.set_text(prev_sig)
46
47 prev_sig = self.last_sig.get()
48 self.prev_sig.set_text(prev_sig)
49 self.last_sig.set_text(sig_str)
50
51 def calendar_month_changed(self, widget):
52 buffer = "month_changed: %s" % self.calendar_date_to_string()
53 self.calendar_set_signal_strings(buffer)
54
55 def calendar_day_selected(self, widget):
56 buffer = "day_selected: %s" % self.calendar_date_to_string()
57 self.calendar_set_signal_strings(buffer)
58
59 def calendar_day_selected_double_click(self, widget):
60 buffer = "day_selected_double_click: %s"
61 buffer = buffer % self.calendar_date_to_string()
62 self.calendar_set_signal_strings(buffer)
63
64 year, month, day = self.window.get_date()
65
66 if self.marked_date[day-1] == 0:
67 self.window.mark_day(day)
68 self.marked_date[day-1] = 1
69 else:
70 self.window.unmark_day(day)
71 self.marked_date[day-1] = 0
72
73 def calendar_prev_month(self, widget):
74 buffer = "prev_month: %s" % self.calendar_date_to_string()
75 self.calendar_set_signal_strings(buffer)
76
77 def calendar_next_month(self, widget):
78 buffer = "next_month: %s" % self.calendar_date_to_string()
79 self.calendar_set_signal_strings(buffer)
80
81 def calendar_prev_year(self, widget):
82 buffer = "prev_year: %s" % self.calendar_date_to_string()
83 self.calendar_set_signal_strings(buffer)
84
85 def calendar_next_year(self, widget):
86 buffer = "next_year: %s" % self.calendar_date_to_string()
87 self.calendar_set_signal_strings(buffer)
88
89 def calendar_set_flags(self):
90 options = 0
91 for i in range(5):
92 if self.settings[i]:
93 options = options + (1<<i)
94 if self.window:
95 self.window.display_options(options)
96
97 def calendar_toggle_flag(self, toggle):
98 j=0
99 for i in range(5):
100 if self.flag_checkboxes[i] == toggle:
101 j=i
102
103 self.settings[j] = not self.settings[j]
104 self.calendar_set_flags()
105
106 def calendar_font_selection_ok(self, button):
107 self.font = self.font_dialog.get_font_name()
108 if self.window:
109 font_desc = pango.FontDescription(self.font)
110 if font_desc:
111 self.window.modify_font(font_desc)
112
113 def calendar_select_font(self, button):
114 if not self.font_dialog:
115 window = gtk.FontSelectionDialog("Font Selection Dialog")
116 self.font_dialog = window
117
118 window.set_position(gtk.WIN_POS_MOUSE)
119
120 window.connect("destroy", self.font_dialog_destroyed)
121
122 window.ok_button.connect("clicked",
123 self.calendar_font_selection_ok)
124 window.cancel_button.connect_object("clicked",
125 lambda wid: wid.destroy(),
126 self.font_dialog)
127 window = self.font_dialog
128 if not (window.flags() & gtk.VISIBLE):
129 window.show()
130 else:
131 window.destroy()
132 self.font_dialog = None
133
134 def font_dialog_destroyed(self, data=None):
135 self.font_dialog = None
136
137 def __init__(self):
138 flags = [
139 "Show Heading",
140 "Show Day Names",
141 "No Month Change",
142 "Show Week Numbers",
143 ]
144 self.window = None
145 self.font = None
146 self.font_dialog = None
147 self.flag_checkboxes = 5*[None]
148 self.settings = 5*[0]
149 self.marked_date = 31*[0]
150
151 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
152 window.set_title("Calendar Example")
153 window.set_border_width(5)
154 window.connect("destroy", lambda x: gtk.main_quit())
155
156 window.set_resizable(gtk.FALSE)
157
158 vbox = gtk.VBox(gtk.FALSE, self.DEF_PAD)
159 window.add(vbox)
160
161 # La parte superior de la ventana, el Calendario, las opcines y fuente.
162 hbox = gtk.HBox(gtk.FALSE, self.DEF_PAD)
163 vbox.pack_start(hbox, gtk.TRUE, gtk.TRUE, self.DEF_PAD)
164 hbbox = gtk.HButtonBox()
165 hbox.pack_start(hbbox, gtk.FALSE, gtk.FALSE, self.DEF_PAD)
166 hbbox.set_layout(gtk.BUTTONBOX_SPREAD)
167 hbbox.set_spacing(5)
168
169 # Control calendario
170 frame = gtk.Frame("Calendar")
171 hbbox.pack_start(frame, gtk.FALSE, gtk.TRUE, self.DEF_PAD)
172 calendar = gtk.Calendar()
173 self.window = calendar
174 self.calendar_set_flags()
175 calendar.mark_day(19)
176 self.marked_date[19-1] = 1
177 frame.add(calendar)
178 calendar.connect("month_changed", self.calendar_month_changed)
179 calendar.connect("day_selected", self.calendar_day_selected)
180 calendar.connect("day_selected_double_click",
181 self.calendar_day_selected_double_click)
182 calendar.connect("prev_month", self.calendar_prev_month)
183 calendar.connect("next_month", self.calendar_next_month)
184 calendar.connect("prev_year", self.calendar_prev_year)
185 calendar.connect("next_year", self.calendar_next_year)
186
187 separator = gtk.VSeparator()
188 hbox.pack_start(separator, gtk.FALSE, gtk.TRUE, 0)
189
190 vbox2 = gtk.VBox(gtk.FALSE, self.DEF_PAD)
191 hbox.pack_start(vbox2, gtk.FALSE, gtk.FALSE, self.DEF_PAD)
192
193 # Crear el frame derecho con sus opciones
194 frame = gtk.Frame("Flags")
195 vbox2.pack_start(frame, gtk.TRUE, gtk.TRUE, self.DEF_PAD)
196 vbox3 = gtk.VBox(gtk.TRUE, self.DEF_PAD_SMALL)
197 frame.add(vbox3)
198
199 for i in range(len(flags)):
200 toggle = gtk.CheckButton(flags[i])
201 toggle.connect("toggled", self.calendar_toggle_flag)
202 vbox3.pack_start(toggle, gtk.TRUE, gtk.TRUE, 0)
203 self.flag_checkboxes[i] = toggle
204
205 # Crear el botón de fuentes derecho
206 button = gtk.Button("Font...")
207 button.connect("clicked", self.calendar_select_font)
208 vbox2.pack_start(button, gtk.FALSE, gtk.FALSE, 0)
209
210 # Crear la parte relativo a señales
211 frame = gtk.Frame("Signal events")
212 vbox.pack_start(frame, gtk.TRUE, gtk.TRUE, self.DEF_PAD)
213
214 vbox2 = gtk.VBox(gtk.TRUE, self.DEF_PAD_SMALL)
215 frame.add(vbox2)
216
217 hbox = gtk.HBox (gtk.FALSE, 3)
218 vbox2.pack_start(hbox, gtk.FALSE, gtk.TRUE, 0)
219 label = gtk.Label("Signal:")
220 hbox.pack_start(label, gtk.FALSE, gtk.TRUE, 0)
221 self.last_sig = gtk.Label("")
222 hbox.pack_start(self.last_sig, gtk.FALSE, gtk.TRUE, 0)
223
224 hbox = gtk.HBox (gtk.FALSE, 3)
225 vbox2.pack_start(hbox, gtk.FALSE, gtk.TRUE, 0)
226 label = gtk.Label("Previous signal:")
227 hbox.pack_start(label, gtk.FALSE, gtk.TRUE, 0)
228 self.prev_sig = gtk.Label("")
229 hbox.pack_start(self.prev_sig, gtk.FALSE, gtk.TRUE, 0)
230
231 hbox = gtk.HBox (gtk.FALSE, 3)
232 vbox2.pack_start(hbox, gtk.FALSE, gtk.TRUE, 0)
233 label = gtk.Label("Second previous signal:")
234 hbox.pack_start(label, gtk.FALSE, gtk.TRUE, 0)
235 self.prev2_sig = gtk.Label("")
236 hbox.pack_start(self.prev2_sig, gtk.FALSE, gtk.TRUE, 0)
237
238 bbox = gtk.HButtonBox ()
239 vbox.pack_start(bbox, gtk.FALSE, gtk.FALSE, 0)
240 bbox.set_layout(gtk.BUTTONBOX_END)
241
242 button = gtk.Button("Close")
243 button.connect("clicked", lambda w: gtk.main_quit())
244 bbox.add(button)
245 button.set_flags(gtk.CAN_DEFAULT)
246 button.grab_default()
247
248 window.show_all()
249
250 def main():
251 gtk.main()
252 return 0
253
254 if __name__ == "__main__":
255 CalendarExample()
256 main()
donde title (título) es una cadena usada para la barra de título del diálogo.
Este es el constructor más común del selector de color. Crea un ColorSelectionDialog.
Éste consiste en un Frame que contiene un controlColorSelection, un HSeparator y
un HBox con tres botones, Ok, Cancelar y Ayuda. Se pueden obtener estos botones
accediendo a los
atributosok_button, cancel_button y help_button del ColorSelectionDialog, (por
ejemplo, colorseldlg.ok_button). El control ColorSelection es accesible usando la
variable colorsel:
colorsel = colorseldlg.colorsel
El control ColorSelection tiene unos cuantos métodos que cambian sus características o
proporcionan acceso a la selección de color.
colorsel.set_has_opacity_control(has_opacity)
Para fijar el nombre de fichero, por ejemplo para mostrar un directorio específico, o
establecer un fichero predeterminado, usa este método:
filesel.set_filename(filename)
Para obtener el nombre de fichero que el usuario ha escrito o seleccionado, se usa este
método:
filename = filesel.get_filename()
una interfaz para el mecanismo de filtrado de fuente que restringe las fuentes
disponibles para seleccionar
La función para crear un FontSelectionDialog es:
fontseldlg = gtk.FontSelectionDialog(title)