Está en la página 1de 254

Tutorial de PyGTK 2.

0
por John Finlay y Lorenzo Gil Snchez
Tutorial de PyGTK 2.0
por John Finlay y Lorenzo Gil Snchez
Este tutorial describe el uso del mdulo de Python PyGTK.
Tabla de contenidos
I. Tutorial de PyGTK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1. Introduccin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.1. Explorando PyGTK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2. Primeros Pasos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.1. Hola Mundo en PyGTK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.2. Teora de Seales y Retrollamadas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.3. Eventos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.4. Hola Mundo Paso a Paso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
3. Avanzando . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3.1. Ms sobre manejadores de seales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3.2. Un Hola Mundo Mejorado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
4. Empaquetamiento de Controles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
4.1. Teora de Cajas Empaquetadoras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
4.2. Detalles de Cajas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
4.3. Programa de Demostracin de Empaquetamiento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
4.4. Uso de Tablas para Empaquetar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
4.5. Ejemplo de Empaquetamiento con Tablas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
5. Perspectiva General de Controles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
5.1. Jerarqua de Controles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
5.2. Controles sin Ventana . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
6. El Control de Botn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
6.1. Botones Normales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
6.2. Botones Biestado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
6.3. Botones de Activacin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
6.4. Botones de Exclusin Mtua . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
7. Ajustes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
7.1. Crear un Ajuste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
7.2. Usar los Ajustes de la Forma Fcil . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
7.3. El Interior del Ajuste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
8. Controles de Rango . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
8.1. Barras de Desplazamiento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
8.2. Controles de Escala . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
8.2.1. Crear un Control de Escala . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
8.2.2. Mtodos y Seales (bueno, al menos mtodos) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
8.3. Mtodos Comunes de los Rangos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
8.3.1. Establecer la Poltica de Actualizacin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
8.3.2. Obtener y Cambiar Ajustes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
8.4. Atajos de Teclas y Ratn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
8.5. Ejemplo de Control de Rango . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
9. Miscelanea de Controles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
9.1. Etiquetas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
9.2. Flechas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
9.3. El Objeto Pistas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
9.4. Barras de Progreso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
9.5. Dilogos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
9.6. Imgenes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
9.6.1. Pixmaps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
9.7. Reglas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
9.8. Barras de Estado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
9.9. Entradas de Texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
9.10. Botones Aumentar/Disminuir . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
iii
Tutorial de PyGTK
2.0
9.11. Lista Desplegable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
9.12. Calendario . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
9.13. Seleccin de Color . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
9.14. Selectores de Fichero . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
9.15. Dilogo de Seleccin de Fuentes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
10. Controles Contenedores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
10.1. La Caja de Eventos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
10.2. El control Alineador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
10.3. Contenedor Fijo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
10.4. Contenedor de Disposicin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
10.5. Marcos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
10.6. Marcos Proporcionales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
10.7. Controles de Panel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
10.8. Puertos de Visin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
10.9. Ventanas de Desplazamiento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
10.10. Cajas de Botones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
10.11. Barra de Herramientas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
10.12. Fichas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
11. Control Men . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
11.1. Creacin de Mens Manual . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
11.2. Ejemplo de Men Manual . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
11.3. Usando la Factoria de Elementos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
11.4. Ejemplo de Factoria de Elementos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
12. rea de Dibujo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
12.1. Contexto Grco . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
12.2. Mtodos de Dibujo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
13. Control de Vista de Texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
13.1. Perspectiva general de la Vista de Texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
13.2. Vistas de Texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
13.3. Buffers de Texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173
13.3.1. Informacin de estado de un Buffer de Texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
13.3.2. Creacin de Iteradores de Texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
13.3.3. Insercin, Obtencin y Eliminacin de Texto . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
13.3.4. Marcas de Texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
13.3.5. Creacin y Uso de Etiquetas de Texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178
13.3.6. Insercin de Imgenes y Controles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178
13.4. Iteradores de Texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
13.4.1. Atributos de los Iteradores de Texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
13.4.2. Atributos de Texto de un Iterador de Texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
13.4.3. Copiar un Iterador de Texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
13.4.4. Recuperar Texto y Objetos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
13.4.5. Comprobar Condiciones en un Iterador de Texto . . . . . . . . . . . . . . . . . . . . . . . . 182
13.4.6. Comprobar la localizacin de un Iterador de Texto . . . . . . . . . . . . . . . . . . . . . . . 183
13.4.7. Movimiento a travs del Texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184
13.4.8. Moverse a una Posicin Especca . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185
13.4.9. Buscar en el Texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185
13.5. Marcas de Texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185
13.6. Etiquetas de Texto y Tablas de Etiquetas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186
13.6.1. Etiquetas de Texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186
13.6.2. Tablas de Etiquetas de Texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
13.7. Un ejemplo de Vista de Texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
14. Control de Vista de rbol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193
15. Controles sin documentar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
iv
Tutorial de PyGTK 2.0
15.1. Etiqueta de Aceleracin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
15.2. Men de Opciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
15.3. Elementos de Men . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
15.3.1. Elemento de Men de Activacin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
15.3.2. Elemento de Men de Exclusin Mtua . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
15.3.3. Elemento de Men de Separacin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
15.3.4. Elemento de Men de Cascada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
15.4. Curvas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
15.5. Dilogo de Mensaje . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
15.6. Curva Gamma . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
15.7. Enchufes y Clavijas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
16. Cambiar Atributos de Controles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
16.1. Mtodos de Banderas de Controles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
16.2. Mtodos de Visualizacin de Controles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
16.3. Atajos de Teclador de Controles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
16.4. Mtodos para el Nombre de los Controles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
16.5. Estilos de Controles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
17. Temporizadores, Entrada/Salida y Funciones de Inactividad . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201
17.1. Temporizadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201
17.2. Monitorizar la Entrada/Salida . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201
17.3. Funciones de Inactividad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202
18. Procesamiento Avanzado de Eventos y Seales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
18.1. Mtodos de Seales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
18.1.1. Conectar y Desconectar Manejadores de Seales . . . . . . . . . . . . . . . . . . . . . . . . 203
18.1.2. Bloquear y Desbloquear Manejadores de Seales . . . . . . . . . . . . . . . . . . . . . . . . 203
18.1.3. Emitir y Parar Seales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
18.2. Emisin y Propagacin de Seales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
19. Tratamiento de Selecciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
19.1. Perspectiva General de la Seleccin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
19.2. Recuperar la Seleccin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
19.3. Proporcionar la Seleccin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209
20. Arrastrar y Soltar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213
20.1. Perspectiva General de Arrastrar y Soltar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213
20.2. Propiedades de Arrastrar y Soltar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213
20.3. Mtodos de Arrastrar y Soltar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214
20.3.1. Conguracin del Control Orgen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214
20.3.2. Seales en el Control Orgen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
20.3.3. Conguracin de un Control Destino . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
20.3.4. Seales en el Control Destino . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216
21. Ficheros rc de GTK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220
21.1. Funciones para Ficheros rc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220
21.2. Formato de los Ficheros rc de GTK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220
21.3. Ejemplo de chero rc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
22. Scribble, Un Ejemplo de Programa de Dibujo Simple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
22.1. Perspectiva General de Scribble . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
22.2. Manejo de Eventos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
22.2.1. Scribble - Manejo de Eventos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230
22.3. El Control del rea de Dibujo, y Dibujar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232
23. Trucos para Escribir Aplicaciones PyGTK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236
24. Contribuir . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237
A. Seales GTK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238
A.1. GtkObject . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238
A.2. GtkWidget . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238
v
Tutorial de PyGTK 2.0
A.3. GtkData . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240
A.4. GtkContainer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240
A.5. GtkCalendar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240
A.6. GtkEditable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240
A.7. GtkNotebook . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241
A.8. GtkList . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241
A.9. GtkMenuShell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241
A.10. GtkToolbar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241
A.11. GtkButton . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242
A.12. GtkItem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242
A.13. GtkWindow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242
A.14. GtkHandleBox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242
A.15. GtkToggleButton . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242
A.16. GtkMenuItem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242
A.17. GtkCheckMenuItem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242
A.18. GtkInputDialog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243
A.19. GtkColorSelection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243
A.20. GtkStatusBar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243
A.21. GtkCurve . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243
A.22. GtkAdjustment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243
B. Ejemplos de Cdigo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244
B.1. scribblesimple.py . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244
vi
Lista de guras
2.1. Ventana Simple PyGTK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.2. Programa de ejemplo Hola Mundo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
3.1. Ejemplo de Hola Mundo mejorado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
4.1. Empaquetamiento: Cinco variaciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
4.2. Empaquetando con Spacing y Padding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
4.3. Empaquetando con pack_end() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
4.4. Empaquetamiento usando una Tabla . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
6.1. Botn con Pixmap y Etiqueta . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
6.2. Ejemplo de Botn Biestado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
6.3. Ejemplo de Botn de Activacin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
6.4. Ejemplo de Botones de Exclusin Mtua . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
8.1. Ejemplo de Controles de Rango . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
9.1. Ejemplos de Etiquetas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
9.2. Ejemplos de Botones con Flechas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
9.3. Ejemplo de Pistas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
9.4. Ejemplo de Barra de Progreso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
9.5. Ejemplo de Imgenes en Botones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
9.6. Ejemplo de Pixmap en un Botn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
9.7. Ejemplo de Ventana con Forma . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
9.8. Ejemplo de Reglas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
9.9. Ejemplo de Barra de Estado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
9.10. Ejemplo de Entrada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
9.11. Ejemplo de Botn Aumentar/Disminuir . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
9.12. Ejemplo de Calendario . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
9.13. Ejemplo de Dilogo de Seleccin de Color . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
9.14. Ejemplo de Seleccin de Ficheros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
9.15. Dilogo de Seleccin de Fuentes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
10.1. Ejemplo de Caja de Eventos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
10.2. Ejemplo de Fijo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
10.3. Ejemplo de Disposicin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
10.4. Ejemplo de Marco . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
10.5. Ejemplo de Marco Proporcional . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
10.6. Ejemplo de Panel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
10.7. Ejemplo de Ventana de Desplazamiento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
10.8. Ejemplo de Barra de Herramientas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
10.9. Ejemplo de Fichas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
11.1. Ejemplo de Men . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
11.2. Ejemplo de Factoria de Elementos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
12.1. Ejemplo de rea de Dibujo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
13.1. Ejemplo bsico de Vista de Texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
13.2. Ejemplo de Vista de Texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
19.1. Ejemplo de Obtencin de la Seleccin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207
19.2. Ejemplo de Fijar la Seleccin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
20.1. Ejemplo de Arrastrar y Soltar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216
22.1. Ejemplo de Programa de Dibujo Scribble . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
22.2. Ejemplo simple de Scribble . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231
vii
Lista de tablas
20.1. Seales del Control de Orgen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
20.2. Seales del Control Destino . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216
viii
Parte I. Tutorial de PyGTK
Captulo 1. Introduccin
PyGTK 2.0 es un conjunto de mdulos que componen una interfaz Python para GTK+ 2.0. A travs del resto de
este documento PyGTK se reere a la versin 2.0 de PyGTK y GTK y GTK+ se reeren a la versin 2.0 de GTK+.
El principal sitio web de PyGTK es www.daa.com.au/~james/pygtk [http://www.daa.com.au/~james/pygtk]. El
principal autor de PyGTK es:
James Henstridge james@daa.com.au [mailto:james@daa.com.au]
Python es un lenguaje de programacin interpretado, ampliable y orientado a objectos que se distribuye con un
amplio conjunto de mdulos que soportan acceso a un gran nmero de servicios del sistema operativo, servicios
de internet (como HTML, XML, FTP, etc.), grcos (incluyendo OpenGL, TK, etc.), funciones de manejo de
cadenas, servicios de correo (IMAP, SMTP, POP3, etc.), multimedia (audio, JPEG) y servicios de criptografa.
Adems hay otros muchos mdulos disponibles por terceros que aaden otros muchos servicios. Python es
distribuido bajo trminos similares a los de la licencia GPL y est disponible para los sistemas operativos Linux,
Unix, Windows y Macintosh. Ms informacion sobre Python est disponible en www.python.org. El principal
autor de Python es:
Guido van Rossum guido@python.org [mailto:guido@python.org]
GTK (GIMP Toolkit) es una librera para crear interfaces de usuario grcas. Esta licenciada usando la licencia
LGPL, por lo que puedes desarrollar software abierto, software libre, o incluso software comercial no libre usando
GTK sin tener que pagar nada en licencias o derechos.
Se llama el toolkit de GIMP porque originariamente fue escrita para desarrollar el Programa de Manipulacin
de Imgenes GNU (GIMP), pero GTK se usa ahora en un amplio nmero de proyectos de software, incluyendo
el proyecto de Entorno de Modelo de Objetos orientados a Red (GNOME). GTK est diseada encima de GDK
(Kit de Dibujo de GIMP) que bsicamente es una abstraccin de las funciones de bajo nivel para acceder a las
funciones del sistema de ventanas (Xlib en el caso del sistema de ventanas X). Los principales autores de GTK
son:
Peter Mattis petm@xcf.berkeley.edu [mailto:petm@xcf.berkeley.edu]
Spencer Kimball spencer@xcf.berkeley.edu [mailto:spencer@xcf.berkeley.edu]
Josh MacDonald jmacd@xcf.berkeley.edu [mailto:jmacd@xcf.berkeley.edu]
Actualmente GTK es mantenida por:
Owen Taylor otaylor@redhat.com [mailto:otaylor@redhat.com]
Tim Janik timj@gtk.org [mailto:timj@gtk.org]
2
Captulo 1. Introduccin
Bsicamente GTK es un interfaz orientada a objetos para programadores de aplicaciones (API). Aunque est
escrita completamente en C, est implementada usando la idea de clases y funciones de retrollamada (punteros a
funcin).
Tambin hay un tercer componente, llamado Glib, que contiene unas cuantas funciones que reemplazan algunas
llamadas estandard, as como funciones adicionales para manejar listas enlazadas, etc. Las funciones de reemplazo
se usan para aumentar la portabilidad de GTKya que algunas de las funciones que implementa no estn disponibles
o no son estandarden otros unix tales como g_strerror(). Algunas tambin incluyen mejoras a las versiones de
libc, tales como g_malloc que tiene utilidades de depuracin mejoradas.
En la versin 2.0, GLib ha incluido el sistema de tipos que forma la base para la jerarqua de clases de GTK,
el sistema de seales usado en GTK, una API de hebras que abstrae las diferentes APIs nativas de hebras de las
diversas plataformas y una facilidad para cargar modulos.
Como ltimo componente, GTK usa la librera Pango para la salida de texto internacionalizado.
Este tutorial describe el interfaz de Python a GTK+ y esta basado en el tutorial de GTK+ 2.0 escrito por Tony Gale
e Ian Main. Este tutorial intenta documentar todo lo posible PyGTK, pero en ningun caso es completo.
Este tutorial asume algn conocimiento previo de Python, y de cmo crear y ejecutar programas Python. Si no es-
tas familiarizado con Python, por favor lee el Tutorial de Python [http://www.python.org/doc/current/tut/tut.html]
primero. Este tutorial no asume ningun conocimiento previo de GTK; si ests aprendiendo PyGTK para aprender
GTK, por favor comenta cmo encuentras este tutorial, y con qu has tenido problemas. Este tutorial no describe
cmo compilar o instalar Python, GTK+ o PyGTK.
Este tutorial est basado en:
GTK+ 2.0.6
Python 2.2
PyGTK 1.99
Los ejemplos fueron escritos y probados en una RedHat 7.2.
Este documento est "en obras". Por favor consulta www.moeraki.com [http://www.moeraki.com/pygtktutorial]
para actualizaciones.
Me gustara mucho escuchar los problemas que ests teniendo aprendiendo PyGTK a partir de este documento,
y aprecio comentarios y formas de como puede ser mejorado. Por favor mira la seccin Contribuyendo para ms
informacin.
1.1. Explorando PyGTK
Johan Dahlin ha escrito un pequeo programa Python (pygtkconsole.py [examples/pygtkconsole.py]) que se
ejecuta en Linux y permite una exploracin interactiva de PyGTK. El progama proporciona un interfaz de
intrprete interactivo al estilo de Python que se comunica con un proceso hijo que ejecuta los comandos
introducidos. Los mdulos PyGTK se cargan por defecto. Un ejemplo simple de sesin es:
moe: 96:1095$ pygtkconsole.py
Python 2.2.2, PyGTK 1.99.14 (Gtk+ 2.0.6)
Interactive console to manipulate GTK+ widgets.
>>> w=Window()
>>> b=Button(Hola)
3
Captulo 1. Introduccin
>>> w.add(b)
>>> def hola(b):
... print "Hola Mundo!"
...
>>> b.connect(clicked, hola)
5
>>> w.show_all()
>>> Hola Mundo!
Hola Mundo!
Hola Mundo!
>>> b.set_label("Hola a todos")
>>>
Esto crea una ventana que contiene un botn que imprime un mensaje (Hola Mundo!) cuando se hace clic. Este
programa permite probar fcilmente varios controles GTK y sus interfaces PyGTK.
4
Captulo 2. Primeros Pasos
Para empezar nuestra introduccin a PyGTK, comenzaremos con el programa ms simple posible. Este programa
(base.py [examples/base.py]) crear una ventana de 200x200 pxeles y no hay forma de salir excepto matndolo
desde la consola.
1 #!/usr/bin/env python
2
3 # example base.py
4
5 import gtk
6
7 class Base:
8 def __init__(self):
9 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
10 self.window.show()
11
12 def main(self):
13 gtk.main()
14
15 if __name__ == "__main__":
16 base = Base()
17 base.main()
Puedes ejecutar el programa anterior usando:
python base.py
Si base.py [examples/base.py] es hecho ejecutable y se puede encontrar en la variable PATH, puede ser ejecutado
usando:
base.py
La lnea 1 le pedir a python que ejecute base.py [examples/base.py] en este caso. Las lneas 15-17 comprueban
si la variable __name__ es "__main__", lo cual indica que el programa esta siendo ejecutado directamente por
python y no est siendo importado en un intrprete python. En este caso el programa crea una nueva instancia de
la clase Base y guarda una referencia a ella en la variable base. Despus invoca la funcin main() para empezar
el bucle de procesamiento de eventos de GTK.
Una ventana similar a Figura 2.1. Ventana Simple PyGTK debera aparecer en tu pantalla.
5
Captulo 2. Primeros Pasos
Figura 2.1. Ventana Simple PyGTK
La primera lnea permite al programa base.py [examples/base.py] ser invocado desde una consola Linux o Unix
asumiendo que python se encuentre en tu PATH. Esta lnea ser la primera lnea en todos los programas de ejemplo.
La lnea 5 importa el mdulo PyGTK e inicializa el entorno GTK+. El mdulo PyGTK dene los interfaces
Python para las funciones GTK+ que se usarn en el programa. Para aquellos que estn familiarizados con GTK+,
la inicializacin incluye la llamada a la funcin gtk_init(). Este congura unas cuantas cosas por nosotros como
el visual por defecto y el mapa de colores, manejadores de seales predeterminados, y comprueba los argumentos
que se le pasan a tu programa desde la lnea de comandos, buscando alguno de los siguientes:
--gtk-module
--g-fatal-warnings
--gtk-debug
--gtk-no-debug
--gdk-debug
--gdk-no-debug
--display
--sync
--name
--class
6
Captulo 2. Primeros Pasos
Borra estos argumentos de la lista de argumentos, dejando todo lo que no reconoce para que tu programa lo procese
o ignore. Este conjunto de argumentos estandard son los que aceptan todas los programas GTK+.
Las lneas 7-10 denen una clase de python llamada Base que dene un mtodo de inicializacin de instancia
__init__(). La funcin __init__() crea una ventana de nivel superior (lnea 9) y ordena a GTK+ que la
muestre (lnea 10). La GtkWindow se crea en la lnea 9 con el argumento gtk.WINDOW_TOPLEVEL que especica
que queremos una ventana sometida a las decoraciones y posicionamiento del manejador de ventanas. En vez de
crear una ventana de tamao 0x0, una ventana sin hijos tiene un tamao de 200x200 por defecto para que puedas
manipularla.
Las lneas 12-13 denen el mtodo main() que llama a la funcin PyGTKmain(), la cual, invoca el bucle principal
de procesamiento de eventos de GTK+ para manejar eventos de ratn y de teclado, as como eventos de ventana.
Las lneas 15-17 permiten al programa que comience automticamente si es llamado directamente o pasado como
argumento al intrprete de python; en estos casos el nombre de programa que hay en la variable __name__ ser
la cadena "__main__" y el cdigo entre las lneas 16-17 ser ejecutado. Si el programa se carga en un intrprete
de python que se est ejecutando, las lneas 16-17 no sern ejecutadas.
La lnea 16 crea una instancia de la clase Base llamada base. Una GtkWindow es creada y mostrada como
resultado.
La lnea 17 llama al mtodo 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 esperando que ocurran eventos X (como pulsaciones
de teclas o botones), alarmas, o noticaciones de entrada/salida de cheros. En nuestro ejemplo, sin embargo, los
eventos son ignorados.
2.1. Hola Mundo en PyGTK
Ahora haremos un programa con un control (un botn). Es la versin PyGTK del clsico programa hola mundo
(helloworld.py [examples/helloworld.py] ).
1 #!/usr/bin/env python
2
3 # example helloworld.py
4
5 import gtk
6
7 class HelloWorld:
8
9 # This is a callback function. The data arguments are ignored
10 # in this example. More on callbacks below.
11 def hello(self, widget, data=None):
12 print "Hello World"
13
14 def delete_event(self, widget, event, data=None):
15 # If you return FALSE in the "delete_event" signal handler,
16 # GTK will emit the "destroy" signal. Returning TRUE means
17 # you dont want the window to be destroyed.
18 # This is useful for popping up are you sure you want to quit?
19 # type dialogs.
20 print "delete event occurred"
21
22 # Change TRUE to FALSE and the main window will be destroyed with
23 # a "delete_event".
24 return gtk.FALSE
25
7
Captulo 2. Primeros Pasos
26 # Another callback
27 def destroy(self, widget, data=None):
28 gtk.main_quit()
29
30 def __init__(self):
31 # create a new window
32 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
33
34 # When the window is given the "delete_event" signal (this is given
35 # by the window manager, usually by the "close" option, or on the
36 # titlebar), we ask it to call the delete_event () function
37 # as defined above. The data passed to the callback
38 # function is NULL and is ignored in the callback function.
39 self.window.connect("delete_event", self.delete_event)
40
41 # Here we connect the "destroy" event to a signal handler.
42 # This event occurs when we call gtk_widget_destroy() on the window,
43 # or if we return FALSE in the "delete_event" callback.
44 self.window.connect("destroy", self.destroy)
45
46 # Sets the border width of the window.
47 self.window.set_border_width(10)
48
49 # Creates a new button with the label "Hello World".
50 self.button = gtk.Button("Hello World")
51
52 # When the button receives the "clicked" signal, it will call the
53 # function hello() passing it None as its argument. The hello()
54 # function is defined above.
55 self.button.connect("clicked", self.hello, None)
56
57 # This will cause the window to be destroyed by calling
58 # gtk_widget_destroy(window) when "clicked". Again, the destroy
59 # signal could come from here, or the window manager.
60 self.button.connect_object("clicked", gtk.Widget.destroy, self.window)
61
62 # This packs the button into the window (a GTK container).
63 self.window.add(self.button)
64
65 # The final step is to display this newly created widget.
66 self.button.show()
67
68 # and the window
69 self.window.show()
70
71 def main(self):
72 # All PyGTK applications must have a gtk.main(). Control ends here
73 # and waits for an event to occur (like a key press or mouse event).
74 gtk.main()
75
76 # If the program is run directly or passed as an argument to the python
77 # interpreter then create a HelloWorld instance and show it
78 if __name__ == "__main__":
79 hello = HelloWorld()
80 hello.main()
Figura 2.2. Programa de ejemplo Hola Mundo muestra la ventana creada por helloworld.py [exam-
ples/helloworld.py].
8
Captulo 2. Primeros Pasos
Figura 2.2. Programa de ejemplo Hola Mundo
Las variables y funciones que se denen en el mdulo PyGTK se llaman de la forma gtk.*. Por ejemplo, el
programa helloworld.py [examples/helloworld.py] usa:
gtk.FALSE
gtk.mainquit()
gtk.Window()
gtk.Button()
del mdulo PyGTK. En futuras secciones no especicar el prejo del mdulo gtk, pero se asumir. Por supuesto,
los programas de ejemplo usarn los prejos del mdulo.
2.2. Teora de Seales y Retrollamadas
Nota
En la versin 2.0 de GTK+, el sistema de seales se ha movido de GTK a GLib. No entraremos en
detalles sobre las extensiones que GLib 2.0 tiene en relacin con el sistema de seales de GTK 1.2. Las
diferecias no deberan notarse entre los usuarios de PyGTK.
Antes de que entremos en detalle en helloworld.py [examples/helloworld.py], discutiremos las seales y las
retrollamadas. GTK es una libreria orientada a eventos, lo que signica que se dormir en la funcin gtk.main()
hasta que un evento ocurra y el control pase a la funcin apropiada.
Esta delegacin del control se realiza usando la idea de "seales". (Ntese que estas seales no son las mismas
que las seales de los sistemas Unix, y no se implementan usando estas, aunque la terminologa es casi idntica)
Cuando un evento ocurre, como cuando presionamos un botn del ratn, la seal apropiada ser "emitida" por el
el control que fu presionado. Asi es cmo GTK hace la mayora de su trabajo til. Hay seales que todos los
controles heredan, como "destroy", y hay seales que son especcas a cada control, como "toggled" en un botn
de activacin.
Para hacer que un botn realice una accin, tenemos que congurar un manejador de seales que capture estas
seales y llame a la funcin apropiada. Esto se hace usando un mtodo de GtkWidget (heredado de la clase
GObject) como por ejemplo:
handler_id = object.connect(name, func, func_data)
donde object es la instancia de GtkWidget que estar emitiendo la seal, y el primer argumento name es una
cadena que contiene el nombre de la seal que deseas capturar. El segundo argumento, func, es la funcin que
quieres que sea llamada cuando es capturado, y el tercer argumento, func_data, los datos que quieres pasar a
esta funcin. El mtodo devuelve un handler_id que puede usarse para desconectar o bloquear el manejador.
La funcin especicada en el tercer argumento se llama "funcin de retrollamada", y generalmente es de la forma:
9
Captulo 2. Primeros Pasos
def callback_func(widget, callback_data):
donde el primer argumento ser una referencia al widget (control) que emiti la seal, y el segundo
(callback_data) una referencia a los datos dados como ltimo argumento en el mtodo connect() mostrado
antes.
Si la funcin de retrollamada es un mtodo 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 mtodo. Esta es la forma usada en el programa de ejemplo
helloworld.py [examples/helloworld.py].
Nota
La forma anterior de declaracin de una funcin de retrollamada a seales es slo una gua general, ya
que seales especcas de controles generan diferentes parmetros de llamada.
Otra llamada que se usa en el ejemplo helloworld.py [examples/helloworld.py] es:
handler_id = object.connect_object(name, func, slot_object)
connect_object() es lo mismo que connect() excepto que una funcin de retrollamada slo usa un argumento
y un mtodo de retrollamada, dos argumentos:
def callback_func(object)
def callback_meth(self, object)
donde object normalmente es un control. connect_object() permite usar los mtodos de controles PyGTK
qu solo admiten un argumento (self) como manejadores de seales.
2.3. Eventos
Adems del mecanismo de seales descrito anteriormente, hay un conjunto de eventos que reejan el mecanismo
de eventos de X. Las retrollamadas tambin 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
10
Captulo 2. Primeros Pasos
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 funcin de retrollamada a uno de estos eventos se usa el mtodo connect(), como se ha dicho
anteriormente, usando uno del nombres de eventos anteriores en el parmetro name. La funcin (o mtodo) de
retrollamada para eventos es ligeramente diferente de la usada para seales:
def callback_func(widget, event, callback_data ):
def callback_meth(self, widget, event, callback_data ):
GdkEvent es un tipo de objetos python cuyos atributos de tipo indicarn cul de los eventos anteriores ha ocurrido.
Los otros atributos del evento dependern del tipo de evento. 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
11
Captulo 2. Primeros Pasos
CLIENT_EVENT
VISIBILITY_NOTIFY
NO_EXPOSE
SCROLL
WINDOW_STATE
SETTING
Para acceder a estos valores se le pone el prejo gtk.gdk. al tipo evento. Por ejemplo gtk.gdk.DRAG_ENTER.
Por tanto, para conectar una funcin de retrollamada a uno de estos eventos usaramos algo como:
button.connect("button_press_event", button_press_callback)
Esto asume que button es un control GtkButton. Entonces, cuando el ratn este sobre el botn y un botn del
ratn se pulse, se llamar a la funcin button_press_callback. Esta funcin puede ser denida as:
def button_press_callback(widget, event, data ):
El valor que devuelve esta funcin 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. Consulta la seccin Procesamiento Avanzado de
Eventos y Seales para ms detalles sobre el sistema de propagacin.
Las APIs de seleccin y arrastrar y soltar de GDK tambin emiten unos cuantos eventos que se reejan en GTK
por medio de seales. Consulta Seales en el Control de Orgen y Seales en el Control de Destino para detalles
sobre la sintxis de las funciones de retrollamada para estas seales:
selection_received
selection_get
drag_begin_event
drag_end_event
drag_data_delete
drag_motion
drag_drop
drag_data_get
drag_data_received
2.4. Hola Mundo Paso a Paso
Ahora que ya conocemos la teora que hay detrs de esto, vamos a aclarar el programa de ejemplo helloworld.py
[examples/helloworld.py] paso a paso.
Las lneas 7-74 denen la clase HelloWorld que contienen todas las retrollamadas como mtodos de objeto y el
mtodo de inicializacin de objetos. Vamos a examinar los mtodos de retrollamada.
Las lneas 11-12 denen el mtodo de retrollamada hello() que se llamar cuando el botn sea pulsado. Cuando
se llama a este mtodo, se imprime "Hello World" a la consola. En este ejemplo ignoramos los parmetros de la
instancia del objeto, el control y los datos, pero la mayora de las retrollamadas los usan. El parmetro data se
dene con un valor por defecto de None porque PyGTK no pasar ningn valor para los datos si no son incluidos
en la llamada a connect(); esto lanzara un error ya que la retrollamada espera tres argumentos y solo recibe dos.
12
Captulo 2. Primeros Pasos
Denir un valor por defecto None permite llamar a la retrollamada con dos o tres parmetros sin ningn error. En
este caso el parmetro de datos podra haberse omitido ya que el mtodo hello() siempre ser llamado con slo
dos parmetros (nunca se usan los datos de usuario). En el siguiente ejemplo usaremos el argumento de datos para
saber que botn fue pulsado.
def hello(self, widget, data=None):
print "Hello World"
La siguiente retrollamada (lneas 14-24) es un poco especial. El evento "delete_event" se produce cuando el
manejador de ventanas manda este evento al programa. Tenemos varias posibilidades en cuanto a qu hacer con
estos eventos. Podemos ignorarlos, realizar algun tipo de respuesta, o simplemente cerrar el programa.
El valor que devuelvas en esta retrollamada le permite a GTK saber qu accin realizar. Devolviendo TRUE, le
hacemos saber que no queremos que se emita la seal "destroy", y asi nuestra aplicacin sigue ejecutandose.
Devolviendo FALSE, pedimos que se emita la seal "destroy", que a su vez llamar a nuestro manejador de la
seal "destroy". Ntese que se han quitado los comentarios para una mayour claridad.
def delete_event(widget, event, data=None):
print "delete event occurred"
return gtk.FALSE
El mtodo de retrollamada destroy() (lneas 27-28) hace que el programa termine mediante la lllamada a
gtk.main_quit() . Esta funcin le dice a GTK que debe salir de la funcin gtk.main() cuando el control
le sea transferido.
def destroy(widget, data=None):
gtk.main_quit()
Las lneas 30-69 denen el mtodo de inicializacin de instancia __init__() del objeto HelloWorld, el cual
crea la ventana y los controles que se usan en el programa.
La lnea 32 crea una nueva ventana, pero no se muestra directamente hasta que le decimos a GTK que lo haga, casi
al nal del programa. La referencia a la ventana se guarda en un atributo de instancia (self.window) para poder
acceder a ella despus.
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
Las lneas 39 y 44 ilustran dos ejemplos de cmo conectar un manejador de seal a un objeto, en este caso, a
window. Aqui se capturan el evento "delete_event" y la seal "destroy". El primero se emite cuando cerramos la
ventana a travs del manejador de ventanas, o cuando usamos la llamada al mtodo destroy() de GtkWidget.
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 lnea 47 establece un atributo de un objeto contenedor (en este caso window) para que tenga un rea vaca de
10 pxeles de ancho alrededor de l donde ningn control se situar. Hay otras funciones similares que se tratarn
en la seccin Poniendo Atributos de Controles
13
Captulo 2. Primeros Pasos
self.window.set_border_width(10)
La lnea 50 crea un nuevo botn y guarda una referencia a l en self.button. El botn tendr la etiqueta "Hello
World" cuando se muestre.
self.button = gtk.Button("Hello World")
En la lnea 55 conectamos un manejador de seal al botn para que cuando emita la seal "clicked", nuestro
manejador de retrollamada hello() se llame. No estamos pasandole ningn dato a hello() asi que simplemente
le pasamos None como dato. Obviamente la seal "clicked" se emite cuando hacemos clic en el botn con el cursor
del ratn. El valor del parmetro de los datos None no es imprescindible y podra ser omitido. La retrollamada se
llamar con un parmetro menos.
self.button.connect("clicked", self.hello, None)
Tambin vamos a usar este botn para salir de nuestro programa. La lnea 60 muestra como la seal "destroy"
puede venir del manejador de ventanas, o de nuestro programa. Cuando hacemos clic en el botn, al igual que
antes, se llama a la retrollamada hello() primero, y despus a la siguiente en el orden en el que son conguradas.
Puedes tener todas las retrollamadas que necesistes y se ejecutarn en el orden en el que las conectaste.
Como queremos usar el mtodo destroy() de la clase GtkWidget que acepta un argumento (el control que se
va a destruir - en este caso window), utilizamos el mtodo connect_object() y le pasamos la referencia a la
ventana. El mtodo connect_object() organiza el primer argumento de la retrollamada para que sea window
en vez de el botn.
Cuando se llama el mtodo destroy() de la clase GtkWidget esto provoca que se emita la seal "destroy" desde
la ventana que a su vez provocar que se llame el mtodo destroy() de la clase HelloWorld para terminar el
programa.
self.button.connect_object("clicked", gtk.Widget.destroy, self.window)
La lnea 63 es una llamada de colocacin, que ser explicada en profundidad ms tarde en Colocando Controles
. Pero es bastante fcil de entender. Simplemente le dice a GTK que el botn debe situarse en la ventana donde
se mostrar. Ten en cuenta que un contenedor GTK slo puede contener un control. Hay otros controles, que se
describen despus, que estn diseados para posicionar varios controles de diferentes maneras.
self.window.add(self.button)
Ahora lo tenemos todo congurado como queremos. Con todos los manejadores de seales, y el botn situado
en la ventana donde debera estar, le pedimos a GTK (lneas 65 y 69) que muestre los controles en la pantalla.
El control de ventana es mostrado en ltimo lugar para que la ventana entera aparezca de una vez en vez de ver
aparecer la ventana, y luego el botn dentro de ella. Sin embargo, con este ejemplo tan simple, nunca apreciarias
la diferencia.
self.button.show()
14
Captulo 2. Primeros Pasos
self.window.show()
Las lneas 71-74 denen el mtodo main() que llamam a la funcin gtk.main()
def main(self):
gtk.main()
Las lneas 78-80 permiten al programa ejecutarse automticamente si es llamado directamente o como un
argumento al intrprete de python. La lnea 79 crea una instancia de la clase HelloWorld y guarda una referencia
a ella en la variable hello. La lnea 80 llama al mtodo main() de la clase HelloWorld para empezar el bucle
de procesamiento de eventos GTK.
if __name__ == "__main__":
hello = HelloWorld()
hello.main()
Ahora, cuando hagamos clic con el botn del ratn en el botn GTK, el control emitir una seal "clicked". Para
poder usar esta informacin, nuestro programa congura un manejador de seal para que capture esta seal, la
cual llama a la funcin que decidamos. En nuestro ejemplo, cuando el botn que hemos creado es pulsado, se
llama el mtodo hello() con un argumento None, y despus se llama el siguiente manejador para esta seal. El
siguiente manejador llama a la funcin destroy() del control con la ventana como su argumento y de esta manera
causa a la ventana que emita la seal "destroy", que es capturada, y llama a nuestro mtodo destroy() de la clase
HelloWorld
Otra funcin de los eventos es usar el manejador de ventanas para matar la ventana, lo cual causar que se emita
"delete_event". Esto llamar nuestro manejador de "delete_event". Si devolvemos TRUE aqui, la ventana se
quedar como si nada hubiera pasado. Devolviendo FALSE har que GTK emita la seal "destroy" que llama a la
retrollamada "destroy" de la clase HelloWorld cerrando GTK.
15
Captulo 3. Avanzando
3.1. Ms sobre manejadores de seales
Veamos otra vez la llamada a connect() .
object.connect(name, func, func_data)
El valor de retorno de una llamada a connect() es un nmero entero que identica tu retrollamada. Como ya se
ha dicho, se pueden tener tantas retrollamadas por seal como necesites, y cada una se ejecutar por turnos, en el
orden en el que fueron conectadas.
Este identicador permite eliminar la retrollamada de la lista mediante:
object.disconnect(id)
As, pasndole el identicador que devuelven los mtodos de conexin, se puede desconectar un manejador de
seal.
Tambin puedes deshabilitar temporalmente los manejadores de seal con los mtodos signal_handler_block()
y signal_handler_unblock() .
object.signal_handler_block(handler_id)
object.signal_handler_unblock(handler_id)
3.2. Un Hola Mundo Mejorado
1 #!/usr/bin/env python
2
3 # example helloworld2.py
4
5 import gtk
6
7 class HelloWorld2:
8
9 # Our new improved callback. The data passed to this method
10 # is printed to stdout.
11 def callback(self, widget, data):
12 print "Hello again - %s was pressed" % data
13
14 # another callback
15 def delete_event(self, widget, event, data=None):
16 gtk.main_quit()
17 return gtk.FALSE
18
19 def __init__(self):
20 # Create a new window
21 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
22
16
Captulo 3. Avanzando
23 # This is a new call, which just sets the title of our
24 # new window to "Hello Buttons!"
25 self.window.set_title("Hello Buttons!")
26
27 # Here we just set a handler for delete_event that immediately
28 # exits GTK.
29 self.window.connect("delete_event", self.delete_event)
30
31 # Sets the border width of the window.
32 self.window.set_border_width(10)
33
34 # We create a box to pack widgets into. This is described in detail
35 # in the "packing" section. The box is not really visible, it
36 # is just used as a tool to arrange widgets.
37 self.box1 = gtk.HBox(gtk.FALSE, 0)
38
39 # Put the box into the main window.
40 self.window.add(self.box1)
41
42 # Creates a new button with the label "Button 1".
43 self.button1 = gtk.Button("Button 1")
44
45 # Now when the button is clicked, we call the "callback" method
46 # with a pointer to "button 1" as its argument
47 self.button1.connect("clicked", self.callback, "button 1")
48
49 # Instead of add(), we pack this button into the invisible
50 # box, which has been packed into the window.
51 self.box1.pack_start(self.button1, gtk.TRUE, gtk.TRUE, 0)
52
53 # Always remember this step, this tells GTK that our preparation for
54 # this button is complete, and it can now be displayed.
55 self.button1.show()
56
57 # Do these same steps again to create a second button
58 self.button2 = gtk.Button("Button 2")
59
60 # Call the same callback method with a different argument,
61 # passing a pointer to "button 2" instead.
62 self.button2.connect("clicked", self.callback, "button 2")
63
64 self.box1.pack_start(self.button2, gtk.TRUE, gtk.TRUE, 0)
65
66 # The order of showing the buttons is not really important, but I
67 # recommend showing the window last, so it all pops up at once.
68 self.button2.show()
69 self.box1.show()
70 self.window.show()
71
72 def main():
73 gtk.main()
74
75 if __name__ == "__main__":
76 hello = HelloWorld2()
77 main()
Al ejecutar helloworld2.py [examples/helloworld2.py] se genera la ventana que se ve en la Figura 3.1. Ejemplo
de Hola Mundo mejorado.
17
Captulo 3. Avanzando
Figura 3.1. Ejemplo de Hola Mundo mejorado
Esta vez vers que no hay una forma fcil de salir del programa, tienes que usar tu manejador de ventanas o la
lnea de comandos para matarlo. Un buen ejercicio para el lector sera insertar un tercer botn "Salir" que cerrara
el programa. Puedes intentar jugar con las opciones de pack_start() mientras lees la siguiente seccin. Prueba a
cambiar de tamao la ventana, y observa lo que pasa.
Slo como una nota, hay otra constante til para GtkWindow() - WINDOW_DIALOG. Esto interacciona con el
manejador de ventanas de una forma un poco diferente y debe usarse para ventanas temporales.
A continuacin se describen en orden las pequeas diferencias en el cdigo con respecto al primer programa
helloworld.
Como ya se ha dicho no hay manejador para el evento "destroy" en la versin mejorada de helloworld.
Las lneas 11-12 denen un mtodo de retrollamada que es similar a la retrollamada hello() en el primer
helloworld. La diferencia est en que la retrollamada imprime un mensaje incluyendo los datos que se le pasan.
La lnea 25 le pone un ttulo en la barra de ttulo de la ventana (mira la Figura 3.1. Ejemplo de Hola Mundo
mejorado).
La lnea 37 crea una caja horizontal (GtkHBox) para almacenar los dos botones que se crean en las lneas 43 y 58.
La lnea 40 aade la caja horizontal al contenedor de la ventana.
Las lneas 47 y 62 conectan el mtodo callback() a la seal "clicked" de los botones. Cada botn establece una
cadena diferente para que se le pase al mtodo callback() cuando sea invocado.
Las lneas 51 y 64 empaquetan los botones en la caja horizontal. Las lneas 55 y 68 le dicen a GTK que muestren
los botones.
Las lneas 69-70 le piden a GTK que muestre la caja y la ventana respectivamente.
18
Captulo 4. Empaquetamiento de
Controles
Cuando crees un programa, querrs poner ms de un control en una ventana. Nuestro primer ejemplo holamundo
solo usaba un control para que pudieramos usar simplemente el mtodo add() de la clase GtkContainer para
"empaquetar" el control en la ventana. Pero cuando quieres poner ms de un control en la ventana, cmo controlas
el sitio donde ese control se coloca? Aqui es donde la colocacin entra en juego.
4.1. Teora de Cajas Empaquetadoras
La mayora del empaquetamiento se realiza utilizando cajas. Estos contenedores invisibles de controles pueden
ser de dos tipos, una caja horizontal, y una caja vertical. Cuando empaquetamos controles en una caja horizontal,
los objetos se insertan horizontalmente de izquierda a derecha o de derecha a izquierda dependiendo de la llamada
que se use. En una caja vertical, los controles se empaquetan de arriba a abajo o viceversa. Puedes usar una
combinacin de cajas dentro de cajas para obtener el efecto deseado.
Para crear una nueva caja horizontal, usamos una llamada a gtk.HBox(), y para cajas verticales, gtk.VBox()
. Los mtodos pack_start() y pack_end() se utilizan para colocar objetos dentro de estos contenedores. El
mtodo pack_start() empezar en la parte de arriba e ir bajando en una vbox, y de izquierda a derecha en
una hbox. El mtodo pack_end() har lo contrario, empaquetar de abajo a arriba en una vbox, y de derecha a
izquierda en una hbox. Usando estos mtodos, podemos alinear a la derecha o a la izquierda nuestros controles y
se pueden mezclar de la forma necesaria para obtener el efecto deseado. Usaremos pack_start() en la mayora
de nuestros ejemplos. Un objeto puede ser otro contenedor o un control. De hecho, muchos controles son en
realidad contenedores por ellos mismos, incluyendo el botn, pero normalmente slo usamos una etiqueta dentro
de un botn.
Usando estas llamadas, GTK sabe donde quieres colocar tus controles y asi puede cambiar el tamao automti-
camente y otras cosas interesantes. Como puedes imaginar, este mtodo nos da bastante exibilidad al colocar y
crear controles.
4.2. Detalles de Cajas
A causa de esta exibilidad, el empaquetamiento de cajas puede ser confuso al principio. Hay muchas opciones,
y no es obvio al principio cmo enacajan todas ellas. Al nal, de cualquier forma, hay bsicamente cinco estilos.
La Figura 4.1. Empaquetamiento: Cinco variaciones muestra el resultado de ejecutar el programa packbox.py
[examples/packbox.py] con un argumento de 1:
19
Captulo 4. Empaquetamiento de
Controles
Figura 4.1. Empaquetamiento: Cinco variaciones
Cada lnea 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 la hbox. Cada botn es empaquetado en la hbox de la misma manera (por
ejemplo, con los mismos argumentos al mtodo pack_start().
Esto es un ejemplo del mtodo pack_start() .
box.pack_start(child, expand, fill, padding)
box es la caja donde estas empaquetando el objeto; el primer argumento, child, es el objeto que se va a
empaquetar. Los objetos sern botones por ahora, por lo que estaremos empaquetando botones dentro de cajas.
El argumento expand de pack_start() y pack_end() controla si los controles se disponen para ocupar todo el
espacio extra de la caja y de esta manera la caja se expande hasta ocupar todo el rea reservada para ella (TRUE); o
si la caja se encoge para ocupar el espacio justo de los controles (FALSE). Poniendo expand a FALSE te permitir
justicar a la derecha y a la izquierda tus controles. Si no, se expandirn para llenar la caja, y el mismo efecto
podra obtenerse usando slo o pack_start() o pack_end().
El argumnto fill controla si el espacio extra se utiliza en los propios objetos (TRUE), como expacio extra en la
caja alrededor de los objetos (FALSE). Slo tiene efecto si el argumento expand tambin es TRUE.
Python permite denir un mtodo o funcin con valores de argumento por defecto y argumentos con palabras
clave. A travs de este tutorial mostrar la denicin de las funciones y mtodos con valores por defecto y
palabras clave cuando sea aplicable. Por ejemplo, el mtodo pack_start se dene as:
box.pack_start(child, expand=gtk.TRUE, fill=gtk.TRUE, padding=0)
box.pack_end(child, expand=gtk.TRUE, fill=gtk.TRUE, padding=0)
20
Captulo 4. Empaquetamiento de
Controles
child, expand, fill y padding son palabras clave. Los argumentos expand, fill y padding tienen los
valores por defecto mostrados arriba. El argumento child debe especicarse.
Al crear una caja nueva, la funcin es la siguiente:
hbox = gtk.HBox(homogeneous=gtk.FALSE, spacing=0)
vbox = gtk.VBox(homogeneous=gtk.FALSE, spacing=0)
El argumento homogeneous de gtk.HBox() y gtk.VBox() controla si cada objeto en la caja tiene el mismo
tamao (por ejemplo el mismo ancho en una hbox, or el mismo alto en una vbox). Si se usa, las rutinas de
empaquetado funcionan basicamente como si el argumento expand estuviera siempre activado.
Qu diferencia hay entre spacing (se pone cuando la caja se crea) y padding (se pone cuando los elementos
se empaquetan)? El spacing se aade entre objetos, y el padding se aade a cada lado de un objeto. La
Figura 4.2. Empaquetando con Spacing y Padding ilustra la diferencia; pasa un argumento de 2 a packbox.py
[examples/packbox.py] :
Figura 4.2. Empaquetando con Spacing y Padding
La Figura 4.3. Empaquetando con pack_end() ilustra el uso del mtodo pack_end() (pasa un argumento de 3 a
packbox.py [examples/packbox.py]). La etiqueta "end" se empaqueta con el mtodo pack_end(). Se mantendr
en el borde derecho de la ventana cuando esta sea redimensionada.
21
Captulo 4. Empaquetamiento de
Controles
Figura 4.3. Empaquetando con pack_end()
4.3. Programa de Demostracin de Empaquetamiento
Aqui [examples/packbox.py] est el cdigo usado para crear la imgen de arriba. Esta bastante comentado asi que
espero que no tengas ningn problema siguiendolo. Ejectalo y juega con l.
1 #!/usr/bin/env python
2
3 # example packbox.py
4
5 import gtk
6 import sys, string
7
8 # Helper function that makes a new hbox filled with button-labels. Arguments
9 # for the variables were interested are passed in to this function. We do
10 # not show the box, but do show everything inside.
11
12 def make_box(homogeneous, spacing, expand, fill, padding):
13
14 # Create a new hbox with the appropriate homogeneous
15 # and spacing settings
16 box = gtk.HBox(homogeneous, spacing)
17
18 # Create a series of buttons with the appropriate settings
19 button = gtk.Button("box.pack")
20 box.pack_start(button, expand, fill, padding)
21 button.show()
22
23 button = gtk.Button("(button,")
24 box.pack_start(button, expand, fill, padding)
25 button.show()
26
27 # Create a button with the label depending on the value of
28 # expand.
29 if expand == gtk.TRUE:
30 button = gtk.Button("TRUE,")
31 else:
32 button = gtk.Button("FALSE,")
33
34 box.pack_start(button, expand, fill, padding)
35 button.show()
36
37 # This is the same as the button creation for "expand"
38 # above, but uses the shorthand form.
22
Captulo 4. Empaquetamiento de
Controles
39 button = gtk.Button(("FALSE,", "TRUE,")[fill==gtk.TRUE])
40 box.pack_start(button, expand, fill, padding)
41 button.show()
42
43 padstr = "%d)" % padding
44
45 button = gtk.Button(padstr)
46 box.pack_start(button, expand, fill, padding)
47 button.show()
48 return box
49
50 class PackBox1:
51 def delete_event(self, widget, event, data=None):
52 gtk.main_quit()
53 return gtk.FALSE
54
55 def __init__(self, which):
56
57 # Create our window
58 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
59
60 # You should always remember to connect the delete_event signal
61 # to the main window. This is very important for proper intuitive
62 # behavior
63 self.window.connect("delete_event", self.delete_event)
64 self.window.set_border_width(10)
65
66 # We create a vertical box (vbox) to pack the horizontal boxes into.
67 # This allows us to stack the horizontal boxes filled with buttons one
68 # on top of the other in this vbox.
69 box1 = gtk.VBox(gtk.FALSE, 0)
70
71 # which example to show. These correspond to the pictures above.
72 if which == 1:
73 # create a new label.
74 label = gtk.Label("HBox(FALSE, 0)")
75
76 # Align the label to the left side. Well discuss this method
77 # and others in the section on Widget Attributes.
78 label.set_alignment(0, 0)
79
80 # Pack the label into the vertical box (vbox box1). Remember that
81 # widgets added to a vbox will be packed one on top of the other in
82 # order.
83 box1.pack_start(label, gtk.FALSE, gtk.FALSE, 0)
84
85 # Show the label
86 label.show()
87
88 # Call our make box function - homogeneous = FALSE, spacing = 0,
89 # expand = FALSE, fill = FALSE, padding = 0
90 box2 = make_box(gtk.FALSE, 0, gtk.FALSE, gtk.FALSE, 0)
91 box1.pack_start(box2, gtk.FALSE, gtk.FALSE, 0)
92 box2.show()
93
94 # Call our make box function - homogeneous = FALSE, spacing = 0,
95 # expand = TRUE, fill = FALSE, padding = 0
96 box2 = make_box(gtk.FALSE, 0, gtk.TRUE, gtk.FALSE, 0)
97 box1.pack_start(box2, gtk.FALSE, gtk.FALSE, 0)
23
Captulo 4. Empaquetamiento de
Controles
98 box2.show()
99
100 # Args are: homogeneous, spacing, expand, fill, padding
101 box2 = make_box(gtk.FALSE, 0, gtk.TRUE, gtk.TRUE, 0)
102 box1.pack_start(box2, gtk.FALSE, gtk.FALSE, 0)
103 box2.show()
104
105 # Creates a separator, well learn more about these later,
106 # but they are quite simple.
107 separator = gtk.HSeparator()
108
109 # Pack the separator into the vbox. Remember each of these
110 # widgets is being packed into a vbox, so theyll be stacked
111 # vertically.
112 box1.pack_start(separator, gtk.FALSE, gtk.TRUE, 5)
113 separator.show()
114
115 # Create another new label, and show it.
116 label = gtk.Label("HBox(TRUE, 0)")
117 label.set_alignment(0, 0)
118 box1.pack_start(label, gtk.FALSE, gtk.FALSE, 0)
119 label.show()
120
121 # Args are: homogeneous, spacing, expand, fill, padding
122 box2 = make_box(gtk.TRUE, 0, gtk.TRUE, gtk.FALSE, 0)
123 box1.pack_start(box2, gtk.FALSE, gtk.FALSE, 0)
124 box2.show()
125
126 # Args are: homogeneous, spacing, expand, fill, padding
127 box2 = make_box(gtk.TRUE, 0, gtk.TRUE, gtk.TRUE, 0)
128 box1.pack_start(box2, gtk.FALSE, gtk.FALSE, 0)
129 box2.show()
130
131 # Another new separator.
132 separator = gtk.HSeparator()
133 # The last 3 arguments to pack_start are:
134 # expand, fill, padding.
135 box1.pack_start(separator, gtk.FALSE, gtk.TRUE, 5)
136 separator.show()
137 elif which == 2:
138 # Create a new label, remember box1 is a vbox as created
139 # near the beginning of __init__()
140 label = gtk.Label("HBox(FALSE, 10)")
141 label.set_alignment( 0, 0)
142 box1.pack_start(label, gtk.FALSE, gtk.FALSE, 0)
143 label.show()
144
145 # Args are: homogeneous, spacing, expand, fill, padding
146 box2 = make_box(gtk.FALSE, 10, gtk.TRUE, gtk.FALSE, 0)
147 box1.pack_start(box2, gtk.FALSE, gtk.FALSE, 0)
148 box2.show()
149
150 # Args are: homogeneous, spacing, expand, fill, padding
151 box2 = make_box(gtk.FALSE, 10, gtk.TRUE, gtk.TRUE, 0)
152 box1.pack_start(box2, gtk.FALSE, gtk.FALSE, 0)
153 box2.show()
154
155 separator = gtk.HSeparator()
156 # The last 3 arguments to pack_start are:
24
Captulo 4. Empaquetamiento de
Controles
157 # expand, fill, padding.
158 box1.pack_start(separator, gtk.FALSE, gtk.TRUE, 5)
159 separator.show()
160
161 label = gtk.Label("HBox(FALSE, 0)")
162 label.set_alignment(0, 0)
163 box1.pack_start(label, gtk.FALSE, gtk.FALSE, 0)
164 label.show()
165
166 # Args are: homogeneous, spacing, expand, fill, padding
167 box2 = make_box(gtk.FALSE, 0, gtk.TRUE, gtk.FALSE, 10)
168 box1.pack_start(box2, gtk.FALSE, gtk.FALSE, 0)
169 box2.show()
170
171 # Args are: homogeneous, spacing, expand, fill, padding
172 box2 = make_box(gtk.FALSE, 0, gtk.TRUE, gtk.TRUE, 10)
173 box1.pack_start(box2, gtk.FALSE, gtk.FALSE, 0)
174 box2.show()
175
176 separator = gtk.HSeparator()
177 # The last 3 arguments to pack_start are:
178 # expand, fill, padding.
179 box1.pack_start(separator, gtk.FALSE, gtk.TRUE, 5)
180 separator.show()
181
182 elif which == 3:
183
184 # This demonstrates the ability to use pack_end() to
185 # right justify widgets. First, we create a new box as before.
186 box2 = make_box(gtk.FALSE, 0, gtk.FALSE, gtk.FALSE, 0)
187
188 # Create the label that will be put at the end.
189 label = gtk.Label("end")
190 # Pack it using pack_end(), so it is put on the right
191 # side of the hbox created in the make_box() call.
192 box2.pack_end(label, gtk.FALSE, gtk.FALSE, 0)
193 # Show the label.
194 label.show()
195
196 # Pack box2 into box1
197 box1.pack_start(box2, gtk.FALSE, gtk.FALSE, 0)
198 box2.show()
199
200 # A separator for the bottom.
201 separator = gtk.HSeparator()
202
203 # This explicitly sets the separator to 400 pixels wide by 5
204 # pixels high. This is so the hbox we created will also be 400
205 # pixels wide, and the "end" label will be separated from the
206 # other labels in the hbox. Otherwise, all the widgets in the
207 # hbox would be packed as close together as possible.
208 separator.set_usize(400, 5)
209 # pack the separator into the vbox (box1) created near the start
210 # of __init__()
211 box1.pack_start(separator, gtk.FALSE, gtk.TRUE, 5)
212 separator.show()
213
214 # Create another new hbox.. remember we can use as many as we need!
215 quitbox = gtk.HBox(gtk.FALSE, 0)
25
Captulo 4. Empaquetamiento de
Controles
216
217 # Our quit button.
218 button = gtk.Button("Quit")
219
220 # Setup the signal to terminate the program when the button is clicked
221 button.connect_object("clicked", gtk.mainquit, self.window)
222 # Pack the button into the quitbox.
223 # The last 3 arguments to pack_start are:
224 # expand, fill, padding.
225 quitbox.pack_start(button, gtk.TRUE, gtk.FALSE, 0)
226 # pack the quitbox into the vbox (box1)
227 box1.pack_start(quitbox, gtk.FALSE, gtk.FALSE, 0)
228
229 # Pack the vbox (box1) which now contains all our widgets, into the
230 # main window.
231 self.window.add(box1)
232
233 # And show everything left
234 button.show()
235 quitbox.show()
236
237 box1.show()
238 # Showing the window last so everything pops up at once.
239 self.window.show()
240
241 def main():
242 # And of course, our main loop.
243 gtk.main()
244 # Control returns here when main_quit() is called
245 return 0
246
247 if __name__ =="__main__":
248 if len(sys.argv) != 2:
249 sys.stderr.write("usage: packbox.py num, where num is 1, 2, or 3.\n")
250 sys.exit(1)
251 PackBox1(string.atoi(sys.argv[1]))
252 main()
El pequeo tour por el cdigo packbox.py [examples/packbox.py] empieza por las lineas 12-48 que denen una
funcin auxiliar que crea una caja horizontal y la rellena con botones segn los parmetros especcados. Devuelve
una referencia a la caja horizontal.
Las lineas 55-239 denen el mtodo de inicializacin __init__() de la clase PackBox1 que crea una ventana
y una caja vertical dentro de ella que se rellena con una conguracin de controles dependiendo del argumento
que se le pase. Si se le pasa un 1, las lineas 73-136 crean una ventana mostrando las cinco nicas posibilidades
que hay cuando variamos los parmetros homogeneous, expand y ll. Si se le pasa un 2, las lineas 138-180 crean
una ventana mostrando las diferentes combinaciones de ll con spacing y padding. Finalmente, si le pasamos un
3, las lineas 186-212 crean una ventana mostrando el uso del mtodo pack_start() para justicar los botones a
la izquierda y el mtodo pack_end() para justicar una etiqueta a la derecha. Las lineas 215-235 crean una caja
horizontal que contiene un botn que se empaqueta dentro de la caja vertical. La seal clicked del botn est
conectada a la funcin PyGTK main_quit() para terminar el programa.
Las lineas 248-250 comprueba los argumentos de la linea de comandos y terminan el programa usando la funcin
sys.exit() si no hay exactamente un argumento. La linea 251 crea una instancia de PackBox1. La linea 252
llama a la funcin main() para empezar el bucle de procesamiento de eventos GTK.
26
Captulo 4. Empaquetamiento de
Controles
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 despus.
4.4. Uso de Tablas para Empaquetar
Veamos otra manera de empaquetar - Tablas. Pueden ser extremadamente tiles en determinadas situaciones.
Al usar tablas, creamos una rejilla donde podemos colocar los controles. Los controles puede ocupar tantos
espacios como especiquemos.
Lo primero que hay que mirar es obviamente la funcin gtk.Table() :
table = gtk.Table(rows=1, columns=1, homogeneous=FALSE)
El primer argumento es el nmero de las de la tabla, mientras que el segundo, obviamente, es el nmero de
columnas.
El argumento homogeneous tiene que ver en el tamao de las celdas de la tabla. Si homogeneous es TRUE, las
celdas de la tabla tienen el tamao del mayor control en la tabla. Si homogeneous es FALSE, el tamao de las
celdas viene dado por el control ms alto en su misma la, y el control ms ancho en su columna.
Las las y las columnas se disponen de 0 a n, donde n es el nmero que se especic en la llamada a gtk.Table().
Por tanto, si especicas rows (las) = 2 y columns (columnas) = 2, la dispoisicin quedara as:
0 1 2
0+----------+----------+
| | |
1+----------+----------+
| | |
2+----------+----------+
Fijate que el sistema de coordenadas empieza en la esquina superior izquierda. Para meter un control en una caja,
usa el siguiente mtodo:
table.attach(child, left_attach, right_attach, top_attach, bottom_attach,
xoptions=EXPAND|FILL, yoptions=EXPAND|FILL, xpadding=0, ypadding=0)
La instancia table es la tabla que creaste con gtk.Table(). El primer parmetro ("child") es el control que quieres
meter en la tabla.
Los argumentos left_attach, right_attach, top_attach y bottom_attach especican donde colocar el
control, y cuantas cajas usar. Si quieres un botn en la esquina inferior derecha de una tabla 2x2, y quieres que
ocupe SLO ese espacio, left_attach sera = 1, right_attach = 2, top_attach = 1, bottom_attach = 2.
Ahora, si quieres que un control ocupe la la entera de nuestra tabla 2x2, pondras left_attach = 0,
right_attach = 2, top_attach = 0, bottom_attach = 1.
Los argumentos xoptions y yoptions se usan para especicar opciones de colocacin y pueden ser unidas
mediante la operacin OR permitiendo as mltiples opciones.
Estas opciones son:
27
Captulo 4. Empaquetamiento de
Controles
FILL Si la caja es ms grande que el control, y especicas FILL, el control se expandir hasta
usar todo el espacio disponible.
SHRINK Si se le asigna menos espacio a la tabla del que solicit (normalmente porque el usuario ha
redimensionado la ventana), entonces los controles normalmente sera empujados a la parte
inferior de la ventana y desapareceran. Si especicas SHRINK, los controles se encojeran
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 vaco especicado en pixeles alrededor del control.
Tambin tenemos los mtodos set_row_spacing() y set_col_spacing() . Aaden espacio entre las las en
la columna o la especicada.
table.set_row_spacing(row, spacing)
y
table.set_col_spacing(column, spacing)
Fijate que para las columnas, el espacio va a la derecha de la columna, y para las las, el espacio va debajo de la
la.
Tambin puedes poner un espacio consistente para todas las las y/o columnas con:
table.set_row_spacings(spacing)
y,
table.set_col_spacings(spacing)
Fijate que con estas funciones, la ltima la y la ltima columna no obtienen ningn espacio.
4.5. Ejemplo de Empaquetamiento con Tablas
El programa de ejemplo table.py [examples/table.py] hace una ventana con tres botones en una tabla 2x2. Los
primeros dos botones se colocarn en la la superior. Un tercer botn, de salir, se coloca en la la inferior,
ocupando las dos columnas. La Figura 4.4. Empaquetamiento usando una Tabla ilustra la ventana resultante:
28
Captulo 4. Empaquetamiento de
Controles
Figura 4.4. Empaquetamiento usando una Tabla
Aqui va el cdigo fuente:
1 #!/usr/bin/env python
2
3 # example table.py
4
5 import gtk
6
7 class Table:
8 # Our callback.
9 # The data passed to this method is printed to stdout
10 def callback(self, widget, data=None):
11 print "Hello again - %s was pressed" % data
12
13 # This callback quits the program
14 def delete_event(self, widget, event, data=None):
15 gtk.main_quit()
16 return gtk.FALSE
17
18 def __init__(self):
19 # Create a new window
20 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
21
22 # Set the window title
23 self.window.set_title("Table")
24
25 # Set a handler for delete_event that immediately
26 # exits GTK.
27 self.window.connect("delete_event", self.delete_event)
28
29 # Sets the border width of the window.
30 self.window.set_border_width(20)
31
32 # Create a 2x2 table
33 table = gtk.Table(2, 2, gtk.TRUE)
34
35 # Put the table in the main window
36 self.window.add(table)
37
38 # Create first button
39 button = gtk.Button("button 1")
40
41 # When the button is clicked, we call the "callback" method
42 # with a pointer to "button 1" as its argument
43 button.connect("clicked", self.callback, "button 1")
29
Captulo 4. Empaquetamiento de
Controles
44
45
46 # Insert button 1 into the upper left quadrant of the table
47 table.attach(button, 0, 1, 0, 1)
48
49 button.show()
50
51 # Create second button
52
53 button = gtk.Button("button 2")
54
55 # When the button is clicked, we call the "callback" method
56 # with a pointer to "button 2" as its argument
57 button.connect("clicked", self.callback, "button 2")
58 # Insert button 2 into the upper right quadrant of the table
59 table.attach(button, 1, 2, 0, 1)
60
61 button.show()
62
63 # Create "Quit" button
64 button = gtk.Button("Quit")
65
66 # When the button is clicked, we call the mainquit function
67 # and the program exits
68 button.connect("clicked", gtk.mainquit)
69
70 # Insert the quit button into the both lower quadrants of the table
71 table.attach(button, 0, 2, 1, 2)
72
73 button.show()
74
75 table.show()
76 self.window.show()
77
78 def main():
79 gtk.main()
80 return 0
81
82 if __name__ =="__main__":
83 Table()
84 main()
La clase Table se dene entre las lineas 7-76. Las lineas 10-11 denen el mtodo callback() que se llama
cuando se hace "click" en dos de los botones. La retrollamada slo imprime un mensaje en la consola indicando
qu botn fue pulsado usando los datos que se le pasan.
Las lineas 14-16 denen el mtodo delete_event() que se llama cuando el manejador de ventanas le pide a la
ventana que se elimine.
Las lineas 18-76 denen el constructor de la clase Table __init__() . Crea una ventana (linea 20), le pone el
ttulo (linea 23), conecta la retrollamada delete_event() a la seal "delete_event" (linea 27), y le pone el ancho
al borde (linea 30). Se crea una gtk.Table en la linea 33 y se aade a la ventana en la linea 36.
Los dos botones superiores se crean (lineas 39 y 53), sus seales "clicked" se conectan al mtodo callback()
(lineas 43 y 57), y se aaden a la tabla en la primera la (lineas 47 y 59). Las lineas 64-71 crean el botn "Quit",
conectan su seal "clicked" a la funcin mainquit() y lo aaden a la tabla ocupando la la inferior completa.
30
Captulo 5. Perspectiva General de
Controles
Los pasos generales para usar un control (widget) en PyGTK son:
Llama a gtk.* - una de las mltiples funciones para crear un nuevo control. Estas funciones se detallan en esta
seccin.
Conecta todas la seales y eventos que queramos usar a los manejadores apropiados.
Establece los atributos del control.
Empaqueta el control dentro de un contenedor usando una llamada como gtk.Container.add() o
gtk.Box.pack_start().
Llama a gtk.Widget.show() en el control.
show() le permite saber a GTK que hemos terminado de congurar los atributos del control, y esta listo para ser
mostrado. Tambin puedes usar gtk.Widget.hide() para que desaparezca otra vez. El orden en el que muestras
los controles no es importante, pero te sugiero que muestres la ventana al nal para que la ventana entera aparezca
de una vez en vez de ver como los controles individuales van apareciendo en la ventana conforme se van formando.
Los hijos de un control (una ventana tambin es un control) no se mostrarn hasta que la propia ventana se muestre
usando el mtodo show() .
5.1. Jerarqua de Controles
Aqui tienes el rbol de la jerarqua utilizada para implementar los controles para tu referencia. (Los controles
obsoletos y las clases auxiliares se han omitido.)
gobject.GObject
|
gtk.Object (Objeto)
+gtk.Widget (Control)
| +gtk.Misc (Misclaneo)
| | +gtk.Label (Etiqueta)
| | | gtk.AccelLabel (EtiquetaAceleradora)
| | +gtk.Arrow (Flecha)
| | gtk.Image (Imagen)
| +gtk.Container (Contenedor)
| | +gtk.Bin (Bin?)
| | | +gtk.Alignment (Alineador)
| | | +gtk.Frame (Marco)
| | | | gtk.AspectFrame (Marco Proporcional)
| | | +gtk.Button (Botn)
| | | | +gtk.ToggleButton (Botn Biestado)
| | | | | gtk.CheckButton (Botn Activacin)
| | | | | gtk.RadioButton (Botn Exclusin Mtua)
| | | | gtk.OptionMenu (Men Opciones)
| | | +gtk.Item (Elemento)
| | | | +gtk.MenuItem (Elemento de Men)
| | | | +gtk.CheckMenuItem (Elemento Activable de Men)
| | | | | gtk.RadioMenuItem (Elemento de Exclusin Mtua de Men)
| | | | +gtk.ImageMenuItem (Elemento de Imagen de Men)
31
Captulo 5. Perspectiva General de
Controles
| | | | gtk.TearoffMenuItem (Men Desprendible)
| | | +gtk.Window (Ventana)
| | | | +gtk.Dialog (Dilogo)
| | | | | +gtk.ColorSelectionDialog (Dilogo de Seleccin de Colores)
| | | | | +gtk.FileSelection (Selector de Ficheros)
| | | | | +gtk.FontSelectionDialog (Dilogo de Seleccin de Tipos de Letra)
| | | | | +gtk.InputDialog (Dilogo de Entrada de Datos)
| | | | | gtk.MessageDialog (Dilogo de Mensaje)
| | | | gtk.Plug (Conectable)
| | | +gtk.EventBox (Caja de Eventos)
| | | +gtk.HandleBox (Manejador de Caja)
| | | +gtk.ScrolledWindow (Ventana de Desplazamiento)
| | | gtk.Viewport (Puerto)
| | +gtk.Box (Caja)
| | | +gtk.ButtonBox (Caja de Botones)
| | | | +gtk.HButtonBox (Caja de Botones Horizontal)
| | | | gtk.VButtonBox (Caja de Botones Vertical)
| | | +gtk.VBox (Caja Vertical)
| | | | +gtk.ColorSelection (Selector de Colores)
| | | | +gtk.FontSelection (Selector de Tipos de Letra)
| | | | gtk.GammaCurve (Curva Gamma)
| | | gtk.HBox (Caja Horizontal)
| | | +gtk.Combo (Lista Desplegable)
| | | gtk.Statusbar (Barra de Estado)
| | +gtk.Fixed (Fijo)
| | +gtk.Paned (Panel)
| | | +gtk.HPaned (Panel Horizontal)
| | | gtk.VPaned (Panel Vertical)
| | +gtk.Layout (Disposicin)
| | +gtk.MenuShell (Consola de Men)
| | | +gtk.MenuBar (Barra de Men)
| | | gtk.Menu (Men)
| | +gtk.Notebook (Cuaderno de Fichas)
| | +gtk.Socket (Socket)
| | +gtk.Table (Tabla)
| | +gtk.TextView (Vista de Texto)
| | +gtk.Toolbar (Barra de Herramientas)
| | gtk.TreeView (Vista de rbol)
| +gtk.Calendar (Calendario)
| +gtk.DrawingArea (rea de Dibujo)
| | gtk.Curve (Curva)
| +gtk.Editable (Editable)
| | +gtk.Entry (Entrada de Texto)
| | | gtk.SpinButton (Botn Aumentar/Disminuir)
| +gtk.Ruler (Regla)
| | +gtk.HRuler (Regla Horizontal)
| | gtk.VRuler (Regla Vertical)
| +gtk.Range (Rango)
| | +gtk.Scale (Escala)
| | | +gtk.HScale (Escala Horizontal)
| | | gtk.VScale (Escala Vertical)
| | gtk.Scrollbar (Barra de Desplazamiento)
| | +gtk.HScrollbar (Barra de Desplazamiento Horizontal)
| | gtk.VScrollbar (Barra de Desplazamiento Vertical)
| +gtk.Separator (Separador)
| | +gtk.HSeparator (Separador Horizontal)
| | gtk.VSeparator (Separador Vertical)
| +gtk.Invisible (Invisible)
| +gtk.Preview (Previsualizacin)
32
Captulo 5. Perspectiva General de
Controles
| gtk.ProgressBar (Barra de Progreso)
| +gtk.Adjustment (Ajuste)
+gtk.CellRenderer (Visualizador de Celda)
| +gtk.CellRendererPixbuf (Visualizador de Imgen de Celda)
| +gtk.CellRendererText (Visualizador de Texto de Celda)
| +gtk.CellRendererToggle (Visualizador de Activacin de Celda)
+gtk.ItemFactory (Fbrica de Elementos)
+gtk.Tooltips (Pistas)
gtk.TreeViewColumn (Columna de Vista de rbol)
5.2. Controles sin Ventana
Los siguientes controles no tienen ninguna ventana asociada. Si quieres caputar eventos, tendrs que usar
EventBox. Mira la seccin del control EventBox.
gtk.Alignment (Alineador)
gtk.Arrow (Flecha)
gtk.Bin (Bin)
gtk.Box (Caja)
gtk.Button (Botn)
gtk.CheckButton (Botn de Activacin)
gtk.Fixed (Fijo)
gtk.Image (Imgen)
gtk.Label (Etiqueta)
gtk.MenuItem (Elemento de Men)
gtk.Notebook (Cuaderno de Fichas)
gtk.Paned (Panel)
gtk.RadioButton (Botn de Exclusin Mtua)
gtk.Range (Rango)
gtk.ScrolledWindow (Ventana de Desplazamiento)
gtk.Separator (Separador)
gtk.Table (Tabla)
gtk.Toolbar (Barra de Herramientas)
gtk.AspectFrame (Marco de Aspecto)
gtk.Frame (Marco)
gtk.VBox (Caja Vertical)
gtk.HBox (Caja Horizontal)
gtk.VSeparator (Separador Vertical)
gtk.HSeparator (Separador Horizontal)
Seguiremos nuestra exploracin de PyGTK examinando cada control, creando programas de ejemplo simples
que los muestren. Otra buena fuente es el programa testgtk.py que viene con PyGTK. Se puede encontrar en
examples/testgtk/testgtk.py dentro del directorio con las fuentes de PyGTK.
33
Captulo 6. El Control de Botn
6.1. Botones Normales
Ya hemos visto casi todo lo que hay que ver sobre el control de botn. Es bastante sencillo. Puedes usar la funcin
gtk.Button() para crear un botn con una etiqueta pasndole un parmetro de cadena. Despus depende de ti el
empaquetar una etiqueta o un pixmap en este nuevo botn. Para hacer esto, crea una nueva caja, y despus coloca
tus objetos en esta caja usando el tpico pack_start(), y despus usa add() para colocar la caja dentro del botn.
La funcin para crear un botn es:
button = gtk.Button(label=None, stock=None)
si se especica una etiqueta esta se usa como texto del botn.Si se especica stock este se usa para elegir un icono
de stock y una etiqueta para el botn. Los elementos de stock 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
34
Captulo 6. El Control de Botn
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
El programa de ejemplo buttons.py [examples/buttons.py] proporciona un ejemplo del uso de gtk.Button()
para crear un botn con una imagen y una etiqueta dentro de l. He separado el cdigo para crear una caja del
resto para que puedas usarlo en tus programas. Hay ms ejemplos del uso de imgenes ms tarde en el tutorial.
La gura Figura 6.1. Botn con Pixmap y Etiqueta muestra la ventana conteniendo un botn con un imgen y una
etiqueta:
Figura 6.1. Botn con Pixmap y Etiqueta
El cdigo fuente del programa buttons.py [examples/buttons.py] es:
1 #!/usr/bin/env python
2
3 # example-start buttons buttons.c
4
5 import gtk
35
Captulo 6. El Control de Botn
6
7 # Create a new hbox with an image and a label packed into it
8 # and return the box.
9
10 def xpm_label_box(parent, xpm_filename, label_text):
11 # Create box for xpm and label
12 box1 = gtk.HBox(gtk.FALSE, 0)
13 box1.set_border_width(2)
14
15 # Get the style of the button to get the
16 # background color.
17 style = parent.get_style()
18
19 # Now on to the image stuff
20 image = gtk.Image()
21 image.set_from_file(xpm_filename)
22
23 # Create a label for the button
24 label = gtk.Label(label_text)
25
26 # Pack the pixmap and label into the box
27 box1.pack_start(image, gtk.FALSE, gtk.FALSE, 3)
28 box1.pack_start(label, gtk.FALSE, gtk.FALSE, 3)
29
30 image.show()
31 label.show()
32 return box1
33
34 class Buttons:
35 # Our usual callback method
36 def callback(self, widget, data=None):
37 print "Hello again - %s was pressed" % data
38
39 def __init__(self):
40 # Create a new window
41 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
42
43 self.window.set_title("Imaged Buttons!")
44
45 # Its a good idea to do this for all windows.
46 self.window.connect("destroy", lambda wid: gtk.main_quit())
47 self.window.connect("delete_event", lambda a1,a2:gtk.main_quit())
48
49 # Sets the border width of the window.
50 self.window.set_border_width(10)
51
52 # Create a new button
53 button = gtk.Button()
54
55 # Connect the "clicked" signal of the button to our callback
56 button.connect("clicked", self.callback, "cool button")
57
58 # This calls our box creating function
59 box1 = xpm_label_box(self.window, "info.xpm", "cool button")
60
61 # Pack and show all our widgets
62 button.add(box1)
63
64 box1.show()
36
Captulo 6. El Control de Botn
65 button.show()
66
67 self.window.add(button)
68 self.window.show()
69
70 def main():
71 gtk.main()
72 return 0
73
74 if __name__ == "__main__":
75 Buttons()
76 main()
Las lineas 10-32 denen la funcin de ayuda xpm_label_box() que crea una caja horizontal con un borde de
ancho 2 (lineas 12-13) y le pone una imagen (lineas 20-21) y una etiqueta (linea 24).
Las lineas 34-68 denen la clase Buttons Las lineas 39-68 denen el mtodo de inicializacin de instancia que
crea una ventana (linea 41), le pone el ttulo (linea 43), le conecta las seales "delete_event" y "destroy" (lineas
46-47). La linea 53 crea el botn sin etiqueta. Su seal "clicked" se conecta al mtodo callback() en la linea
56. La funcin xpm_label_box() se llama en la linea 59 para crear la imagen y la etiqueta que se pondrn en el
botn en la linea 62.
La funcin xpm_label_box() podra usarse para colocar archivos xpm y etiquetas en cualquier control que pueda
ser un contenedor.
El control Botn tiene las siguientes seales:
pressed - se emite cuando el botn del puntero se presiona en el control Botn
released - se emite cuando el botn del puntero se suelta en el control Botn
clicked - se emite cuando el botn del puntero se presiona y luego se
suelta sobre el control Botn
enter - se emite cuando el puntero entra en el control Botn
leave - se emite cuando el puntero sale del control Botn
6.2. Botones Biestado
Los Botones Biestado se derivan de los botones normales y son muy similares, excepto que siempre estn en uno
de dos estados, que cambia con un clic. Puedan estar presionados, y cuando vuelvas a hacer clic, volvern a su
estado inicial, levantados. Haz clic otra vez, y volvern a estar presionados.
Los botones Biestado son la base para los botones de activacin y los botones de exclusin mtua, y por eso,
muchas de las llamadas usadas con los botones biestado son heredados por los botones de activacin y los botones
de exclusin mtua. Volver a destacar este hecho cuando tratemos dichos botones.
Creando un nuevo botn biestado:
toggle_button = gtk.ToggleButton(label=None)
37
Captulo 6. El Control de Botn
Como puedes imaginar, estas llamadas funcionan igual que las llamadas al control de botn normal. Si no se
especica etiqueta el botn estar vacio. El texto de la etiqueta se analiza para comprobar si contiene caracteres
memotcnicos con prejo _
Para obtener el estado de un botn biestado, incluyendo los botones de exclusin mtua y los botones de activacin,
utilizamos el mecanismo del ejemplo anterior. Asi comprobamos el estado del biestado, llamando al mtodo
get_active() del objeto botn biestado. La seal que nos interesa que emiten los botones biestado (el botn
biestado, el botn de activacin y el botn de exclusin mtua) es la seal toggled. Para comprobar el estado de
estos botones, congura un manejador de seales para capturar la seal toggled, y 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 botn biestado est pulsado
else:
# Si estamos aqui, el botn biestado est levantado
Para forzar el estado de un botn biestado, y sus hijos, el botn de exclusin mtua y el botn de activacin, utiliza
este mtodo:
toggle_button.set_active(is_active)
El mtodo anterior puede usarse para forzar el estado del botn biestado, y sus hijos los botones de activacin y
de exclusin mtua. Especicando un argumento TRUE o FALSE para el parmetro is_active indicamos si el
botn debera estar pulsado o levantado. Cuando el botn biesado se crea su valor predeterminado es levantado o
FALSE.
Fjate que cuando usas el mtodo set_active(), y cambias el estado realmente, esto causa que las seales
"clicked" y "toggled" se emitan desde el botn.
toggle_button.get_active()
Este mtodo devuelve el estado actual del botn biestado como un valor booleano TRUE/FALSE.
El programa togglebutton.py [examples/togglebutton.py] proporciona un ejemplo simple del uso de botones
biestado. La gura Figura 6.2. Ejemplo de Botn Biestado ilustra la ventana resultante con el segundo botn
biestado activo:
Figura 6.2. Ejemplo de Botn Biestado
38
Captulo 6. El Control de Botn
El cdigo fuente del programa es:
1 #!/usr/bin/env python
2
3 # example togglebutton.py
4
5 import gtk
6
7 class ToggleButton:
8 # Our callback.
9 # The data passed to this method is printed to stdout
10 def callback(self, widget, data=None):
11 print "%s was toggled %s" % (data, ("OFF", "ON")[widget.get_active()])
12
13 # This callback quits the program
14 def delete_event(self, widget, event, data=None):
15 gtk.main_quit()
16 return gtk.FALSE
17
18 def __init__(self):
19 # Create a new window
20 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
21
22 # Set the window title
23 self.window.set_title("Toggle Button")
24
25 # Set a handler for delete_event that immediately
26 # exits GTK.
27 self.window.connect("delete_event", self.delete_event)
28
29 # Sets the border width of the window.
30 self.window.set_border_width(20)
31
32 # Create a vertical box
33 vbox = gtk.VBox(gtk.TRUE, 2)
34
35 # Put the vbox in the main window
36 self.window.add(vbox)
37
38 # Create first button
39 button = gtk.ToggleButton("toggle button 1")
40
41 # When the button is toggled, we call the "callback" method
42 # with a pointer to "button" as its argument
43 button.connect("toggled", self.callback, "toggle button 1")
44
45
46 # Insert button 1 into the upper left quadrant of the table
47 vbox.pack_start(button, gtk.TRUE, gtk.TRUE, 2)
48
49 button.show()
50
51 # Create second button
52
53 button = gtk.ToggleButton("toggle button 2")
54
55 # When the button is toggled, we call the "callback" method
56 # with a pointer to "button 2" as its argument
39
Captulo 6. El Control de Botn
57 button.connect("toggled", self.callback, "toggle button 2")
58 # Insert button 2 into the upper right quadrant of the table
59 vbox.pack_start(button, gtk.TRUE, gtk.TRUE, 2)
60
61 button.show()
62
63 # Create "Quit" button
64 button = gtk.Button("Quit")
65
66 # When the button is clicked, we call the mainquit function
67 # and the program exits
68 button.connect("clicked", lambda wid: gtk.main_quit())
69
70 # Insert the quit button into the both lower quadrants of the table
71 vbox.pack_start(button, gtk.TRUE, gtk.TRUE, 2)
72
73 button.show()
74 vbox.show()
75 self.window.show()
76
77 def main():
78 gtk.main()
79 return 0
80
81 if __name__ == "__main__":
82 ToggleButton()
83 main()
Las lineas interesantes son la 10-11, que denen el mtodo callback() que imprime la etiqueta del botn biestado
y su estado cuando es activado. Las lineas 43 y 57 conectan la seal "toggled" de los botones biestado al mtodo
callback().
6.3. Botones de Activacin
Los botones de activacin heredan muchas propiedades y mtodos de los botones biestado vistos anteriormente,
pero su apariencia es un poco diferente. En vez de ser botones con texto dentro de ellos, son pequeas cajas con
un texto a su derecha. Normalmente se utilizan para opciones que pueden estar activadas o desactivadas en las
aplicaciones.
El mtodo de creacin es similar que el de los botones normales.
check_button = gtk.CheckButton(label=None)
Si el argumento label se especica el mtodo crea un botn de activacin con una etiqueta a su lado. El texto de
la etiqueta se analiza para comprobar si contiene caracteres memotcnicos con prejo _
Ver y modicar el estado de un botn de activacin es idntico que en un botn biestado.
El programa checkbutton.py [examples/checkbutton.py] proporciona un ejemplo del uso de los botones de
activacin. La gura Figura 6.3. Ejemplo de Botn de Activacin ilustra la ventana resultante:
40
Captulo 6. El Control de Botn
Figura 6.3. Ejemplo de Botn de Activacin
El cdigo fuente del programa checkbutton.py [examples/checkbutton.py] es:
1 #!/usr/bin/env python
2
3 # example checkbutton.py
4
5 import gtk
6
7 class CheckButton:
8 # Our callback.
9 # The data passed to this methods is printed to stdout
10 def callback(self, widget, data=None):
11 print "%s was toggled %s" % (data, ("OFF", "ON")[widget.get_active()]) 12
13 # This callback quits the program
14 def delete_event(self, widget, event, data=None):
15 gtk.main_quit()
16 return gtk.FALSE
17
18 def __init__(self):
19 # Create a new window
20 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
21
22 # Set the window title
23 self.window.set_title("Check Button")
24
25 # Set a handler for delete_event that immediately
26 # exits GTK.
27 self.window.connect("delete_event", self.delete_event)
28
29 # Sets the border width of the window.
30 self.window.set_border_width(20)
31
32 # Create a vertical box
33 vbox = gtk.VBox(gtk.TRUE, 2)
34
35 # Put the vbox in the main window
36 self.window.add(vbox)
37
38 # Create first button
39 button = gtk.CheckButton("check button 1")
40
41
Captulo 6. El Control de Botn
41 # When the button is toggled, we call the "callback" method
42 # with a pointer to "button" as its argument
43 button.connect("toggled", self.callback, "check button 1")
44
45
46 # Insert button 1 into the upper left quadrant of the table
47 vbox.pack_start(button, gtk.TRUE, gtk.TRUE, 2)
48
49 button.show()
50
51 # Create second button
52
53 button = gtk.CheckButton("check button 2")
54
55 # When the button is toggled, we call the "callback" method
56 # with a pointer to "button 2" as its argument
57 button.connect("toggled", self.callback, "check button 2")
58 # Insert button 2 into the upper right quadrant of the table
59 vbox.pack_start(button, gtk.TRUE, gtk.TRUE, 2)
60
61 button.show()
62
63 # Create "Quit" button
64 button = gtk.Button("Quit")
65
66 # When the button is clicked, we call the mainquit function
67 # and the program exits
68 button.connect("clicked", lambda wid: gtk.main_quit())
69
70 # Insert the quit button into the both lower quadrants of the table
71 vbox.pack_start(button, gtk.TRUE, gtk.TRUE, 2)
72
73 button.show()
74 vbox.show()
75 self.window.show()
76
77 def main():
78 gtk.main()
79 return 0
80
81 if __name__ == "__main__":
82 CheckButton()
83 main()
6.4. Botones de Exclusin Mtua
Los botones de exclusin mtua son similares a los botones de activacin excepto que se agrupan de tal forma que
slo uno puede estar seleccionado/pulsado en un momento dado. Esto es bueno para sitios en los que tu aplicacin
necesita seleccionar un valor de una pequea lista de opciones.
Crear un nuevo botn de exclusin mtua se hace con la siguiente llamada:
radio_button = gtk.RadioButton(group=None, label=None)
42
Captulo 6. El Control de Botn
Te habrs dado cuenta del argumento adicional de esta llamada. Los botones de exclusin mtua requieren un
grupo para funcionar correctamente.La primera llamada a gtk.RadioButton() debe pasarle None en el primer
argumento y entonces se crear un nuevo grupo de botones de exclusin mtua con el nuevo botn de exclusin
mtua como su nico miembro.
Para aadir ms botones de exclusin mtua a un grupo, pasa una referencia a un botn de exclusin mtua en el
grupo en las llamadas posteriores a gtk.RadioButton().
Si se especica un argumento label dicho texto se analizar para comprobar si contiene caracteres memotcnicos
con prejo _
Tambin es una buena idea especicar explcitamente que botn ser el que est activado por defecto mediante:
radio_button.set_active(is_active)
Esto se describe en la seccin de los botones biestado, y funciona exactamente de la misma forma. Una vez que
los botones de exclusin mtua se agrupan juntos, slo uno del grupo puede estar activo al mismo tiempo. Si el
usuario hace clic en un botn de exclusin mtua, y luego en otro, el primer botn de exclusin mtua emitir una
seal "toggled" (para informar de que va a estar activo), y luego el segundo botn emitir su seal "toggled" (para
informar de que va a estar activo).
El programa de ejemplo radiobuttons.py [examples/radiobuttons.py] crea un grupo de botones de exclusin
mtua con tres botones. La gura Figura 6.4. Ejemplo de Botones de Exclusin Mtua ilustra la ventana
resultante:
Figura 6.4. Ejemplo de Botones de Exclusin Mtua
The source code for the example program is:
1 #!/usr/bin/env python
2
3 # example radiobuttons.py
4
5 import gtk
6
7 class RadioButtons:
8 def callback(self, widget, data=None):
43
Captulo 6. El Control de Botn
9 print "%s was toggled %s" % (data, ("OFF", "ON")[widget.get_active()])
10
11 def close_application(self, widget, event, data=None):
12 gtk.main_quit()
13 return gtk.FALSE
14
15 def __init__(self):
16 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
17
18 self.window.connect("delete_event", self.close_application)
19
20 self.window.set_title("radio buttons")
21 self.window.set_border_width(0)
22
23 box1 = gtk.VBox(gtk.FALSE, 0)
24 self.window.add(box1)
25 box1.show()
26
27 box2 = gtk.VBox(gtk.FALSE, 10)
28 box2.set_border_width(10)
29 box1.pack_start(box2, gtk.TRUE, gtk.TRUE, 0)
30 box2.show()
31
32 button = gtk.RadioButton(None, "radio button1")
33 button.connect("toggled", self.callback, "radio button 1")
34 box2.pack_start(button, gtk.TRUE, gtk.TRUE, 0)
35 button.show()
36
37 button = gtk.RadioButton(button, "radio button2")
38 button.connect("toggled", self.callback, "radio button 2")
39 button.set_active(gtk.TRUE)
40 box2.pack_start(button, gtk.TRUE, gtk.TRUE, 0)
41 button.show()
42
43 button = gtk.RadioButton(button, "radio button3")
44 button.connect("toggled", self.callback, "radio button 3")
45 box2.pack_start(button, gtk.TRUE, gtk.TRUE, 0)
46 button.show()
47
48 separator = gtk.HSeparator()
49 box1.pack_start(separator, gtk.FALSE, gtk.TRUE, 0)
50 separator.show()
51
52 box2 = gtk.VBox(gtk.FALSE, 10)
53 box2.set_border_width(10)
54 box1.pack_start(box2, gtk.FALSE, gtk.TRUE, 0)
55 box2.show()
56
57 button = gtk.Button("close")
58 button.connect_object("clicked", self.close_application, self.window,
59 None)
60 box2.pack_start(button, gtk.TRUE, gtk.TRUE, 0)
61 button.set_flags(gtk.CAN_DEFAULT)
62 button.grab_default()
63 button.show()
64 self.window.show()
65
66 def main():
67 gtk.main()
44
Captulo 6. El Control de Botn
68 return 0
69
70 if __name__ == "__main__":
71 RadioButtons()
72 main()
El cdigo es bastante simple de seguir. Las lineas 61-62 hacen que el botn "close" sea el control por defecto para
que al pulsar la tecla "Enter" cuando la ventana est activa el botn "close" emitir la seal "clicked".
45
Captulo 7. Ajustes
GTK tiene varios controles que pueden ser ajustados visualmente por el usuario usando el ratn o el teclado, tales
como los controles de rango, descritos en la seccin Controles de Rango. Tambin 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 puerto.
Obviamente, una aplicacin necesita ser capaz de reaccionar ante los cambios que el usuario realiza en los
controles de rango. Una forma de hacer esto sera que cada control emitiera su propio tipo de seal cuando
su ajuste cambiara y, o bien pasa el nuevo valor al manejador de seal, o requiere que se mire dentro de la
estructura de datos del control para ver el nuevo valor. Pero puede que tambin quieras conectar los ajustes de
varios controles juntos, para que ajustando uno se ajusten los otros. El ejemplo ms obvio de esto es conectar una
barra de desplazamiento a un puerto o a un rea de texto desplazable. Si cada control tuviera su propia manera
de manipular el valor del ajuste, entonces el programador tendra que escribir sus propios manejadores de seales
para traducir entre la salida de la seal de un control y la entrada del mtodo de ajuste de otro control.
GTK arregla este problema usando el objeto Adjustment , que no es un control sino una manera de que los
controles almacenen y pasen la informacin de ajuste de una forma abstracta y exible. El uso ms obvio de
Adjustment es almacenar los parmetros de conguracin y los valores de los controles de rango como las
barras de desplazamiento y los controles de escala. Sin embargo, como la clase Adjustments deriva de Object,
tambin tiene unas caractersticas especiales ms alla de ser estructuras de datos normales. La ms importante
es que pueden emitir seales, como los controles, y estas seales no slo 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.
Vers como los ajustes encajan entre s cuando veas otros controles que los incorporan: Barras de Progreso,
Puertos, Ventanas de Desplazamiento, y otros.
7.1. Crear un Ajuste
Muchos de los controles que usan ajustes lo hacen automticamente, pero ms tarde se mostrarn casos en los que
puedes necesitar crearlos por ti mismo. Puedes crear un ajuste usando:
adjustment = gtk.Adjustment(value=0, lower=0, upper=0, step_incr=0, page_incr=0,

page_size=0)
El argumento value es el valor inicial que quieres darle al ajuste, normalmente corresponde a la posicin superior
o la posicin ms a la izquierda de un control ajustable. El argumento lower especica el valor ms bajo que
puede tomar el ajuste. El argumento step_incr especica el incremento ms pequeo de los dos incrementos
por los que el usuario puede cambiar el valor, mientras que el argumento page_incr es el ms grande de los
dos. El argumento page_size normalmente se corresponde de alguna manera con el rea visible de un control
desplazable. El argumento upper se usa para representar la coordenada inferior o la ms a la derecha en el hijo
de un control desplazable. Por tanto no es siempre el nmero ms grande que el valor puede tomar, ya que el
page_size de tales controles normalmente es distinto de cero.
7.2. Usar los Ajustes de la Forma Fcil
Los controles ajustables pueden dividirse ms o menos en aquellos que usan y requieren unidades especcas para
estos valores, y aquellos que los tratan como nmero arbitrarios. El grupo que trata los valores como nmeros
arbitrarios incluye los controles de rango (barras de desplazamiento y escalas, la barra de progreso y los botones
de aumentar/disminuir). Todos estos controles normalmente se ajustan directamente por el usuario con el ratn o
el teclado. Tratarn los valores inferior y superior de un ajuste como un rango dentro del cual el usuario puede
manipular el valor del ajuste. Por defecto, solo modicarn el valor de un ajuste.
46
Captulo 7. Ajustes
El otro grupo incluye el control de texto, el control de puerto, el control de lista compuesta y el control de
ventana de desplazamiento. Todos estos controles usan valores de pxeles para sus ajustes. Todos estos controles
normalmente se ajustan indirectamente usando barras de desplazamiento. Aunque todos los controles que usan
ajustes pueden crear sus propios ajustes o usar los que les proporciones, normalmente querrs dejarles a ellos
la tarea de crear sus propios ajustes. Normalmente, sobreescribirn todos los valores de los ajustes que les
proporciones, excepto el propio valor, pero los resultado son, en general, impredecibles (lo que signica que
tendrs que leer el cdigo fuente para descubrirlo, y puede ser diferente entre los controles).
Ahora, probablemente estes pensando, ya que los controles de texto y los puertos insisten en establecer todos los
parmetros de sus ajustes excepto el valor, mientras que las barras de desplazamiento solo tocan el valor del ajuste,
si compartes un objeto ajuste entre una barra de desplazamiento y un control de texto, al manipular la barra de
desplazamiento, se ajustar automgicamente el control de texto? Por supuesto que lo har! Tal y como esto:
# crea sus propios ajustes
viewport = gtk.Viewport()
# usa los ajustes recin creados para la barra de desplazamiento tambin
vscrollbar = gtk.VScrollbar(viewport.get_vadjustment())
7.3. El Interior del Ajuste
Vale, dirs, eso est bien, pero qu pasa si quiero crear mis propios manejadores que respondan cuando el
usuario ajuste un control de rango o un botn aumentar/disminuir, y cmo obtengo el valor de un ajuste en estos
manejadores? Para contestar a estas preguntas y a otras ms, vamos a empezar mirando los atributos de la propia
clase gtk.Adjustment :
lower
upper
value
step_increment
page_increment
page_size
Sea adj una instancia de la clase gtk.Adjustment, cada uno de los atributos se obtienen o modican usando
adj.lower, adj.value, etc.
Ya que, cuando pones el valor de un ajuste, generalmente quieres que el cambio afecte a todos los controles que
usan este ajuste, PyGTK proporciona un mtodo para hacer esto:
adjustment.set_value(value)
Como se ha dicho antes, Adjustment es una subclase de Object igual que los dems controles, y por tanto,
es capaz de emitir seales. Esto es la causa, claro est, de por qu las actualizaciones ocurren automgicamente
cuando compartes un objeto ajuste entre una barra de desplazamiento y otro control ajustable; todos los controles
ajustables conectan manejadores de seales a la seal "value_changed" de sus ajustes, como podra hacerlo tu
programa. Aqui tienes la denicin de la retrollamada de esta seal:
def value_changed(adjustment):
47
Captulo 7. Ajustes
Los diversos controles que usan el objeto Adjustment emitirn esta seal 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 explcitamente cambia el valor con el mtodo set_value(). As, por ejemplo, si tienes un
control de escala, y quieres que cambie la rotacin de una imagen siempre que su valor cambie, podras crear una
retrollamada como esta:
def cb_rotate_picture(adj, picture):
set_picture_rotation (picture, adj.value)
...
y conectarla al ajuste del control de escala as:
adj.connect("value_changed", cb_rotate_picture, picture)
Y qu pasa cuando un control recongura los campos upper (superior) o lower (inferior) de su ajuste,
tal y como cuando un usario aade ms texto al control de texto? En este caso, se emite la seal "changed", que
es as:
def changed(adjustment):
Los controles Range normalmente conectan un manejador para esta seal, el cual cambia su apariencia para
reejar el cambio - por ejemplo, el tamao del deslizador de una barra de desplazamiento crecer o encojer en
proporcin inversa a la diferencia entre el valor superior e inferior de su ajuste.
Probablemente nunca tendrs que conectar un manejador a esta seal, a menos que estes escribiendo un nuevo
tipo de control de rango. En cualquier caso, si cambias alguno de los valores de un Adjustment directamente,
deberas emitir esta seal para recongurar los controles que lo estn usando, tal que as:
adjustment.emit("changed")
Ahora adelante y ajusta!
48
Captulo 8. Controles de Rango
La categora de los controles de rango incluye el famoso control de barra de desplazamiento y el menos comn
control de escala. Aunque estos dos tipos de controles se usan generalmente para propsitos diferentes, son
bastante similares en funcin e implementacin. Todos los controles de rango comparten un conjunto de elementos
grcos, cada uno de los cuales tiene su propia ventana X y recibe eventos. Todos ellos contienen un canal y un
deslizador (lo que a veces se ha llamado un "thumbwheel" (????) en otros entornos GUI). Arrastrar el deslizador
con el puntero del ratn hace que se mueve hacia alante y hacia atrs dentro del canal, mientras que haciendo clic
en el canal avanza el deslizador hacia la localizacin del clic, ya sea completamente, o con una cantidad designada,
dependiendo del botn del ratn que se use.
Como se mencion en Adjustments ms arriba, todos los controles de rango estn asociados con un objeto ajuste,
a partir del cual se calcula la longitud del deslizador y su posicin con respecto al canal. Cuando el usuario
manipula el deslizador, el control de rango cambiar el valor del ajuste.
8.1. Barras de Desplazamiento
Estas son tus barras de desplazamiento estandares . Deberan usarse slo para desplazar algn otro control, tal
como una lista, una caja de texto, o un puerto (y generalmente es ms fcil de usar la ventana de desplazamiento
en la mayora de los casos). Para otros propsitos, deberas usar los controles de escala, ya que son ms amigables
y tienen ms caractersticas.
Hay tipos separados para ls barras de desplazamiento horizontales y verticales. No hay demasiado que decir sobre
ellos. Los puedes crear con los siguientes mtodos:
hscrollbar = gtk.HSscrollbar(adjustment=None)
vscrollbar = gtk.VSscrollbar(adjustment=None)
y eso es todo. El argumento adjustment puede ser o una referencia a un Adjustment existente, o nada, en
cuyo caso se crear uno. Especicar nada puede ser til en el caso, en el que quieras pasar el ajuste recin creado
al constructor de algn otro control que ser congurado por ti, tal como una caja de texto.
8.2. Controles de Escala
Los controles Scale (Escala) se usan para permitir al usuario seleccionar y manipular visualmente un valor dentro
de un rango especco. Puedes querer usar un control de escala, por ejemplo, para ajustar el nivel de zoom en una
previsualizacin de una imagen, o para controlar el brillo de un color, o para especicar el nmero de minutos de
inactividad antes de que el protector de pantalla se active.
8.2.1. Crear un Control de Escala
Al igual que con las barras de desplazamiento, hay controles separados para los controles de escala horizontales
y verticales. (La mayora de los programadres suelen usar los controles de escala horizontales.) Ya que
esencialmente funcionan de la misma manera, no hay necesidad de tratarlos por separado aqui. Los siguientes
mtodos crean controles de escala verticales y horizontales, respectivamente:
vscale = gtk.VScale(adjustment=None)
hscale = gtk.HScale(adjustment=None)
49
Captulo 8. Controles de Rango
El argumento adjustment puede ser o un ajuste que ya haya sido creado con gtk.Adjustment() , o nada, en
cuyo caso se crea un Adjustment annimo con todos sus valores puestos a 0.0 (lo cual no es muy til en este
caso). Para evitarte confusiones, probablemente quieras crear tu ajuste con un valor de page_size de 0.0 para
que su valor upper realmente corresponda con el valor ms alto que el usuario puede seleccionar. (Si ya ests
realmente confundido, lee la seccin sobre Ajustes otra vez para una explicacin de lo que hacen exactamente los
ajustes y como crearlos y manipularlos.)
8.2.2. Mtodos y Seales (bueno, al menos mtodos)
Los controles de escala pueden visualizar su valor como un nmero al lado del canal. El comportamiento por
defecto es mostrar el valor, pero puedes cambiarlo con este mtodo:
scale.set_draw_value(draw_value)
Como habrs imaginado, draw_value es o TRUE o FALSE, con consecuencias predecibles para cualquiera de
los dos.
El valor que muestra un control de escala se redondea a un valor decimal por defecto, tal y como se hace con el
campo valor en su Adjustment (Ajuste). Puedes cambiar esto con:
scale.set_digits(digits)
donde digits es el nmero de posiciones decimales que quieres. Puedes poner el nmero que quieras, pero no
se veran ms de 13 posiciones en la pantalla.
Finalmente, el valor se puede mostrar en diferentes posiciones relativas al canal:
scale.set_value_pos(pos)
El argumento pos puede tomar uno de los siguientes valores:
POS_LEFT
POS_RIGHT
POS_TOP
POS_BOTTOM
Si pones el valor en un "lado" del canal (por ejemplo, en la parte de arriba o abajo de un control de escala
horizontal), entonces seguir al deslizador arriba y abajo del canal.
8.3. Mtodos Comunes de los Rangos
La clase Range es bastante complicada internamente, pero, como todas las clases base de los controles, la mayora
de su complejidad solo te interesa si quieres trastear con ella. Adems, la mayora de los mtodos y seales que
dene slo son tiles al escribir controles derivados. Hay, en cualquier caso, unos cuantos mtodos tiles que
funcionarn con todos los controles de rango.
8.3.1. Establecer la Poltica de Actualizacin
50
Captulo 8. Controles de Rango
La "poltica de actualizacin" de un control de rango dene en qu puntos de la interaccin con el usuario se
cambiar el campo de valor de su Adjustment y emitir la seal "value_changed" en este Adjustment. Las
polticas de actualizacin son:
UPDATE_CONTINUOUS Es es el valor predeterminado. La seal "value_changed" se emite contnuamente,
por ejemplo, cada vez qeu el deslizador se mueve incluso en las cantidades mas
minsculas.
UPDATE_DISCONTINUOUS La seal "value_changed" slo se mite una vez que el deslizador ha parado de
moverse y el usuario ha soltado el botn del ratn.
UPDATE_DELAYED La seal "value_changed" se emite cuando el usuario suelta el botn del ratn, o si
el deslizador para de moverse durante un corto perodo de tiempo.
La poltica de actualizacin de un control de rango puede cambiarse con este mtodo:
range.set_update_policy(policy)
8.3.2. Obtener y Cambiar Ajustes
Obtener y cambiar el ajuste de un control de rango sobre la marcha se puede hacer, predeciblemente, con:
adjustment = range.get_adjustment()
range.set_adjustment(adjustment)
El mtodo get_adjustment() devuelve una referencia al adjustment que est conectado al rango.
El mtodo set_adjustment() no hace absolutamente nada si le pasas el adjustment que el range ya est
utilizando, da igual que le hayas cambiado alguno de sus cambios o no. Si le pasas un nuevo Adjustment, se
perder la referencia al antiguo si exista (posiblemente se destruir), se conectarn las seales apropiadas al nuevo,
y se recalcular el tamao y/o posicin del deslizador y se repintar si es necesario. Como se ha mencionado en la
seccin de ajustes, si deseas reutilizar el mismo Adjustment, cuando modiques sus valores directamente, debes
emitir la seal "changed" en l, como por ejemplo:
adjustment.emit("changed")
8.4. Atajos de Teclas y Ratn
Todos los controles de rango de GTK reaccionan a clics de ratn ms o menos de la misma forma. Haciendo clic
con el botn-1 en el canal hace que el valor page_increment del ajuste se aada o se reste a su value, y que
el deslizador se mueva de forma acorde. Haciendo clic con el botn-2 en el canal har que el deslizador salte al
punto donde se ha hecho clic. Haciendo clic con cualquier botn en las echas de una barra de desplazamiento
harn que su ajuste cambie tanto como diga su valor step_increment de una vez.
Las barras de desplazamiento no pueden recibir el foco, por lo que no tienen atajos de teclado. Los atajos de
teclado de otros controles de rango (que por supuesto slo estn ativos cuando el control tiene el foco) no se
diferencian para los controles de rango horizontales y verticales.
51
Captulo 8. Controles de Rango
Todos los controles de rango pueden manejarse con las teclas de echa izquierda, echa derecha, echa arriba y
echa abajo , as como con las teclas Pgina Anterior y Pgina Siguiente . Las echas mueven el deslizador
en cantidades iguales a step_increment, mientras que Pgina Anterior y Pgina Siguiente lo mueven en
cantidades de page_increment.
El usuario tambin puede mover el deslizador directamente a un extremo o al otro del canal usando el teclado.
Esto se hace con las teclas Inicio y Fin .
8.5. Ejemplo de Control de Rango
El programa de ejemplo (rangewidgets.py [examples/rangewidgets.py]) es una versin modicada del test
"controles de rango" de testgtk.py. Bsicamente muestra una ventana con tres controles de rango todos conectados
al mismo ajuste, y un par de controles para ajustar algunos de los parmetros mencionados ms arriba y en la
seccin de ajustes, por lo que puedes ver como afectan a la manera en la que estos controles funcionan para el
usuario. La gura Figura 8.1. Ejemplo de Controles de Rango muestra el resultado de ejecutar el programa:
Figura 8.1. Ejemplo de Controles de Rango
52
Captulo 8. Controles de Rango
El cdigo fuente de rangewidgets.py [examples/rangewidgets.py] es:
1 #!/usr/bin/env python
2
3 # example rangewidgets.py
4
5 import gtk
6
7 # Convenience functions
8
9 def make_menu_item(name, callback, data=None):
10 item = gtk.MenuItem(name)
11 item.connect("activate", callback, data)
12 item.show()
13 return item
14
15 def scale_set_default_values(scale):
16 scale.set_update_policy(gtk.UPDATE_CONTINUOUS)
17 scale.set_digits(1)
18 scale.set_value_pos(gtk.POS_TOP)
19 scale.set_draw_value(gtk.TRUE)
20
21 class RangeWidgets:
22 def cb_pos_menu_select(self, item, pos):
23 # Set the value position on both scale widgets
24 self.hscale.set_value_pos(pos)
25 self.vscale.set_value_pos(pos)
26
27 def cb_update_menu_select(self, item, policy):
28 # Set the update policy for both scale widgets
29 self.hscale.set_update_policy(policy)
30 self.vscale.set_update_policy(policy)
31
32 def cb_digits_scale(self, adj):
33 # Set the number of decimal places to which adj->value is rounded
34 self.hscale.set_digits(adj.value)
35 self.vscale.set_digits(adj.value)
36
37 def cb_page_size(self, get, set):
38 # Set the page size and page increment size of the sample
39 # adjustment to the value specified by the "Page Size" scale
40 set.page_size = get.value
41 set.page_incr = get.value
42 # Now emit the "changed" signal to reconfigure all the widgets that
43 # are attached to this adjustment
44 set.emit("changed")
45
46 def cb_draw_value(self, button):
47 # Turn the value display on the scale widgets off or on depending
48 # on the state of the checkbutton
49 self.hscale.set_draw_value(button.get_active())
50 self.vscale.set_draw_value(button.get_active())
51
52 # makes the sample window
53
54 def __init__(self):
55 # Standard window-creating stuff
56 self.window = gtk.Window (gtk.WINDOW_TOPLEVEL)
53
Captulo 8. Controles de Rango
57 self.window.connect("destroy", gtk.mainquit)
58 self.window.set_title("range controls")
59
60 box1 = gtk.VBox(gtk.FALSE, 0)
61 self.window.add(box1)
62 box1.show()
63
64 box2 = gtk.HBox(gtk.FALSE, 10)
65 box2.set_border_width(10)
66 box1.pack_start(box2, gtk.TRUE, gtk.TRUE, 0)
67 box2.show()
68
69 # value, lower, upper, step_increment, page_increment, page_size
70 # Note that the page_size value only makes a difference for
71 # scrollbar widgets, and the highest value youll get is actually
72 # (upper - page_size).
73 adj1 = gtk.Adjustment(0.0, 0.0, 101.0, 0.1, 1.0, 1.0)
74
75 self.vscale = gtk.VScale(adj1)
76 scale_set_default_values(self.vscale)
77 box2.pack_start(self.vscale, gtk.TRUE, gtk.TRUE, 0)
78 self.vscale.show()
79
80 box3 = gtk.VBox(gtk.FALSE, 10)
81 box2.pack_start(box3, gtk.TRUE, gtk.TRUE, 0)
82 box3.show()
83
84 # Reuse the same adjustment
85 self.hscale = gtk.HScale(adj1)
86 self.hscale.set_size_request(200, 30)
87 scale_set_default_values(self.hscale)
88 box3.pack_start(self.hscale, gtk.TRUE, gtk.TRUE, 0)
89 self.hscale.show()
90
91 # Reuse the same adjustment again
92 scrollbar = gtk.HScrollbar(adj1)
93 # Notice how this causes the scales to always be updated
94 # continuously when the scrollbar is moved
95 scrollbar.set_update_policy(gtk.UPDATE_CONTINUOUS)
96 box3.pack_start(scrollbar, gtk.TRUE, gtk.TRUE, 0)
97 scrollbar.show()
98
99 box2 = gtk.HBox(gtk.FALSE, 10)
100 box2.set_border_width(10)
101 box1.pack_start(box2, gtk.TRUE, gtk.TRUE, 0)
102 box2.show()
103
104 # A checkbutton to control whether the value is displayed or not
105 button = gtk.CheckButton("Display value on scale widgets")
106 button.set_active(gtk.TRUE)
107 button.connect("toggled", self.cb_draw_value)
108 box2.pack_start(button, gtk.TRUE, gtk.TRUE, 0)
109 button.show()
110
111 box2 = gtk.HBox(gtk.FALSE, 10)
112 box2.set_border_width(10)
113
114 # An option menu to change the position of the value
115 label = gtk.Label("Scale Value Position:")
54
Captulo 8. Controles de Rango
116 box2.pack_start(label, gtk.FALSE, gtk.FALSE, 0)
117 label.show()
118
119 opt = gtk.OptionMenu()
120 menu = gtk.Menu()
121
122 item = make_menu_item ("Top", self.cb_pos_menu_select, gtk.POS_TOP)
123 menu.append(item)
124
125 item = make_menu_item ("Bottom", self.cb_pos_menu_select,
126 gtk.POS_BOTTOM)
127 menu.append(item)
128
129 item = make_menu_item ("Left", self.cb_pos_menu_select, gtk.POS_LEFT)
130 menu.append(item)
131
132 item = make_menu_item ("Right", self.cb_pos_menu_select, gtk.POS_RIGHT)
133 menu.append(item)
134
135 opt.set_menu(menu)
136 box2.pack_start(opt, gtk.TRUE, gtk.TRUE, 0)
137 opt.show()
138
139 box1.pack_start(box2, gtk.TRUE, gtk.TRUE, 0)
140 box2.show()
141
142 box2 = gtk.HBox(gtk.FALSE, 10)
143 box2.set_border_width(10)
144
145 # Yet another option menu, this time for the update policy of the
146 # scale widgets
147 label = gtk.Label("Scale Update Policy:")
148 box2.pack_start(label, gtk.FALSE, gtk.FALSE, 0)
149 label.show()
150
151 opt = gtk.OptionMenu()
152 menu = gtk.Menu()
153
154 item = make_menu_item("Continuous", self.cb_update_menu_select,
155 gtk.UPDATE_CONTINUOUS)
156 menu.append(item)
157
158 item = make_menu_item ("Discontinuous", self.cb_update_menu_select,
159 gtk.UPDATE_DISCONTINUOUS)
160 menu.append(item)
161
162 item = make_menu_item ("Delayed", self.cb_update_menu_select,
163 gtk.UPDATE_DELAYED)
164 menu.append(item)
165
166 opt.set_menu(menu)
167 box2.pack_start(opt, gtk.TRUE, gtk.TRUE, 0)
168 opt.show()
169
170 box1.pack_start(box2, gtk.TRUE, gtk.TRUE, 0)
171 box2.show()
172
173 box2 = gtk.HBox(gtk.FALSE, 10)
174 box2.set_border_width(10)
55
Captulo 8. Controles de Rango
175
176 # An HScale widget for adjusting the number of digits on the
177 # sample scales.
178 label = gtk.Label("Scale Digits:")
179 box2.pack_start(label, gtk.FALSE, gtk.FALSE, 0)
180 label.show()
181
182 adj2 = gtk.Adjustment(1.0, 0.0, 5.0, 1.0, 1.0, 0.0)
183 adj2.connect("value_changed", self.cb_digits_scale)
184 scale = gtk.HScale(adj2)
185 scale.set_digits(0)
186 box2.pack_start(scale, gtk.TRUE, gtk.TRUE, 0)
187 scale.show()
188
189 box1.pack_start(box2, gtk.TRUE, gtk.TRUE, 0)
190 box2.show()
191
192 box2 = gtk.HBox(gtk.FALSE, 10)
193 box2.set_border_width(10)
194
195 # And, one last HScale widget for adjusting the page size of the
196 # scrollbar.
197 label = gtk.Label("Scrollbar Page Size:")
198 box2.pack_start(label, gtk.FALSE, gtk.FALSE, 0)
199 label.show()
200
201 adj2 = gtk.Adjustment(1.0, 1.0, 101.0, 1.0, 1.0, 0.0)
202 adj2.connect("value_changed", self.cb_page_size, adj1)
203 scale = gtk.HScale(adj2)
204 scale.set_digits(0)
205 box2.pack_start(scale, gtk.TRUE, gtk.TRUE, 0)
206 scale.show()
207
208 box1.pack_start(box2, gtk.TRUE, gtk.TRUE, 0)
209 box2.show()
210
211 separator = gtk.HSeparator()
212 box1.pack_start(separator, gtk.FALSE, gtk.TRUE, 0)
213 separator.show()
214
215 box2 = gtk.VBox(gtk.FALSE, 10)
216 box2.set_border_width(10)
217 box1.pack_start(box2, gtk.FALSE, gtk.TRUE, 0)
218 box2.show()
219
220 button = gtk.Button("Quit")
221 button.connect_object("clicked", gtk.mainquit, self.window)
222 box2.pack_start(button, gtk.TRUE, gtk.TRUE, 0)
223 button.set_flags(gtk.CAN_DEFAULT)
224 button.grab_default()
225 button.show()
226 self.window.show()
227
228 def main():
229 gtk.main()
230 return 0
231
232 if __name__ == "__main__":
233 RangeWidgets()
56
Captulo 8. Controles de Rango
234 main()
Notars que el programa no llama al mtodo connect() para el evento "delete_event", si slo con la seal
destroy. Esto seguir realizando la accin deseada porque un evento "delete_event" sin tratar resultar en una
seal "destroy" mandada a la ventana.
57
Captulo 9. Miscelanea de Controles
9.1. Etiquetas
Las Labels (Etiquetas) se usan un montn en GTK, y son relativamente simples. Las Labels (Etiquetas) no
emiten seales ya que no tienen ninguna ventana X asociada. Si necesitas capturar seales, o hacer recorte, ponlas
dentro de un control EventBox (Caja de Eventos) o de un control Button (Botn).
Para crear una nueva etiqueta, usa:
label = gtk.Label(str)
El nico argumento es la cadena de texto que quieres que la etiqueta visualice. Para cambiar el texto de la etiqueta
despus de la creacin, usa el mtodo:
label.set_text(str)
label es la etiqueta que has creado previamente, y str es la nueva cadena. El espacio que necesite la nueva
cadena se ajustar automticamente si es necesario. Puedes hacer etiquetas multilinea poniendo saltos de linea en
la cadena de la etiqueta.
Para obtener la cadena actual, usa:
str = label.get_text()
label es la etiqueta que has creado, y str es la cadena que devuelve. El texto de una etiqueta se puede justicar
usando:
label.set_justify(jtype)
Los valores para jtype son:
JUSTIFY_LEFT
JUSTIFY_RIGHT
JUSTIFY_CENTER # valor predeterminado
JUSTIFY_FILL
El control de etiqueta tambin es capaz de partir el texto automticamente. Esto se puede activar usando:
label.set_line_wrap(wrap)
El argumento wrap toma un valor TRUE o FALSE.
Si quieres la etiqueta subrayada, entonces puedes ponerle un patrn a la etiqueta:
58
Captulo 9. Miscelanea de Controles
label.set_pattern(pattern)
El argumento pattern (patrn) indica cmo se ver el subrayadao. Consiste en una cadena de signos de
subrayado y caracteres de espacio. Un signo de subrayado indica que el caracter correspondiente en la etiqueta
debe estar subrayado. Por ejemplo, la cadena "__ __" subrayara los primeros dos caracteres y los
caracteres octavo y noveno. Si slo quieres un atajo subrayado ("mnemnico") en tu etiqueta, deberas usar
set_text_with_mnemonic (str) , no set_pattern().
El programa de ejemplo label.py [examples/label.py] es un ejemplo corto para ilustrar estos mtodos. Este
ejemplo hace uso del control Frame (Marco) para demostrar mejor los estilos de etiqueta. Puedes ignorar esto por
ahora ya que el control Frame (Marco) se explica despus.
En GTK+ 2.0, el texto de la etiqueta puede contener marcas para el tipo de letra y otros atributos del texto, y las
etiquetas pueden ser seleccionables (para copiar y pegar). Estas caractersticas avanzadas no se explican aqui.
La gura Figura 9.1. Ejemplos de Etiquetas ilustra el resultado de ejecutar el programa de ejemplo:
Figura 9.1. Ejemplos de Etiquetas
59
Captulo 9. Miscelanea de Controles
El cdigo fuente de label.py [examples/label.py] es:
1 #!/usr/bin/env python
2
3 # example label.py
4
5 import gtk
6
7 class Labels:
8 def __init__(self):
9 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
10 self.window.connect("destroy", gtk.mainquit)
11
12 self.window.set_title("Label")
13 vbox = gtk.VBox(gtk.FALSE, 5)
14 hbox = gtk.HBox(gtk.FALSE, 5)
15 self.window.add(hbox)
16 hbox.pack_start(vbox, gtk.FALSE, gtk.FALSE, 0)
17 self.window.set_border_width(5)
18
19 frame = gtk.Frame("Normal Label")
20 label = gtk.Label("This is a Normal label")
21 frame.add(label)
22 vbox.pack_start(frame, gtk.FALSE, gtk.FALSE, 0)
23
24 frame = gtk.Frame("Multi-line Label")
25 label = gtk.Label("This is a Multi-line label.\nSecond line\n"
26 "Third line")
27 frame.add(label)
28 vbox.pack_start(frame, gtk.FALSE, gtk.FALSE, 0)
29
30 frame = gtk.Frame("Left Justified Label")
31 label = gtk.Label("This is a Left-Justified\n"
32 "Multi-line label.\nThird line")
33 label.set_justify(gtk.JUSTIFY_LEFT)
34 frame.add(label)
35 vbox.pack_start(frame, gtk.FALSE, gtk.FALSE, 0)
36
37 frame = gtk.Frame("Right Justified Label")
38 label = gtk.Label("This is a Right-Justified\nMulti-line label.\n"
39 "Fourth line, (j/k)")
40 label.set_justify(gtk.JUSTIFY_RIGHT)
41 frame.add(label)
42 vbox.pack_start(frame, gtk.FALSE, gtk.FALSE, 0)
43
44 vbox = gtk.VBox(gtk.FALSE, 5)
45 hbox.pack_start(vbox, gtk.FALSE, gtk.FALSE, 0)
46 frame = gtk.Frame("Line wrapped label")
47 label = gtk.Label("This is an example of a line-wrapped label. It "
48 "should not be taking up the entire "
49 "width allocated to it, but automatically "
50 "wraps the words to fit. "
51 "The time has come, for all good men, to come to "
52 "the aid of their party. "
53 "The sixth sheiks six sheeps sick.\n"
54 " It supports multiple paragraphs correctly, "
55 "and correctly adds "
56 "many extra spaces. ")
60
Captulo 9. Miscelanea de Controles
57 label.set_line_wrap(gtk.TRUE)
58 frame.add(label)
59 vbox.pack_start(frame, gtk.FALSE, gtk.FALSE, 0)
60
61 frame = gtk.Frame("Filled, wrapped label")
62 label = gtk.Label("This is an example of a line-wrapped, filled label. "
63 "It should be taking "
64 "up the entire width allocated to it. "
65 "Here is a sentence to prove "
66 "my point. Here is another sentence. "
67 "Here comes the sun, do de do de do.\n"
68 " This is a new paragraph.\n"
69 " This is another newer, longer, better "
70 "paragraph. It is coming to an end, "
71 "unfortunately.")
72 label.set_justify(gtk.JUSTIFY_FILL)
73 label.set_line_wrap(gtk.TRUE)
74 frame.add(label)
75 vbox.pack_start(frame, gtk.FALSE, gtk.FALSE, 0)
76
77 frame = gtk.Frame("Underlined label")
78 label = gtk.Label("This label is underlined!\n"
79 "This one is underlined in quite a funky fashion")
80 label.set_justify(gtk.JUSTIFY_LEFT)
81 label.set_pattern(
82 "_________________________ _ _________ _ ______ __ _______ ___")
83 frame.add(label)
84 vbox.pack_start(frame, gtk.FALSE, gtk.FALSE, 0)
85 self.window.show_all ()
86
87 def main():
88 gtk.main()
89 return 0
90
91 if __name__ == "__main__":
92 Labels()
93 main()
9.2. Flechas
El control Arrow (Flecha) dibuja la cabeza de una echa, apuntando a un nmero de direcciones posibles y con
un nmero de estilos posibles. Puede ser muy til en un botn en muchas aplicaciones. Al igual que con el control
Label (Etiqueta), no emite ninguna seal.
Slo hay dos llamadas para manipular un control Arrow :
arrow = gtk.Arrow(arrow_type, shadow_type)
arrow.set(arrow_type, shadow_type)
La primera crea un control echacon el tipo y apariencia indicados. La segunda permite cambiar estos valores
respectivamente. El argumento arrow_type puede tomar uno de lo siguientes valores:
ARROW_UP #(Arriba)
61
Captulo 9. Miscelanea de Controles
ARROW_DOWN #(Abajo)
ARROW_LEFT #(Izquierda)
ARROW_RIGHT #(Derecha)
Estos valores obviamente indican la direccin hacia la que apunta la echa. El argumento shadow_type puede
tomar uno de los siguientes valores:
SHADOW_IN
SHADOW_OUT # valor predeterminado
SHADOW_ETCHED_IN
SHADOW_ETCHED_OUT
El programa de ejemplo arrow.py [examples/arrow.py] ilustra brevemente su uso. La gura Figura 9.2. Ejemplos
de Botones con Flechas muestra el resultado de ejecutar el programa:
Figura 9.2. Ejemplos de Botones con Flechas
El cdigo fuente del programa arrow.py [examples/arrow.py] es:
1 #!/usr/bin/env python
2
3 # example arrow.py
4
5 import gtk
6
7 # Create an Arrow widget with the specified parameters
8 # and pack it into a button
9 def create_arrow_button(arrow_type, shadow_type):
10 button = gtk.Button();
11 arrow = gtk.Arrow(arrow_type, shadow_type);
12 button.add(arrow)
13 button.show()
14 arrow.show()
15 return button
16
17 class Arrows:
18 def __init__(self):
19 # Create a new window
20 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
21
22 window.set_title("Arrow Buttons")
23
24 # Its a good idea to do this for all windows.
25 window.connect("destroy", gtk.mainquit)
26
27 # Sets the border width of the window.
28 window.set_border_width(10)
62
Captulo 9. Miscelanea de Controles
29
30 # Create a box to hold the arrows/buttons
31 box = gtk.HBox(gtk.FALSE, 0)
32 box.set_border_width(2)
33 window.add(box)
34
35 # Pack and show all our widgets
36 box.show()
37
38 button = create_arrow_button(gtk.ARROW_UP, gtk.SHADOW_IN)
39 box.pack_start(button, gtk.FALSE, gtk.FALSE, 3)
40
41 button = create_arrow_button(gtk.ARROW_DOWN, gtk.SHADOW_OUT)
42 box.pack_start(button, gtk.FALSE, gtk.FALSE, 3)
43
44 button = create_arrow_button(gtk.ARROW_LEFT, gtk.SHADOW_ETCHED_IN)
45 box.pack_start(button, gtk.FALSE, gtk.FALSE, 3)
46
47 button = create_arrow_button(gtk.ARROW_RIGHT, gtk.SHADOW_ETCHED_OUT)
48 box.pack_start(button, gtk.FALSE, gtk.FALSE, 3)
49
50 window.show()
51
52 def main():
53 gtk.main()
54 return 0
55
56 if __name__ == "__main__":
57 Arrows()
58 main()
9.3. El Objeto Pistas
Las Tooltips (Pistas) son pequeas cadenas de texto que aparecen cuando dejas el cursor sobre un botn u otro
control durante unos segundos.
Los controles que no reciben eventos (controles que no tienen su propia ventana) no funcionarn con las pistas.
La primera llamada que usars crear una nueva pista. Slo tienes que hacer esto una vez ya que el objeto que
devuelve gtk.Tooltips puede usarse para crear mltiples pistas.
tooltips = gtk.Tooltips()
Una vez que has creado una nueva pista, y el control que quieres que la use est preparado, simplemente usa esta
llamada para asociarlos:
tooltips.set_tip(widget, tip_text, tip_private=None)
El objeto tooltips es la pista que acabas de crear. El primero argumento (widget) es el control que quieres
que muestre la pista; el segundo argumento (tip_text), el texto que quieres visualizar. El ltimo argumento
(tip_private) es una cadena de texto que puede usarse como identicador.
63
Captulo 9. Miscelanea de Controles
El programa de ejemplo tooltip.py [examples/tooltip.py] modica el programa arrow.py [examples/arrow.py]
para aadir una pista a cada botn. La gura Figura 9.3. Ejemplo de Pistas ilustra la ventana resultante con la
pista del segundo botn echa activada:
Figura 9.3. Ejemplo de Pistas
El cdigo fuente del programa tooltip.py [examples/tooltip.py] es:
1 #!/usr/bin/env python
2
3 # example tooltip.py
4
5 import gtk
6
7 # Create an Arrow widget with the specified parameters
8 # and pack it into a button
9 def create_arrow_button(arrow_type, shadow_type):
10 button = gtk.Button();
11 arrow = gtk.Arrow(arrow_type, shadow_type);
12 button.add(arrow)
13 button.show()
14 arrow.show()
15 return button
16
17 class Tooltips:
18 def __init__(self):
19 # Create a new window
20 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
21
22 window.set_title("Tooltips")
23
24 # Its a good idea to do this for all windows.
25 window.connect("destroy", gtk.mainquit)
26
27 # Sets the border width of the window.
28 window.set_border_width(10)
29
30 # Create a box to hold the arrows/buttons
31 box = gtk.HBox(gtk.FALSE, 0)
32 box.set_border_width(2)
33 window.add(box)
34
35 # create a tooltips object
36 self.tooltips = gtk.Tooltips()
37
38 # Pack and show all our widgets
39 box.show()
64
Captulo 9. Miscelanea de Controles
40
41 button = create_arrow_button(gtk.ARROW_UP, gtk.SHADOW_IN)
42 box.pack_start(button, gtk.FALSE, gtk.FALSE, 3)
43 self.tooltips.set_tip(button, "SHADOW_IN")
44
45 button = create_arrow_button(gtk.ARROW_DOWN, gtk.SHADOW_OUT)
46 box.pack_start(button, gtk.FALSE, gtk.FALSE, 3)
47 self.tooltips.set_tip(button, "SHADOW_OUT")
48
49 button = create_arrow_button(gtk.ARROW_LEFT, gtk.SHADOW_ETCHED_IN)
50 box.pack_start(button, gtk.FALSE, gtk.FALSE, 3)
51 self.tooltips.set_tip(button, "SHADOW_ETCHED_IN")
52
53 button = create_arrow_button(gtk.ARROW_RIGHT, gtk.SHADOW_ETCHED_OUT)
54 box.pack_start(button, gtk.FALSE, gtk.FALSE, 3)
55 self.tooltips.set_tip(button, "SHADOW_ETCHED_OUT")
56
57 window.show()
58
59 def main():
60 gtk.main()
61 return 0
62
63 if __name__ == "__main__":
64 tt = Tooltips()
65 main()
Hay otros mtodos que pueden usarse con las pistas. Simplemente los listar con una breve descripcin sobre lo
que hacen.
tooltips.enable()
Activa un conjunto de pistas desactivadas.
tooltips.disable()
Desactiva un conjunto de pistas activadas.
tooltips.set_delay(delay)
Dice cuantos milisegundos tienes que mantener el puntero sobre el control antes de que la pista aparezca. El valor
predenido es de 500 milisegundos (medio segundo).
Y esos son todos los mtodos asociados con las pistas. Ms de lo que siempre quisiste saber :-)
9.4. Barras de Progreso
Las barras de progreso se usan para mostrar el estado de una operacin. Son bastante fciles de usar, como vers
en el cdigo que sigue. Pero primero empecemos con una llamada para crar una nueva barra de progreso.
65
Captulo 9. Miscelanea de Controles
progressbar = gtk.ProgressBar(adjustment=None)
El argumento adjustment (ajuste) especica un ajusta para usarlo con la barra de progreso. Si no se especica
se crear un ajuste. Ahora la barra de progreso est creada y podemos usarla.
progressbar.set_fraction(fraction)
El objeto progressbar es la barra de progreso con la que queremos operar, y el argumento (fraction) es la
cantidad "completada", lo que signica la cantidad con la que se ha rellenado la barra de progreso desde 0 a 100%.
Esto se le pasa al mtodo como un nmero real entre 0 y 1.
Una barra de progreso puede orientarse de diversas formas usando el mmtodo:
progressbar.set_orientation(orientation)
El argumento orientation puede tomar uno de los siguientes valores para indicar la direccin 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
Adems de indicar la cantidad de progreso que se ha completado, la barra de progreso tambin puede usarse para
indicar que ha habido alguna actividad. Esto puede ser til en situaciones donde el progreso no se puede medir
con un rango de valores. La siguiente funcin indica que se ha hecho algn progreso.
progressbar.pulse()
El tamao de paso de un indicador de actividad se establece usando la siguiente funcin, donde la fraccin es un
nmero entre 0.0 y 1.0.
progressbar.set_pulse_step(fraction)
Cuando no est en el modo actividad, la barra de progreso tambin puede mostrar una cadena de texto en su canal,
usando el siguiente mtodo:
progressbar.set_text(text)
Nota
Ten en cuenta que set_text() no soporta el formateo de texto al estilo printf() como lo haca la barra
de progreso de GTK+ 1.2.
Puedes desactivar la visualizacin de la cadena llamando a set_text() otra vez sin argumentos.
66
Captulo 9. Miscelanea de Controles
La cadena de texto actual de la barra de progreso se puede obtener con el siguiente mtodo:
text = progressbar.get_text()
Normalmente las Barras de Progreso usan cronmetros u otras funciones parecidas (mira la seccin sobre
Cronmetros, E/S y Funciones de Inactividad) para dar la ilusin de multitarea. Todas usarn los mtodos
set_fraction() o pulse() de la misma forma.
El programa progressbar.py [examples/progressbar.py] proporciona un ejemplo de barra de progreso, actualizada
usando cronmetros. Este cdigo tambin muestra como reiniciar la Barra de Progreso. La gura Figura 9.4.
Ejemplo de Barra de Progreso muestra la ventana resultante:
Figura 9.4. Ejemplo de Barra de Progreso
El cdigo fuente del programa progressbar.py [examples/progressbar.py] es:
1 #!/usr/bin/env python
2
3 # example progressbar.py
4
5 import gtk
6
7 # Update the value of the progress bar so that we get
8 # some movement
9 def progress_timeout(pbobj):
10 if pbobj.activity_check.get_active():
11 pbobj.pbar.pulse()
12 else:
13 # Calculate the value of the progress bar using the
14 # value range set in the adjustment object
15 new_val = pbobj.pbar.get_fraction() + 0.01
16 if new_val > 1.0:
17 new_val = 0.0
18 # Set the new value
19 pbobj.pbar.set_fraction(new_val)
67
Captulo 9. Miscelanea de Controles
20
21 # As this is a timeout function, return TRUE so that it
22 # continues to get called
23 return gtk.TRUE
24
25 class ProgressBar:
26 # Callback that toggles the text display within the progress
27 # bar trough
28 def toggle_show_text(self, widget, data=None):
29 if widget.get_active():
30 self.pbar.set_text("some text")
31 else:
32 self.pbar.set_text("")
33
34 # Callback that toggles the activity mode of the progress
35 # bar
36 def toggle_activity_mode(self, widget, data=None):
37 if widget.get_active():
38 self.pbar.pulse()
39 else:
40 self.pbar.set_fraction(0.0)
41
42 # Callback that toggles the orientation of the progress bar
43 def toggle_orientation(self, widget, data=None):
44 if self.pbar.get_orientation() == gtk.PROGRESS_LEFT_TO_RIGHT:
45 self.pbar.set_orientation(gtk.PROGRESS_RIGHT_TO_LEFT)
46 elif self.pbar.get_orientation() == gtk.PROGRESS_RIGHT_TO_LEFT:
47 self.pbar.set_orientation(gtk.PROGRESS_LEFT_TO_RIGHT)
48
49 # Clean up allocated memory and remove the timer
50 def destroy_progress(self, widget, data=None):
51 gtk.timeout_remove(self.timer)
52 self.timer = 0
53 gtk.mainquit()
54
55 def __init__(self):
56 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
57 self.window.set_resizable(gtk.TRUE)
58
59 self.window.connect("destroy", self.destroy_progress)
60 self.window.set_title("ProgressBar")
61 self.window.set_border_width(0)
62
63 vbox = gtk.VBox(gtk.FALSE, 5)
64 vbox.set_border_width(10)
65 self.window.add(vbox)
66 vbox.show()
67
68 # Create a centering alignment object
69 align = gtk.Alignment(0.5, 0.5, 0, 0)
70 vbox.pack_start(align, gtk.FALSE, gtk.FALSE, 5)
71 align.show()
72
73 # Create the ProgressBar using the adjustment
74 self.pbar = gtk.ProgressBar()
75
76 align.add(self.pbar)
77 self.pbar.show()
78
68
Captulo 9. Miscelanea de Controles
79 # Add a timer callback to update the value of the progress bar
80 self.timer = gtk.timeout_add (100, progress_timeout, self)
81
82 separator = gtk.HSeparator()
83 vbox.pack_start(separator, gtk.FALSE, gtk.FALSE, 0)
84 separator.show()
85
86 # rows, columns, homogeneous
87 table = gtk.Table(2, 2, gtk.FALSE)
88 vbox.pack_start(table, gtk.FALSE, gtk.TRUE, 0)
89 table.show()
90
91 # Add a check button to select displaying of the trough text
92 check = gtk.CheckButton("Show text")
93 table.attach(check, 0, 1, 0, 1,
94 gtk.EXPAND | gtk.FILL, gtk.EXPAND | gtk.FILL,
95 5, 5)
96 check.connect("clicked", self.toggle_show_text)
97 check.show()
98
99 # Add a check button to toggle activity mode
100 self.activity_check = check = gtk.CheckButton("Activity mode")
101 table.attach(check, 0, 1, 1, 2,
102 gtk.EXPAND | gtk.FILL, gtk.EXPAND | gtk.FILL,
103 5, 5)
104 check.connect("clicked", self.toggle_activity_mode)
105 check.show()
106
107 # Add a check button to toggle orientation
108 check = gtk.CheckButton("Right to Left")
109 table.attach(check, 0, 1, 2, 3,
110 gtk.EXPAND | gtk.FILL, gtk.EXPAND | gtk.FILL,
111 5, 5)
112 check.connect("clicked", self.toggle_orientation)
113 check.show()
114
115 # Add a button to exit the program
116 button = gtk.Button("close")
117 button.connect("clicked", self.destroy_progress)
118 vbox.pack_start(button, gtk.FALSE, gtk.FALSE, 0)
119
120 # This makes it so the button is the default.
121 button.set_flags(gtk.CAN_DEFAULT)
122
123 # This grabs this button to be the default button. Simply hitting
124 # the "Enter" key will cause this button to activate.
125 button.grab_default ()
126 button.show()
127
128 self.window.show()
129
130 def main():
131 gtk.main()
132 return 0
133
134 if __name__ == "__main__":
135 ProgressBar()
136 main()
69
Captulo 9. Miscelanea de Controles
9.5. Dilogos
El control Dialog (Dilogo) es muy simple, y realmente es slo 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 accin").
El control Dialog (Dilogo) se puede usar para mensajes emergentes para el usuario, y otras tareas similares. Es
realmente bsico, y slo hay una funcin para la caja de dilogo, que es:
dialog = gtk.Dialog(title=None, parent=None, flags=0, buttons=None)
donde title (ttulo) es el texto usado en la barra de ttulo, parent (padre) es la ventana principal de la aplicacin
y flags establecen varios modos de operacin para el dilogo:
DIALOG_MODAL - hace el dilogo modal
DIALOG_DESTROY_WITH_PARENT - destruye el dilogo cuando su padre transient (???)

sea destruido
DIALOG_NO_SEPARATOR - omite el separador entre la vbox y el rea de accin
El argumento buttons (botones) es una tupla de pares texto de botn y respuesta. Todos los argumentos tienen
valores predeterminados y pueden especicarse usando palabras clave.
Esto crear la caja de dilogo, y ahora depende de ti el usarla. Podras empaquetar un botn en el rea de accin:
button = ...
dialog.action_area.pack_start(button, TRUE, TRUE, 0)
button.show()
Y podras aadir, por ejemplo una etiqueta, al rea vbox usando el empaqeutamiento, intenta algo as:
label = gtk.Label("Los dilogos molan")
dialog.vbox.pack_start(label, TRUE, TRUE, 0)
label.show()
Como ejemplo del uso de una caja de dilogo, podras poner dos botones en el rea de accin, un botn de Cancelar
y un botn de Aceptar, y una etiqueta en el rea vbox , preguntando al usuario una pregunta, o informando de un
error, etc. Luego podras conectar diferentes seales a cada botn y realizar la operacin que el usuario seleccione.
Si la funcionalidad bsica que proporcionan las cajas verticales y horizontales predeterminadas no te dan el
suciente control para tu aplicacin, entonces puedes simplemente empaquetar otro control dentro de las cajas
proporcionadas. Por ejemplo, podras empaquetar una tabla dentro de la caja vertical.
9.6. Imgenes
Las Images (Imgenes) son estructuras de datos que contienen dibujos. Estos dibujos se pueden usar en varios
sitios.
Las Images (Imgenes) se pueden crear a partir de Pixbufs, Pixmaps, archivos que contengan informacin de
imagen (por ejemplo. XPM, PNG, JPEG, TIFF, etc.), incluso cheros de animacin.
70
Captulo 9. Miscelanea de Controles
Las Images (Imgenes) se crean usando la funcin:
image = gtk.Image()
Despus se carga la imgen usando alguno de los siguientes mtodos:
image.set_from_pixbuf(pixbuf)
image.set_from_pixmap(pixmap, mask)
image.set_from_image(image)
image.set_from_file(filename)
image.set_from_stock(stock_id, size)
image.set_from_icon_set(icon_set, size)
image.set_from_animation(animation)
Donde pixbuf es un GdkPixbuf; pixmap y mask son GdkPixmaps; image es una GdkImage; stock_id es el
nombre de un GtkStockItem; icon_set es un GtkIconSet; y, animation es una GdkPixbufAnimation. el
argumento size (tamao) es uno de:
ICON_SIZE_MENU
ICON_SIZE_SMALL_TOOLBAR
ICON_SIZE_LARGE_TOOLBAR
ICON_SIZE_BUTTON
ICON_SIZE_DND
ICON_SIZE_DIALOG
La forma ms fcil de crear una imagen es usar el mtodo set_from_file() que automticamente determina el
tipo de imagen y la carga.
El programa images.py [examples/images.py] muestra cmo cargar varios tipos de imagen (goalie.gif
[examples/goalie.gif], apple-red.png [examples/apple-red.png], chaos.jpg [examples/chaos.jpg],
important.tif [examples/important.tif], soccerball.gif [examples/soccerball.gif]) en imagenes que
se colocan dentro de botones:
Figura 9.5. Ejemplo de Imgenes en Botones
71
Captulo 9. Miscelanea de Controles
El cdigo fuente es:
1 #!/usr/bin/env python
2
3 # example images.py
4
5 import gtk
6
7 class ImagesExample:
8 # when invoked (via signal delete_event), terminates the application.
9 def close_application(self, widget, event, data=None):
10 gtk.mainquit()
11 return gtk.FALSE
12
13 # is invoked when the button is clicked. It just prints a message.
14 def button_clicked(self, widget, data=None):
15 print "button %s clicked" % data
16
17 def __init__(self):
18 # create the main window, and attach delete_event signal to terminating
19 # the application
20 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
21 window.connect("delete_event", self.close_application)
22 window.set_border_width(10)
23 window.show()
24
25 # a horizontal box to hold the buttons
26 hbox = gtk.HBox()
27 hbox.show()
28 window.add(hbox)
29
30 pixbufanim = gtk.gdk.PixbufAnimation("goalie.gif")
31 image = gtk.Image()
32 image.set_from_animation(pixbufanim)
33 image.show()
34 # a button to contain the image widget
35 button = gtk.Button()
36 button.add(image)
37 button.show()
38 hbox.pack_start(button)
39 button.connect("clicked", self.button_clicked, "1")
40
41 # create several images with data from files and load images into
42 # buttons
43 image = gtk.Image()
44 image.set_from_file("apple-red.png")
45 image.show()
46 # a button to contain the image widget
47 button = gtk.Button()
48 button.add(image)
49 button.show()
50 hbox.pack_start(button)
51 button.connect("clicked", self.button_clicked, "2")
52
53 image = gtk.Image()
54 image.set_from_file("chaos.jpg")
55 image.show()
56 # a button to contain the image widget
72
Captulo 9. Miscelanea de Controles
57 button = gtk.Button()
58 button.add(image)
59 button.show()
60 hbox.pack_start(button)
61 button.connect("clicked", self.button_clicked, "3")
62
63 image = gtk.Image()
64 image.set_from_file("important.tif")
65 image.show()
66 # a button to contain the image widget
67 button = gtk.Button()
68 button.add(image)
69 button.show()
70 hbox.pack_start(button)
71 button.connect("clicked", self.button_clicked, "4")
72
73 image = gtk.Image()
74 image.set_from_file("soccerball.gif")
75 image.show()
76 # a button to contain the image widget
77 button = gtk.Button()
78 button.add(image)
79 button.show()
80 hbox.pack_start(button)
81 button.connect("clicked", self.button_clicked, "5")
82
83
84 def main():
85 gtk.main()
86 return 0
87
88 if __name__ == "__main__":
89 ImagesExample()
90 main()
9.6.1. Pixmaps
Los Pixmaps son estructuras de datos que contienen dibujos. Estos dibujos se pueden usar en varios sitios, pero
lo ms comn es usarlos como iconos en un escritorio X, o como cursores.
Un pixmap con slo 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 cmo 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 grcos y maneja el teclado y el ratn. Este programa
que interactua directamente con el usuario se llama un "servidor de visualizacin" o "servidor X". Ya que la
comunicacin puede tener lugar sobre una red, es importante mantener alguna informacin en el servidor X. Los
Pixmaps, por ejemplo, se almacenan en la memoria del servidor X. Esto signica que una vez que los valores
de un pixmap se establecen, no hay que seguir transmitiendolos por la red; en lugar de eso, se enva un comando
para "mostrar el pixmap nmero XYZ aqui." Incluso si no ests usando X con GTK simultneamente, usando
construcciones como Pixmaps har que tus programas funcionen en X.
Para usar pixmaps en PyGTK, primero debemos construir un GdkPixmap usando las funciones de gtk.gdk en
PyGTK. Los Pixmaps se pueden crear a partir de datos en memoria, o a partir de datos leidos de un chero.
Veamos cada una de las llamadas usadas para crear un pixmap.
73
Captulo 9. Miscelanea de Controles
pixmap = gtk.gdk.pixmap_create_from_data(window, data, width, height, fg, bg)
Esta rutina se usa para crear un pixmap con la profundidad de color dada por el argumento window a partir de
los datos data en memoria. Cada pixel usa un nmero de bits de datos para representar el color que es igual a la
profundidad de color. El width(ancho) y el height (alto) son en pixeles. El argumento window (ventana) debe
referirse a una GdkWindow realizada, ya que los recursos de un pixmap slo 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.
Pixmaps can be created from XPM les using:
pixmap, mask = gtk.gdk.pixmap_create_from_xpm(window, transparent_color, filename)
El formato XPM es una representacin legible de pixmap para el Sistema de Ventanas X. Es usado amplia-
mente y hay muchas utilidades disponibles para crear cheros de imgenes en este formato. En la funcin
pixmap_create_from_xpm() el primer argumento es un GdkWindow . (La mayora de los controles GTK tienen
una GdkWindow subyacente que se puede obtener usando el atributo window (ventana) del control.) El chero se
especicar con filename que debe contener una imagen en formato XPM el cual se carga en la estructura del
pixmap . La mask (mscara) es un bitmap que especica que bits del pixmap son opacos; se crea con la funcin.
Todos los dems pixeles se colorean con el color especicado por transparent_color. Un ejemplo del uso de
esta funcin a continuacin:
Los Pixmaps tambin puede crearse a partir de datos en memoria usando la funcin:
pixmap, mask = gtk.gdk.pixmap_create_from_xpm_d(window, transparent_color, data)
Imagenes pequeas se pueden incorporar a un programa como datos en el formato XPMusando la funcin anterior.
Un pixmap se crea usando estos datos, en lugar de leerlo de un chero. Un ejemplo de este tipo de datos es:
xpm_data = [
"16 16 3 1",
" c None",
". c #000000000000",
"X c #FFFFFFFFFFFF",
" ",
" ...... ",
" .XXX.X. ",
" .XXX.XX. ",
" .XXX.XXX. ",
" .XXX..... ",
" .XXXXXXX. ",
" .XXXXXXX. ",
" .XXXXXXX. ",
" .XXXXXXX. ",
" .XXXXXXX. ",
" .XXXXXXX. ",
" .XXXXXXX. ",
" ......... ",
" ",
" "
]
74
Captulo 9. Miscelanea de Controles
La ltima forma para crear un pixmap en blanco disponible para operaciones de dibujo es:
pixmap = gtk.gdk.Pixmap(window, width, height, depth=-1)
window es o una GdkWindow o None. Si window es una GdkWindow entonces depth puede ser -1 para indicar
que la profundidad se obtiene de la ventana. Si window es None entonces depth debe especicarse.
El programa pixmap.py [examples/pixmap.py] es un ejemplo del uso de un pixmap en un botn. La gura Figura
9.6. Ejemplo de Pixmap en un Botn muestra el resultado:
Figura 9.6. Ejemplo de Pixmap en un Botn
El cdigo fuente es:
1 #!/usr/bin/env python
2
3 # example pixmap.py
4
5 import gtk
6
7 # XPM data of Open-File icon
8 xpm_data = [
9 "16 16 3 1",
10 " c None",
11 ". c #000000000000",
12 "X c #FFFFFFFFFFFF",
13 " ",
14 " ...... ",
15 " .XXX.X. ",
16 " .XXX.XX. ",
17 " .XXX.XXX. ",
18 " .XXX..... ",
19 " .XXXXXXX. ",
20 " .XXXXXXX. ",
21 " .XXXXXXX. ",
22 " .XXXXXXX. ",
23 " .XXXXXXX. ",
24 " .XXXXXXX. ",
25 " .XXXXXXX. ",
26 " ......... ",
27 " ",
28 " "
29 ]
30
31 class PixmapExample:
32 # when invoked (via signal delete_event), terminates the application.
33 def close_application(self, widget, event, data=None):
34 gtk.mainquit()
75
Captulo 9. Miscelanea de Controles
35 return gtk.FALSE
36
37 # is invoked when the button is clicked. It just prints a message.
38 def button_clicked(self, widget, data=None):
39 print "button clicked"
40
41 def __init__(self):
42 # create the main window, and attach delete_event signal to terminating
43 # the application
44 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
45 window.connect("delete_event", self.close_application)
46 window.set_border_width(10)
47 window.show()
48
49 # now for the pixmap from XPM data
50 pixmap, mask = gtk.gdk.pixmap_create_from_xpm_d(window.window,
51 None,
52 xpm_data)
53
54 # an image widget to contain the pixmap
55 image = gtk.Image()
56 image.set_from_pixmap(pixmap, mask)
57 image.show()
58
59 # a button to contain the image widget
60 button = gtk.Button()
61 button.add(image)
62 window.add(button)
63 button.show()
64
65 button.connect("clicked", self.button_clicked)
66
67 def main():
68 gtk.main()
69 return 0
70
71 if __name__ == "__main__":
72 PixmapExample()
73 main()
Una desventaja de usar pixmaps es que que el objeto mostrado siempre es rectangular, da igual la imagen. Nos
gustara crear escritorios y aplicaciones con iconos que tengan formas ms naturales. Por ejemplo, para el interfaz
de un juego, nos gustara 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 imgen de fondo se colorea, no la sobreescribimos con un borde rectangular y que no encaja, de nuestro
icono. El programa de ejemplo wheelbarrow.p [examples/wheelbarrow.p] muestra una imagen completa en el
escritorio. La gura Figura 9.7. Ejemplo de Ventana con Forma muestra la imagen sobre una ventana de terminal:
76
Captulo 9. Miscelanea de Controles
Figura 9.7. Ejemplo de Ventana con Forma
The source code for wheelbarrow.py is:
1 #!/usr/bin/env python
2
3 # example wheelbarrow.py
4
5 import gtk
6
7 # XPM
8 WheelbarrowFull_xpm = [
9 "48 48 64 1",
10 " c None",
11 ". c #DF7DCF3CC71B",
12 "X c #965875D669A6",
13 "o c #71C671C671C6",
14 "O c #A699A289A699",
15 "+ c #965892489658",
16 "@ c #8E38410330C2",
17 "# c #D75C7DF769A6",
18 "$ c #F7DECF3CC71B",
19 "% c #96588A288E38",
20 "& c #A69992489E79",
21 "* c #8E3886178E38",
22 "= c #104008200820",
23 "- c #596510401040",
24 "; c #C71B30C230C2",
25 ": c #C71B9A699658",
26 "> c #618561856185",
27 ", c #20811C712081",
28 "< c #104000000000",
29 "1 c #861720812081",
30 "2 c #DF7D4D344103",
31 "3 c #79E769A671C6",
32 "4 c #861782078617",
33 "5 c #41033CF34103",
34 "6 c #000000000000",
35 "7 c #49241C711040",
36 "8 c #492445144924",
37 "9 c #082008200820",
38 "0 c #69A618611861",
39 "q c #B6DA71C65144",
40 "w c #410330C238E3",
77
Captulo 9. Miscelanea de Controles
41 "e c #CF3CBAEAB6DA",
42 "r c #71C6451430C2",
43 "t c #EFBEDB6CD75C",
44 "y c #28A208200820",
45 "u c #186110401040",
46 "i c #596528A21861",
47 "p c #71C661855965",
48 "a c #A69996589658",
49 "s c #30C228A230C2",
50 "d c #BEFBA289AEBA",
51 "f c #596545145144",
52 "g c #30C230C230C2",
53 "h c #8E3882078617",
54 "j c #208118612081",
55 "k c #38E30C300820",
56 "l c #30C2208128A2",
57 "z c #38E328A238E3",
58 "x c #514438E34924",
59 "c c #618555555965",
60 "v c #30C2208130C2",
61 "b c #38E328A230C2",
62 "n c #28A228A228A2",
63 "m c #41032CB228A2",
64 "M c #104010401040",
65 "N c #492438E34103",
66 "B c #28A2208128A2",
67 "V c #A699596538E3",
68 "C c #30C21C711040",
69 "Z c #30C218611040",
70 "A c #965865955965",
71 "S c #618534D32081",
72 "D c #38E31C711040",
73 "F c #082000000820",
74 " ",
75 " .XoO ",
76 " +@#$%o& ",
77 " *=-;#::o+ ",
78 " >,<12#:34 ",
79 " 45671#:X3 ",
80 " +89<02qwo ",
81 "e* >,67;ro ",
82 "ty> 459@>+&& ",
83 "$2u+ ><ipas8* ",
84 "%$;=* *3:.Xa.dfg> ",
85 "Oh$;ya *3d.a8j,Xe.d3g8+ ",
86 " Oh$;ka *3d$a8lzxxc:.e3g54 ",
87 " Oh$;kO *pd$%svbzz,sxxxxfX..&wn> ",
88 " Oh$@mO *3dthwlsslszjzxxxxxxx3:td8M4 ",
89 " Oh$@g& *3d$XNlvvvlllm,mNwxxxxxxxfa.:,B* ",
90 " Oh$@,Od.czlllllzlmmqV@V#V@fxxxxxxxf:%j5& ",
91 " Oh$1hd5lllslllCCZrV#r#:#2AxxxxxxxxxcdwM* ",
92 " OXq6c.%8vvvllZZiqqApA:mq:Xxcpcxxxxxfdc9* ",
93 " 2r<6gde3bllZZrVi7S@SV77A::qApxxxxxxfdcM ",
94 " :,q-6MN.dfmZZrrSS:#riirDSAX@Af5xxxxxfevo",
95 " +A26jguXtAZZZC7iDiCCrVVii7Cmmmxxxxxx%3g",
96 " *#16jszN..3DZZZZrCVSA2rZrV7Dmmwxxxx&en",
97 " p2yFvzssXe:fCZZCiiD7iiZDiDSSZwwxx8e*>",
98 " OA1<jzxwwc:$d%NDZZZZCCCZCCZZCmxxfd.B ",
99 " 3206Bwxxszx%et.eaAp77m77mmmf3&eeeg* ",
78
Captulo 9. Miscelanea de Controles
100 " @26MvzxNzvlbwfpdettttttttttt.c,n& ",
101 " *;16=lsNwwNwgsvslbwwvccc3pcfu<o ",
102 " p;<69BvwwsszslllbBlllllllu<5+ ",
103 " OS0y6FBlvvvzvzss,u=Blllj=54 ",
104 " c1-699Blvlllllu7k96MMMg4 ",
105 " *10y8n6FjvllllB<166668 ",
106 " S-kg+>666<M<996-y6n<8* ",
107 " p71=4 m69996kD8Z-66698&& ",
108 " &i0ycm6n4 ogk17,0<6666g ",
109 " N-k-<> >=01-kuu666> ",
110 " ,6ky& &46-10ul,66, ",
111 " Ou0<> o66y<ulw<66& ",
112 " *kk5 >66By7=xu664 ",
113 " <<M4 466lj<Mxu66o ",
114 " *>> +66uv,zN666* ",
115 " 566,xxj669 ",
116 " 4666FF666> ",
117 " >966666M ",
118 " oM6668+ ",
119 " *4 ",
120 " ",
121 " "
122 ]
123
124 class WheelbarrowExample:
125 # When invoked (via signal delete_event), terminates the application
126 def close_application(self, widget, event, data=None):
127 gtk.mainquit()
128 return gtk.FALSE
129
130 def __init__(self):
131 # Create the main window, and attach delete_event signal to terminate
132 # the application. Note that the main window will not have a titlebar
133 # since were making it a popup.
134 window = gtk.Window(gtk.WINDOW_POPUP)
135 window.connect("delete_event", self.close_application)
136 window.set_events(window.get_events() | gtk.gdk.BUTTON_PRESS_MASK)
137 window.connect("button_press_event", self.close_application)
138 window.show()
139
140 # Now for the pixmap and the image widget
141 pixmap, mask = gtk.gdk.pixmap_create_from_xpm_d(
142 window.window, None, WheelbarrowFull_xpm)
143 image = gtk.Image()
144 image.set_from_pixmap(pixmap, mask)
145 image.show()
146
147 # To display the image, we use a fixed widget to place the image
148 fixed = gtk.Fixed()
149 fixed.set_size_request(200, 200)
150 fixed.put(image, 0, 0)
151 window.add(fixed)
152 fixed.show()
153
154 # This masks out everything except for the image itself
155 window.shape_combine_mask(mask, 0, 0)
156
157 # show the window
158 window.set_position(gtk.WIN_POS_CENTER_ALWAYS)
79
Captulo 9. Miscelanea de Controles
159 window.show()
160
161 def main():
162 gtk.main()
163 return 0
164
165 if __name__ == "__main__":
166 WheelbarrowExample()
167 main()
Para hacer la imagen sensible, conectamos la seal "button_press_event" para hacer que el programa nalice.
Las lineas 137-138 hacen el dibujo sensible a una pulsacin de un botn del ratn y lo conectan al mtodo
close_application() .
9.7. Reglas
Los controles Ruler (Regla) se usan para indicar la posicin del puntero del ratn 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
pequeo tringulo indicador en la regla muestra la posicin exacta del puntero relativa a la regla.
Una regla debe crearse primero. Reglas horizontales y verticales se crean usando las siguientes funciones:
hruler = gtk.HRuler() # regla horizontal
vruler = gtk.VRuler() # regla vertical
Una vez que una regla se crea, podemos denir la unidad de medida. Las unidades de medida para las reglas
pueden ser PIXELS (PIXELES), INCHES (PULGADAS) o CENTIMETERS (CENTIMETROS). Esto se ja usando
el mtodo:
ruler.set_metric(metric)
La medida predeterminada es PIXELS.
ruler.set_metric(gtk.PIXELS)
Otra caracterstica importante de una regla es cmo marca las unidades de escala y donde se coloca el indicador
de posicin inicialmente. Esto se ja usando el mtodo:
ruler.set_range(lower, upper, position, max_size)
Los argumentos lower (bajo) y upper (alto) denen la extensin de la regla, y max_size (tamao mximo) es
el mayor nmero posible que se visualizar. La Position (Posicin) dene la posicin inicial del indicador del
puntero dentro de la regla.
Una regla vertical puede medir una ventana de 800 pxeles de ancho de la siguiente forma:
80
Captulo 9. Miscelanea de Controles
vruler.set_range(0, 800, 0, 800)
Las marcas mostradas en la regla irn desde 0 a 800, con un nmero cada 100 pxeles. Si en lugar de eso
quisieramos una regla de 7 a 16, escribiramos
vruler.set_range(7, 16, 0, 20)
El indicador de la regla es una pequea marca triangular que indica la posicin del puntero relativa a la regla.
Si la regla se usa para seguir el puntero del ratn, la seal "motion_notify_event" debe conectarse al mtodo
"motion_notify_event" de la regla. Hay que congurar una retrollamada para "motion_notify_event" para el rea
y usar connect_object() para que la regla emita una seal "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 [examples/rulers.py] crea un rea de dibujo con una regla horizontal en la parte
de arriba y una regla vertical a su izquierda. El tamao del rea de dibujo es de 600 pxeles de ancho por 400
pxeles de alto. La regla horizontal va desde 7 hasta 13 con una marca cada 100 pxeles, mientras que la regla
vertical va de 0 a 400 con una marca cada 100 pxeles. La colocacin del rea de dibujo y las reglas se hace con
una tabla. La gura Figura 9.8. Ejemplo de Reglas ilustra el resultado:
81
Captulo 9. Miscelanea de Controles
Figura 9.8. Ejemplo de Reglas
El cdigo fuente es rulers.py [examples/rulers.py] :
1 #!/usr/bin/env python
2
3 # example rulers.py
4
5 import gtk
6
7 class RulersExample:
8 XSIZE = 600
9 YSIZE = 400
10
82
Captulo 9. Miscelanea de Controles
11 # This routine gets control when the close button is clicked
12 def close_application(self, widget, event, data=None):
13 gtk.mainquit()
14 return gtk.FALSE
15
16 def __init__(self):
17 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
18 window.connect("delete_event", self.close_application)
19 window.set_border_width(10)
20
21 # Create a table for placing the ruler and the drawing area
22 table = gtk.Table(3, 2, gtk.FALSE)
23 window.add(table)
24
25 area = gtk.DrawingArea()
26 area.set_size_request(self.XSIZE, self.YSIZE)
27 table.attach(area, 1, 2, 1, 2,
28 gtk.EXPAND|gtk.FILL, gtk.FILL, 0, 0 )
29 area.set_events(gtk.gdk.POINTER_MOTION_MASK |
30 gtk.gdk.POINTER_MOTION_HINT_MASK )
31
32 # The horizontal ruler goes on top. As the mouse moves across the
33 # drawing area, a motion_notify_event is passed to the
34 # appropriate event handler for the ruler.
35 hrule = gtk.HRuler()
36 hrule.set_metric(gtk.PIXELS)
37 hrule.set_range(7, 13, 0, 20)
38 def motion_notify(ruler, event):
39 return ruler.emit("motion_notify_event", event)
40 area.connect_object("motion_notify_event", motion_notify, hrule)
41 table.attach(hrule, 1, 2, 0, 1,
42 gtk.EXPAND|gtk.SHRINK|gtk.FILL, gtk.FILL, 0, 0 )
43
44 # The vertical ruler goes on the left. As the mouse moves across
45 # the drawing area, a motion_notify_event is passed to the
46 # appropriate event handler for the ruler.
47 vrule = gtk.VRuler()
48 vrule.set_metric(gtk.PIXELS)
49 vrule.set_range(0, self.YSIZE, 10, self.YSIZE)
50 area.connect_object("motion_notify_event", motion_notify, vrule)
51 table.attach(vrule, 0, 1, 1, 2,
52 gtk.FILL, gtk.EXPAND|gtk.SHRINK|gtk.FILL, 0, 0 )
53
54 # Now show everything
55 area.show()
56 hrule.show()
57 vrule.show()
58 table.show()
59 window.show()
60
61 def main():
62 gtk.main()
63 return 0
64
65 if __name__ == "__main__":
66 RulersExample()
67 main()
83
Captulo 9. Miscelanea de Controles
Las lineas 40 y 50 conectan la retrollamada motion_notify() al rea pasandole hrule en la linea 40 y vrule
en la linea 50 como datos de usuario. La retrollamada motion_notify() se llamar dos veces cada vez que el
ratn se mueva - una vez con hrule y otra vez con vrule.
9.8. Barras de Estado
Las Statusbars (Barras de Estado) son unos controles simples que se usan para visualizar un mensaje de texto.
Mantienen una pila de los mensajes que se les han enviado, para que al quitar el mensaje actual se visualice el
mensaje anterior.
Para que distintas partes de la aplicacin puedan usar la misma barra de estado para visualizar mensajes, el control
de barra de estado mantiene Identicadores de Contexto que se usan para identicar diferentes "usuarios". El
mensaje en el tope de la pila es el que se visualiza, no importa el contexto al que pertenezca. Los mensajes se
apilan en orden ltimo en llegar primero en salir, no en orden de identicadores de contexto.
Una barra de estado se crea con una llamada a:
statusbar = gtk.Statusbar()
Se puede solicitar un nuevo Identicador de Contexto usando una llamada al siguiente mtodo con una pequea
descripcin textual del contexto:
context_id = statusbar.get_context_id(context_description)
Hay tres mtodos adicionales para utilizar las barras de estado:
message_id = statusbar.push(context_id, text)
statusbar.pop(context_id)
statusbar.remove(context_id, message_id)
El primero, push(), se usa para aadir un nuevo mensaje a la statusbar (barra de estado). Devuelve un
message_id (identicador de mensaje), que puede usarse con el mtodo remove() para borrar el mensaje que
cumpla la combinacin de message_id y context_id en la pila de la statusbar (barra de estado).
El mtodo pop() elimina el mensaje que est en la posicin ms alta de la pila con el identicador de contexto
context_id.
El programa de ejemplo statusbar.py [examples/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 gura Figura 9.9. Ejemplo
de Barra de Estado muestra el resultado:
84
Captulo 9. Miscelanea de Controles
Figura 9.9. Ejemplo de Barra de Estado
El cdigo fuente es:
1 #!/usr/bin/env python
2
3 # example statusbar.py
4
5 import gtk
6
7 class StatusbarExample:
8 def push_item(self, widget, data):
9 buff = " Item %d" % self.count
10 self.count = self.count + 1
11 self.status_bar.push(data, buff)
12 return
13
14 def pop_item(self, widget, data):
15 self.status_bar.pop(data)
16 return
17
18 def __init__(self):
19 self.count = 1
20 # create a new window
21 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
22 window.set_size_request(200, 100)
23 window.set_title("PyGTK Statusbar Example")
24 window.connect("delete_event", gtk.mainquit)
25
26 vbox = gtk.VBox(gtk.FALSE, 1)
27 window.add(vbox)
28 vbox.show()
29
30 self.status_bar = gtk.Statusbar()
31 vbox.pack_start(self.status_bar, gtk.TRUE, gtk.TRUE, 0)
32 self.status_bar.show()
33
34 context_id = self.status_bar.get_context_id("Statusbar example") 35
36 button = gtk.Button("push item")
37 button.connect("clicked", self.push_item, context_id)
38 vbox.pack_start(button, gtk.TRUE, gtk.TRUE, 2)
39 button.show()
40
41 button = gtk.Button("pop last item")
42 button.connect("clicked", self.pop_item, context_id)
85
Captulo 9. Miscelanea de Controles
43 vbox.pack_start(button, gtk.TRUE, gtk.TRUE, 2)
44 button.show()
45
46 # always display the window as the last step so it all splashes on
47 # the screen at once.
48 window.show()
49
50 def main():
51 gtk.main()
52 return 0
53
54 if __name__ == "__main__":
55 StatusbarExample()
56 main()
9.9. Entradas de Texto
El control Entry (Entrada) permite escribir texto y mostrarlo en una caja de texto con una nica linea. El texto
puede jarse con llamadas a mtodos que permiten que nuevo texto reemplace, se inserte antes o se aada despus
del contenido actual del control Entry .
La funcin para crear un control Entry es:
entry = gtk.Entry(max=0)
Si el argumento max se especica se establece un lmite de longitud del texto dentro de la Entry. Si max es 0 no
hay lmite.
La longitud mxima de una entrada puede cambiarse usando el mtodo:
entry.set_max_length(max)
El siguiente mtodo altera el texto que hay actualmente en el control Entry .
entry.set_text(text)
El mtodo set_text() ja el contenido del control Entry a text, reemplazando el contenido actual. Fjate que
la clase Entry implementa el interfaz Editable (s, gobject soporta interfaces al estilo de Java) que contiene
algunas funciones ms para manipular los contenidos. Por ejemplo, el mtodo:
entry.insert_text(text, position=0)
inserta text en la posicin indicada dentro de la entry.
El contenido de la Entry puede recuperarse usando una llamada al siguiente mtodo. Esto es til en las
retrollamadas que se describen ms abajo.
86
Captulo 9. Miscelanea de Controles
text = entry.get_text()
Si no queremos que el contenido de la Entry sea modicada por alguien escribiendo en ella, podemos cambiar
su estado de edicin.
entry.set_editable(is_editable)
El mtodo anterior permite intercambiar el estado de edicin del control Entry pasndole 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 contrasea se escribe, podemos usar el siguiente mtodo, que adems acepta una bandera booleana.
entry.set_visibility(visible)
Una regin del texto se puede poner como seleccionada usando el siguiente mtodo. Esto se usara sobre todo
cuando se ponga algn valor predeterminado en un Entry, haciendo fcil para el usuario el borrado.
entry.select_region(start, end)
Si queremos recibir noticacin cuando el usuario introduzca el texto, podemos conectar a las seales "activate"
o "changed". La primera se produce cuando el usuario pulsa la tecla enter dentro del control Entry . La segunda
se produce cuando ocurre cualquier cambio en el texto, por ejemplo para cualquier insercin o borrado de un
caracter.
El programa de ejemplo entry.py [examples/entry.py] muestra el uso de un control Entry . La gura Figura 9.10.
Ejemplo de Entrada muestra el resultado de ejecutar el programa:
Figura 9.10. Ejemplo de Entrada
87
Captulo 9. Miscelanea de Controles
El cdigo fuente entry.py [examples/entry.py] es:
1 #!/usr/bin/env python
2
3 # example entry.py
4
5 import gtk
6
7 class EntryExample:
8 def enter_callback(self, widget, entry):
9 entry_text = entry.get_text()
10 print "Entry contents: %s\n" % entry_text
11
12 def entry_toggle_editable(self, checkbutton, entry):
13 entry.set_editable(checkbutton.get_active())
14
15 def entry_toggle_visibility(self, checkbutton, entry):
16 entry.set_visibility(checkbutton.get_active())
17
18 def __init__(self):
19 # create a new window
20 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
21 window.set_size_request(200, 100)
22 window.set_title("GTK Entry")
23 window.connect("delete_event", gtk.mainquit)
24
25 vbox = gtk.VBox(gtk.FALSE, 0)
26 window.add(vbox)
27 vbox.show()
28
29 entry = gtk.Entry()
30 entry.set_max_length(50)
31 entry.connect("activate", self.enter_callback, entry)
32 entry.set_text("hello")
33 entry.insert_text(" world", len(entry.get_text()))
34 entry.select_region(0, len(entry.get_text()))
35 vbox.pack_start(entry, gtk.TRUE, gtk.TRUE, 0)
36 entry.show()
37
38 hbox = gtk.HBox(gtk.FALSE, 0)
39 vbox.add(hbox)
40 hbox.show()
41
42 check = gtk.CheckButton("Editable")
43 hbox.pack_start(check, gtk.TRUE, gtk.TRUE, 0)
44 check.connect("toggled", self.entry_toggle_editable, entry)
45 check.set_active(gtk.TRUE)
46 check.show()
47
48 check = gtk.CheckButton("Visible")
49 hbox.pack_start(check, gtk.TRUE, gtk.TRUE, 0)
50 check.connect("toggled", self.entry_toggle_visibility, entry)
51 check.set_active(gtk.TRUE)
52 check.show()
53
54 button = gtk.Button(stock=gtk.STOCK_CLOSE)
55 button.connect_object("clicked", gtk.mainquit, window)
56 vbox.pack_start(button, gtk.TRUE, gtk.TRUE, 0)
88
Captulo 9. Miscelanea de Controles
57 button.set_flags(gtk.CAN_DEFAULT)
58 button.grab_default()
59 button.show()
60 window.show()
61
62 def main():
63 gtk.main()
64 return 0
65
66 if __name__ == "__main__":
67 EntryExample()
68 main()
9.10. Botones Aumentar/Disminuir
El control SpinButton (Botn Aumentar/ Disminuir) se usa generalmente para permitir al usuario seleccionar
un valor dentro de un rango de valores numricos. Consiste en una caja de entrada de texto con botones de echa
arriba y abajo a un lado. Seleccionando uno de los botones causa que el valor aumente o disminuya en el rango de
valores posibles. La caja de entrada tambin puede editarse directamente para introducir un valor especco.
El SpinButton permite que el valor tenga cero o ms cifras decimales y puede incrementarse/decrementarse en
pasos congurables. La accin de mantener pulsado uno de los botones opcionalmente provoca una aceleracin
en el cambio del valor correspondiente al tiempo que se mantenga presionado.
El SpinButton usa un objeto Adjustment (Ajuste) para almacenar la informacin del rango de valores que el
botn aumentar/disminuir puede tomar. Esto le hace un control muy til.
Recuerda que un control Adjustment (Ajuste) se crea con la siguiente funcin, que muestra la informacin que
almacena:
adjustment = gtk.Adjustment(value=0, lower=0, upper=0, step_incr=0, page_incr=0,

page_size=0)
Estos atributos de un Adjustment (Ajuste) se usan en el SpinButton de la siguiente manera:
value valor inicial para el Botn Aumentar/Disminuir
lower el valor ms bajo del rango
upper el valor ms alto del rango
step_increment valor que se incrementa/decrementa cuando se pulsa el botn-1 del ratn en un
botn
page_increment valor que se incrementa/decrementa cuando se pulsa el botn-2 del ratn en un
botn
page_size no se usa
Adicionalmente, el botn del ratn botn-3 se puede usar para saltar directamente a los valores upper (superior) y
lower (inferior) cuando se usa para seleccionar uno de los botones. Veamos como crear un SpinButton (Botn
Aumentar/Disminuir):
spin_button = gtk.SpinButton(adjustment=None, climb_rate=0.0, digits=0)
El argumento climb_rate (razn de escalada) puede tomar un valor entre 0.0 y 1.0 e indica la cantidad de
aceleracin que el SpinButton tiene. El argumento digits especica el nmero de cifras decimales que se
mostrarn.
89
Captulo 9. Miscelanea de Controles
Un SpinButton se puede recongurar despus de su creacin usando el siguiente mtodo:
spin_button.configure(adjustment, climb_rate, digits)
La variable spin_button especica el botn aumentar/disminuir que se va a recongurar. Los otros argumentos
son los mismos que antes.
El adjustment (ajuste) se puede jar y recupar independientemente usando los siguientes dos mtodos:
spin_button.set_adjustment(adjustment)
adjustment = spin_button.get_adjustment()
El nmero de cifras decimales tambin se puede cambiar usando:
spin_button.set_digits(digits)
El valor que un SpinButton esta mostrando actualmente se puede cambiar usando el siguiente mtodo:
spin_button.set_value(value)
El valor actual de un SpinButton se puede recuperar como un valor real o como un valor entero usando los
siguientes mtodos:
float_value = spin_button.get_value()
int_value = spin_button.get_value_as_int()
Si quieres alterar el valor de un SpinButton relativo a su valor actual, entonces usa el siguiente mtodo:
spin_button.spin(direction, increment)
El parmetro direction (direccin) puede tomar uno de los siguientes valores:
SPIN_STEP_FORWARD # paso hacia adelante
SPIN_STEP_BACKWARD # paso hacia atrs
SPIN_PAGE_FORWARD # pgina hacia adelante
SPIN_PAGE_BACKWARD # pgina hacia atrs
SPIN_HOME # inicio
SPIN_END # fin
SPIN_USER_DEFINED # definido por el usuario
Este mtodo comprime bastante funcionalidad, que intentar explicar ahora. Muchos de estos parmetros usan
valores del objeto Adjustment (Ajuste) que est asociado con un SpinButton (Botn Aumentar/Disminuir).
90
Captulo 9. Miscelanea de Controles
SPIN_STEP_FORWARD (paso adelante) y SPIN_STEP_BACKWARD (paso atrs) cambian el valor del
SpinButton con una cantidad especicada por el increment (incremento), a menos que increment (in-
cremento) sea igual a 0, en cuyo caso el valor se modica con el step_increment (incremento de paso) del
Adjustment.
SPIN_PAGE_FORWARD (pgina adelante) y SPIN_PAGE_BACKWARD (pgina atrs) simplemente alteran el
valor del SpinButton por increment (incremento).
SPIN_HOME (inicio) pone el valor del SpinButton a la parte de abajo del rango del Adjustment .
SPIN_END (n) ja el valor del SpinButton a la parte de arriba del rango del Adjustment .
SPIN_USER_DEFINED (denido por el usuario) simplemente modica el valor del SpinButton con la cantidad
especicada.
Ahora nos alejamos de los mtodos para jar y recuperar los atributos del rango de un SpinButton , y nos
centramos en los mtodos que modican la apariencia y comportamiento de un control SpinButton propiamente.
El primero de estos mtodos se usa para limitar la caja de texto del SpinButton para que solo contenga un valor
numrico. Esto evita que el usuario escriba cualquier otra cosa que no sea un valor numrico dentro de la caja de
texto de un SpinButton:
spin_button.set_numeric(numeric)
El argumento numeric es TRUE para limitar la caja de texto a valores numricos o FALSE para quitar esta
limitacin.
Puedes jar si quieres que el valor del SpinButton se quede en los valores inferior y superior del rango con el
siguiente mtodo:
spin_button.set_wrap(wrap)
El SpinButton limitar los valores dentro del rango si wrap es TRUE.
Puedes hacer que el SpinButton redondee el valor al step_increment (incremento) ms cercano, lo cual se
ja dentro del objeto Adjustment usado en el SpinButton. Esto se consigue con el siguiente mtodo cuando el
argumento snap_to_ticks es TRUE:
spin_button.set_snap_to_ticks(snap_to_ticks)
La poltica de actualizacin de un SpinButton se cambia con el siguiente mtodo:
spin_button.set_update_policy(policy)
Los valores posibles de esta poltica son:
UPDATE_ALWAYS # actualizar siempre
91
Captulo 9. Miscelanea de Controles
UPDATE_IF_VALID # actualizar si es vlido
Estas polticas afectan el comportamiento de un SpinButton cuando analiza el texto insertado y sincroniza su
valor con los valores del Adjustment.
En el caso de UPDATE_IF_VALID (actualizar si es vlido) el valor del SpinButton slo cambia si el texto es
un valor numrico que est dentro del rango especicado por el Adjustment. En cualquier otro caso el texto se
resetea al valor actual.
En el caso de UPDATE_ALWAYS (actualizar siempre) se ignoran los errores de conversin al pasar el texto a un
valor numrico.
Finalmente, puedes especicar una actualizacin por ti mismo SpinButton :
spin_button.update()
El programa de ejemplo spinbutton.py [examples/spinbutton.py] muestra el uso de botones de aumen-
tar/disminuir incluyendo el uso de un nmero de caractersticas. La gura Figura 9.11. Ejemplo de Botn
Aumentar/Disminuir muestra el resultado de ejecutar el programa de ejemplo:
Figura 9.11. Ejemplo de Botn Aumentar/Disminuir
92
Captulo 9. Miscelanea de Controles
El cdigo fuente spinbutton.py [examples/spinbutton.py] es:
1 #!/usr/bin/env python
2
3 # example spinbutton.py
4
5 import gtk
6
7 class SpinButtonExample:
8 def toggle_snap(self, widget, spin):
9 spin.set_snap_to_ticks(widget.get_active())
10
11 def toggle_numeric(self, widget, spin):
12 spin.set_numeric(widget.get_active())
13
14 def change_digits(self, widget, spin, spin1):
15 spin1.set_digits(spin.get_value_as_int())
16
17 def get_value(self, widget, data, spin, spin2, label):
18 if data == 1:
19 buf = "%d" % spin.get_value_as_int()
20 else:
21 buf = "%0.*f" % (spin2.get_value_as_int(),
22 spin.get_value())
23 label.set_text(buf)
24
25 def __init__(self):
26 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
27 window.connect("destroy", gtk.mainquit)
28 window.set_title("Spin Button")
29
30 main_vbox = gtk.VBox(gtk.FALSE, 5)
31 main_vbox.set_border_width(10)
32 window.add(main_vbox)
33
34 frame = gtk.Frame("Not accelerated")
35 main_vbox.pack_start(frame, gtk.TRUE, gtk.TRUE, 0)
36
37 vbox = gtk.VBox(gtk.FALSE, 0)
38 vbox.set_border_width(5)
39 frame.add(vbox)
40
41 # Day, month, year spinners
42 hbox = gtk.HBox(gtk.FALSE, 0)
43 vbox.pack_start(hbox, gtk.TRUE, gtk.TRUE, 5)
44
45 vbox2 = gtk.VBox(gtk.FALSE, 0)
46 hbox.pack_start(vbox2, gtk.TRUE, gtk.TRUE, 5)
47
48 label = gtk.Label("Day :")
49 label.set_alignment(0, 0.5)
50 vbox2.pack_start(label, gtk.FALSE, gtk.TRUE, 0)
51
52 adj = gtk.Adjustment(1.0, 1.0, 31.0, 1.0, 5.0, 0.0)
53 spinner = gtk.SpinButton(adj, 0, 0)
54 spinner.set_wrap(gtk.TRUE)
55 vbox2.pack_start(spinner, gtk.FALSE, gtk.TRUE, 0)
56
93
Captulo 9. Miscelanea de Controles
57 vbox2 = gtk.VBox(gtk.FALSE, 0)
58 hbox.pack_start(vbox2, gtk.TRUE, gtk.TRUE, 5)
59
60 label = gtk.Label("Month :")
61 label.set_alignment(0, 0.5)
62 vbox2.pack_start(label, gtk.FALSE, gtk.TRUE, 0)
63
64 adj = gtk.Adjustment(1.0, 1.0, 12.0, 1.0, 5.0, 0.0)
65 spinner = gtk.SpinButton(adj, 0, 0)
66 spinner.set_wrap(gtk.TRUE)
67 vbox2.pack_start(spinner, gtk.FALSE, gtk.TRUE, 0)
68
69 vbox2 = gtk.VBox(gtk.FALSE, 0)
70 hbox.pack_start(vbox2, gtk.TRUE, gtk.TRUE, 5)
71
72 label = gtk.Label("Year :")
73 label.set_alignment(0, 0.5)
74 vbox2.pack_start(label, gtk.FALSE, gtk.TRUE, 0)
75
76 adj = gtk.Adjustment(1998.0, 0.0, 2100.0, 1.0, 100.0, 0.0)
77 spinner = gtk.SpinButton(adj, 0, 0)
78 spinner.set_wrap(gtk.FALSE)
79 spinner.set_size_request(55, -1)
80 vbox2.pack_start(spinner, gtk.FALSE, gtk.TRUE, 0)
81
82 frame = gtk.Frame("Accelerated")
83 main_vbox.pack_start(frame, gtk.TRUE, gtk.TRUE, 0)
84
85 vbox = gtk.VBox(gtk.FALSE, 0)
86 vbox.set_border_width(5)
87 frame.add(vbox)
88
89 hbox = gtk.HBox(gtk.FALSE, 0)
90 vbox.pack_start(hbox, gtk.FALSE, gtk.TRUE, 5)
91
92 vbox2 = gtk.VBox(gtk.FALSE, 0)
93 hbox.pack_start(vbox2, gtk.TRUE, gtk.TRUE, 5)
94
95 label = gtk.Label("Value :")
96 label.set_alignment(0, 0.5)
97 vbox2.pack_start(label, gtk.FALSE, gtk.TRUE, 0)
98
99 adj = gtk.Adjustment(0.0, -10000.0, 10000.0, 0.5, 100.0, 0.0)
100 spinner1 = gtk.SpinButton(adj, 1.0, 2)
101 spinner1.set_wrap(gtk.TRUE)
102 spinner1.set_size_request(100, -1)
103 vbox2.pack_start(spinner1, gtk.FALSE, gtk.TRUE, 0)
104
105 vbox2 = gtk.VBox(gtk.FALSE, 0)
106 hbox.pack_start(vbox2, gtk.TRUE, gtk.TRUE, 5)
107
108 label = gtk.Label("Digits :")
109 label.set_alignment(0, 0.5)
110 vbox2.pack_start(label, gtk.FALSE, gtk.TRUE, 0)
111
112 adj = gtk.Adjustment(2, 1, 5, 1, 1, 0)
113 spinner2 = gtk.SpinButton(adj, 0.0, 0)
114 spinner2.set_wrap(gtk.TRUE)
115 adj.connect("value_changed", self.change_digits, spinner2, spinner1)
94
Captulo 9. Miscelanea de Controles
116 vbox2.pack_start(spinner2, gtk.FALSE, gtk.TRUE, 0)
117
118 hbox = gtk.HBox(gtk.FALSE, 0)
119 vbox.pack_start(hbox, gtk.FALSE, gtk.TRUE, 5)
120
121 button = gtk.CheckButton("Snap to 0.5-ticks")
122 button.connect("clicked", self.toggle_snap, spinner1)
123 vbox.pack_start(button, gtk.TRUE, gtk.TRUE, 0)
124 button.set_active(gtk.TRUE)
125
126 button = gtk.CheckButton("Numeric only input mode")
127 button.connect("clicked", self.toggle_numeric, spinner1)
128 vbox.pack_start(button, gtk.TRUE, gtk.TRUE, 0)
129 button.set_active(gtk.TRUE)
130
131 val_label = gtk.Label("")
132
133 hbox = gtk.HBox(gtk.FALSE, 0)
134 vbox.pack_start(hbox, gtk.FALSE, gtk.TRUE, 5)
135 button = gtk.Button("Value as Int")
136 button.connect("clicked", self.get_value, 1, spinner1, spinner2,
137 val_label)
138 hbox.pack_start(button, gtk.TRUE, gtk.TRUE, 5)
139
140 button = gtk.Button("Value as Float")
141 button.connect("clicked", self.get_value, 2, spinner1, spinner2,
142 val_label)
143 hbox.pack_start(button, gtk.TRUE, gtk.TRUE, 5)
144
145 vbox.pack_start(val_label, gtk.TRUE, gtk.TRUE, 0)
146 val_label.set_text("0")
147
148 hbox = gtk.HBox(gtk.FALSE, 0)
149 main_vbox.pack_start(hbox, gtk.FALSE, gtk.TRUE, 0)
150
151 button = gtk.Button("Close")
152 button.connect("clicked", gtk.mainquit)
153 hbox.pack_start(button, gtk.TRUE, gtk.TRUE, 5)
154 window.show_all()
155
156 def main():
157 gtk.main()
158 return 0
159
160 if __name__ == "__main__":
161 SpinButtonExample()
162 main()
9.11. Lista Desplegable
La lista desplegable es otro control bastante simple que es realmente una coleccin de otros controles. Desde el
punto de vista del usuario, el control consiste en una caja de entrada de texto y un men desplegable desde el que
el usuario puede seleccionar una entrada a partir de un conjunto predenido. Alternativamente, el usuario puede
escribir una opcin diferente directamente en la caja de texto.
El Combo tiene dos partes principales de las que te tienes que preocupar: una entry (entrada) y una list (lista).
Puedes acceder a ellas usando los atributos:
95
Captulo 9. Miscelanea de Controles
combo.entry
combo.list
Lo primero, para crear una lista desplegable, usa:
combo = gtk.Combo()
Ahora, si quieres jar la cadena en la seccin de la entrada de la lista desplegable, esto se hace manipulando el
control entrada directamente:
combo.entry.set_text(text)
Para jar los valores de la lista desplegable, uno usa el mtodo:
combo.set_popdown_strings(strings)
Antes de que puedas hacer esto, tienes que componer una lista con las opciones que quieras.
Aqui tenemos el tpico cdigo para crear un conjunto de opciones:
slist = [ "String 1", "String 2", "String 3", "String 4" ]
combo.set_popdown_strings(slist)
En este punto ya tienes una lista desplegable funcionando. Hay unos cuantos aspectos de su comportamiento que
puedes cambiar. Esto se consigue con los mtodos:
combo.set_use_arrows(val)
combo.set_use_arrows_always(val)
combo.set_case_sensitive(val)
El mtodo set_use_arrows() permite al usuario cambiar el valor de la entrada usando las teclas de echa
arriba/abajo cuando val se pone a TRUE. Esto no despliega la lista, si no que sustituye el texto actual de la entrada
con la siguiente entrada de la lista (arriba o abajo, segn la combinacin de tecla indique). Esto se hace buscando
en la lista el elemento correspondiente al valor actual de la entrada y seleccionando el elemento anterior/siguiente
correspondiente. Normalmente en una entrada las teclas de echa se usan para cambiar el foco (tambin puedes
hacer esto usando el tabulador). Ten en cuenta que cuando el elemento actual es el ltimo de la lista y pulsas la
tecla echa abajo se cambia el foco (lo mismo ocurre cuando estas en el primer elemento y pulsas la tecla echa
arriba).
Si el valor actual de la entrada no est en la lista, el mtodo set_use_arrows() se desactiva.
96
Captulo 9. Miscelanea de Controles
El mtodo set_use_arrows_always() , cuando val es TRUE, tambin permite al usuario el uso de las teclas
de echa arriba/abajo para ciclar por las opciones de la lista desplegable, excepto que da la vuelta a los valores de
la lista, desactivando por completo el uso de las echas arriba y abajo para cambiar el foco.
El mtodo set_case_sensitive() dice si GTK busca o no las entradas de una forma sensible a maysculas.
Esto se usa cuando se le pide al control Combo que busque un valor de la lista usando la entrada actual de la caja
de texto. Este completado puede producirse de forma sensible o insensible a maysculas, dependiendo de lo que
le pasemos a este mtodo. El control Combo tambin puede simplemente completar la entrada actual si el usuario
pulsa la combinacin de teclas MOD-1-Tab. MOD-1 normalmente corresponde a la tecla Alt, gracias a la utilidad
xmodmap. Ten en cuenta, sin embargo, que algunos manejadores de ventana tambin usan esta combinacin de
teclas, lo que inutilizar su uso en GTK.
Ahora que tenemos una lista desplegable, y que tiene la apariencia y el comportamiento que queremos, lo nico
que nos falta es la capacidad de obtener los datos de la lista desplegable. Esto es relativamente directo. La mayora
del tiempo, de lo nico que te tienes que preocupar es de obtener los datos de la entrada. La entrada es accesible
simplemente como combo.entry. Las dos cosas fundamentales que vas a querer hacer con ella es conectarle la
seal "activate", que indica que el usuario ha pulsado la tecla Return o la tecla Enter, y leer el texto. Lo primero
se consigue usando algo como:
combo.entry.connect("activate", my_callback, my_data)
Obtener el texto en cualquier momento se consigue simplemente usando el siguiente mtodo:
string = combo.entry.get_text()
Eso es todo lo importante. Hay un mtodo:
combo.disable_activate()
que desactivar la seal "activate" en el control de entrada de la lista desplegable. Personalmente, no se me ocurre
ninguna situacin en la que quieras usarlo, pero existe.
9.12. Calendario
El control Calendar (Calendario) es una forma efectiva para visualizar y obtener informacin relativa a fechas
mensuales. Es un control muy fcil de usar y trabajar con l.
Crear un control GtkCalendar es tan simple como:
calendar = gtk.Calendar()
El calendario mostrar el mes y el ao actual de manera predeterminada.
Puede haber ocasiones en las que necesites cambiar mucha informacin dentro de este control y los siguientes
mtodos te permitirn realizar mltiples cambios al control Calendar sin que el usuario vea muchos cambios en
pantalla.
calendar.freeze() # congelar
97
Captulo 9. Miscelanea de Controles
calendar.thaw() # reanudar
Funcionan exactamente igual que los mtodos freeze/thaw de cualquier otro control.
El control Calendar tiene unas cuantas opciones que te permiten cambiar la manera en la que el control se
visualiza y se comporta usando el mtodo:
calendar.display_options(flags)
El argumento flags (banderas) se puede formar combinando cualquiera de las siguientes cinco opciones usando
el operador lgico (|):
CALENDAR_SHOW_HEADING esta opcin especica que el mes y el ao deben mostrarse cuando se
dibuje el calendario.
CALENDAR_SHOW_DAY_NAMES esta opcin especica que la descripcin de tres letras para cada da (Lun,
Mar, etc.) debe mostrarse.
CALENDAR_NO_MONTH_CHANGE esta opcin dice que el usuario no podr cambiar el mes que se muestra.
Esto puede ser bueno si slo necesitas mostrar un mes en particular como
cuando muestras 12 controles de calendario uno para cada mes dentro de
un mes en particular.
CALENDAR_SHOW_WEEK_NUMBERS esta opcin especica que se muestre el nmero de cada semana en la
parte de abajo izquierda del calendario (ejemplo: Enero 1 = Semana 1,
Diciembre 31 = Semana 52).
CALENDAR_WEEK_START_MONDAY esta opcin dice que la semana empezar en Lunes en lugar de en
Domingo, que es el valor predeterminado. Esto solo afecta al orden en el
que se muestran los das de izquierda a derecha.
Los siguientes mtodos se usan para jar la fecha que se muestra:
result = calendar.select_month(month, year)
calendar.select_day(day)
El valor que devuelve el mtodo select_month() es un valor booleano que indica si la seleccin tuvo xito.
Con el mtodo select_day() el da especicado se selecciona dentro del mes actual, si eso es posible. Un valor
para el da de 0 limpiar la seleccin actual.
Adems de tener un da seleccionado, un nmero arbitrario de das se pueden "marcar". Un da marcado se destaca
en el calendario. Los siguientes mtodos se proporcionan para manipular das marcados:
result = calendar.mark_day(day)
result = calendar.unmark_day(day)
calendar.clear_marks()
mark_day() y unmark_day() devuelven un valor booleano que indica si el mtodo tuvo xito. Fjate que las
marcas son persistentes entre cambios de meses y aos.
98
Captulo 9. Miscelanea de Controles
El ltimo mtodo del control Calendar se usa para obtener la fecha seleccionada, mes y/o ao.
ao, mes, da = calendar.get_date()
El control Calendar puede generar varias seales que indican la seleccin y cambio de la fecha. Los nombres de
estas seales son autoexplicativos, y son:
month_changed # cambio de mes
day_selected # da seleccionado
day_selected_double_click # doble clic en da seleccionado
prev_month # mes anterior
next_month # mes siguiente
prev_year # ao anterior
next_year # ao siguiente
Esto nos deja con la necesidad de poner todo esto junto en el programa de ejemplo calendar.py [exam-
ples/calendar.py] . La gura Figura 9.12. Ejemplo de Calendario muestra el resultado del programa:
99
Captulo 9. Miscelanea de Controles
Figura 9.12. Ejemplo de Calendario
El cdigo fuente es calendar.py [examples/calendar.py]:
1 #!/usr/bin/env python
2
3 # example calendar.py
4 #
5 # Copyright (C) 1998 Cesar Miquel, Shawn T. Amundson, Mattias Gronlund
6 # Copyright (C) 2000 Tony Gale
7 # Copyright (C) 2001-2002 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.
100
Captulo 9. Miscelanea de Controles
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 gtk, pango
24 import time
25
26 class CalendarExample:
27 DEF_PAD = 10
28 DEF_PAD_SMALL = 5
29 TM_YEAR_BASE = 1900
30
31 calendar_show_header = 0
32 calendar_show_days = 1
33 calendar_month_change = 2
34 calendar_show_week = 3
35 calendar_monday_first = 4
36
37 def calendar_date_to_string(self):
38 year, month, day = self.window.get_date()
39 mytime = time.mktime((year, month+1, day, 0, 0, 0, 0, 0, 0))
40 return time.strftime("%x", time.gmtime(mytime))
41
42 def calendar_set_signal_strings(self, sig_str):
43 prev_sig = self.prev_sig.get()
44 self.prev2_sig.set_text(prev_sig)
45
46 prev_sig = self.last_sig.get()
47 self.prev_sig.set_text(prev_sig)
48 self.last_sig.set_text(sig_str)
49
50 def calendar_month_changed(self, widget):
51 buffer = "month_changed: %s" % self.calendar_date_to_string()
52 self.calendar_set_signal_strings(buffer)
53
54 def calendar_day_selected(self, widget):
55 buffer = "day_selected: %s" % self.calendar_date_to_string()
56 self.calendar_set_signal_strings(buffer)
57
58 def calendar_day_selected_double_click(self, widget):
59 buffer = "day_selected_double_click: %s"
60 buffer = buffer % self.calendar_date_to_string()
61 self.calendar_set_signal_strings(buffer)
62
63 year, month, day = self.window.get_date()
64
65 if self.marked_date[day-1] == 0:
66 self.window.mark_day(day)
67 self.marked_date[day-1] = 1
68 else:
69 self.window.unmark_day(day)
70 self.marked_date[day-1] = 0
71
72 def calendar_prev_month(self, widget):
73 buffer = "prev_month: %s" % self.calendar_date_to_string()
74 self.calendar_set_signal_strings(buffer)
75
76 def calendar_next_month(self, widget):
101
Captulo 9. Miscelanea de Controles
77 buffer = "next_month: %s" % self.calendar_date_to_string()
78 self.calendar_set_signal_strings(buffer)
79
80 def calendar_prev_year(self, widget):
81 buffer = "prev_year: %s" % self.calendar_date_to_string()
82 self.calendar_set_signal_strings(buffer)
83
84 def calendar_next_year(self, widget):
85 buffer = "next_year: %s" % self.calendar_date_to_string()
86 self.calendar_set_signal_strings(buffer)
87
88 def calendar_set_flags(self):
89 options = 0
90 for i in range(5):
91 if self.settings[i]:
92 options = options + (1<<i)
93 if self.window:
94 self.window.display_options(options)
95
96 def calendar_toggle_flag(self, toggle):
97 j = 0
98 for i in range(5):
99 if self.flag_checkboxes[i] == toggle:
100 j = i
101
102 self.settings[j] = not self.settings[j]
103 self.calendar_set_flags()
104
105 def calendar_font_selection_ok(self, button):
106 self.font = self.font_dialog.get_font_name()
107 if self.window:
108 font_desc = pango.FontDescription(self.font)
109 if font_desc:
110 self.window.modify_font(font_desc)
111
112 def calendar_select_font(self, button):
113 if not self.font_dialog:
114 window = gtk.FontSelectionDialog("Font Selection Dialog")
115 self.font_dialog = window
116
117 window.set_position(gtk.WIN_POS_MOUSE)
118
119 window.connect("destroy", self.font_dialog_destroyed)
120
121 window.ok_button.connect("clicked",
122 self.calendar_font_selection_ok)
123 window.cancel_button.connect_object("clicked",
124 lambda wid: wid.destroy(),
125 self.font_dialog)
126 window = self.font_dialog
127 if not (window.flags() & gtk.VISIBLE):
128 window.show()
129 else:
130 window.destroy()
131 self.font_dialog = None
132
133 def font_dialog_destroyed(self, data=None):
134 self.font_dialog = None
135
102
Captulo 9. Miscelanea de Controles
136 def __init__(self):
137 flags = [
138 "Show Heading",
139 "Show Day Names",
140 "No Month Change",
141 "Show Week Numbers",
142 "Week Start Monday"
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", gtk.mainquit)
155
156 window.set_resizable(gtk.FALSE)
157
158 vbox = gtk.VBox(gtk.FALSE, self.DEF_PAD)
159 window.add(vbox)
160
161 # The top part of the window, Calendar, flags and fontsel.
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 # Calendar widget
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 # Build the Right frame with the flags in
194 frame = gtk.Frame("Flags")
103
Captulo 9. Miscelanea de Controles
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(5):
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 # Build the right font-button
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 # Build the Signal-event part.
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", gtk.mainquit)
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
104
Captulo 9. Miscelanea de Controles
254 if __name__ == "__main__":
255 CalendarExample()
256 main()
9.13. Seleccin de Color
El control de seleccin de color es, como cabe de esperar, un control para seleccionar colores interactivamente.
Este control compuesto permite al usuario seleccionar un color manipulando triples RGB (Rojo, Verde, Azul)
y HSV (Tono, Saturacin, Valor). Esto se consigue ajustando valores simples con deslizadores o entradas, o
haciendo clic en el color deseado en una rueda de tono-saturacin y una barra de valor. Opcionalmente, la opacidad
del color tambin se puede especicar.
El control de seleccin de color solo emite una seal por ahora, "color_changed", que se emite siempre que el
color actual del control cambie, bien porque el usuario lo cambia o porque se especique explcitamente a travs
del mtodo set_color() .
Veamos lo que nos ofrece el control de seleccin de color. El control viene en dos sabores: GtkColorSelection
y GtkColorSelectionDialog.
colorsel = gtk.ColorSelection()
Probablemente no uses este constructor directamente. Crea un control ColorSelection huerfano que tendrs
que apadrinar tu mismo. El control ColorSelection hereda del control VBox .
colorseldlg = gtk.ColorSelectionDialog(title)
donde title (ttulo) es una cadena usada para la barra de ttulo del dilogo.
Este es el constructor ms comn del selector de color. Crea un ColorSelectionDialog. Este consiste en
un Frame que contiene un control ColorSelection , un HSeparator y un HBox con tres botones, "Ok",
"Cancelar" y "Ayuda". Puedes obtener estos botones accediendo a los atributos ok_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 mtodos que cambian sus caractersticas o proporcionan acceso
a la seleccin de color.
colorsel.set_has_opacity_control(has_opacity)
El control de seleccin de color permite ajustar la opacidad de un color (tambin conocida como el canal alfa).
Esto esta desactivado por defecto. Llamando a este mtodo con has_opacity igual TRUE activa la opacidad.
De la misma forma, has_opacity igual a FALSE desactivar la opacidad.
colorsel.set_current_color(color)
105
Captulo 9. Miscelanea de Controles
colorsel.set_current_alpha(alpha)
Puedes poner el color actual explcitamente llamando al mtodo set_current_color() con un GdkColor.
La opacidad (canal alfa) se pone con el mtodo set_current_alpha().El canal alfa debe estar entre 0
(completamente transparente) y 65636 (completamente opaco).
color = colorsel.get_current_color()
alpha = colorsel.get_current_alpha()
Cuando tengas que mirar el color actual, tpicamente al recibir la seal "color_changed", puedes usar estos
mtodos.
El programa de ejemplo colorsel.py [examples/colorsel.py] demuestra el uso del ColorSelectionDialog. Este
programa muestra una ventana que contiene un rea de dibujo. Al hacer clic en ella se abre un dilogo de seleccin
de color, y cambiando el color en dicho dilogo se cambia el color de fondo. La gura Figura 9.13. Ejemplo de
Dilogo de Seleccin de Color muestra el programa en accin:
Figura 9.13. Ejemplo de Dilogo de Seleccin de Color
106
Captulo 9. Miscelanea de Controles
El cdigo fuente de colorsel.py [examples/colorsel.py] es:
1 #!/usr/bin/env python
2
3 # example colorsel.py
4
5 import gtk
6
7 class ColorSelectionExample:
8 # Color changed handler
9 def color_changed_cb(self, widget):
10 # Get drawingarea colormap
11 colormap = self.drawingarea.get_colormap()
12
13 # Get current color
14 color = self.colorseldlg.colorsel.get_current_color()
15
16 # Set window background color
17 self.drawingarea.modify_bg(gtk.STATE_NORMAL, color)
18
19 # Drawingarea event handler
20 def area_event(self, widget, event):
21 handled = gtk.FALSE
22
23 # Check if weve received a button pressed event
24 if event.type == gtk.gdk.BUTTON_PRESS:
25 handled = gtk.TRUE
26
27 # Create color selection dialog
28 if self.colorseldlg == None:
29 self.colorseldlg = gtk.ColorSelectionDialog(
30 "Select background color")
31
32 # Get the ColorSelection widget
33 colorsel = self.colorseldlg.colorsel
34
35 colorsel.set_previous_color(self.color)
36 colorsel.set_current_color(self.color)
37 colorsel.set_has_palette(gtk.TRUE)
38
39 # Connect to the "color_changed" signal
40 colorsel.connect("color_changed", self.color_changed_cb)
41 # Show the dialog
42 response = self.colorseldlg.run()
43
44 if response -- gtk.RESPONSE_OK:
45 self.color = colorsel.get_current_color()
46 else:
47 self.drawingarea.modify_bg(gtk.STATE_NORMAL, self.color)
48
49 self.colorseldlg.hide()
50
51 return handled
52
53 # Close down and exit handler
54 def destroy_window(self, widget, event):
55 gtk.mainquit()
56 return gtk.TRUE
107
Captulo 9. Miscelanea de Controles
57
58 def __init__(self):
59 self.colorseldlg = None
60 # Create toplevel window, set title and policies
61 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
62 window.set_title("Color selection test")
63 window.set_resizable(gtk.TRUE)
64
65 # Attach to the "delete" and "destroy" events so we can exit
66 window.connect("delete_event", self.destroy_window)
67
68 # Create drawingarea, set size and catch button events
69 self.drawingarea = gtk.DrawingArea()
70
71 self.color = self.drawingarea.get_colormap().alloc_color(0, 65535, 0)
72
73 self.drawingarea.set_size_request(200, 200)
74 self.drawingarea.set_events(gtk.gdk.BUTTON_PRESS_MASK)
75 self.drawingarea.connect("event", self.area_event)
76
77 # Add drawingarea to window, then show them both
78 window.add(self.drawingarea)
79 self.drawingarea.show()
80 window.show()
81
82 def main():
83 gtk.main()
84 return 0
85
86 if __name__ == "__main__":
87 ColorSelectionExample()
88 main()
9.14. Selectores de Fichero
El control de seleccin de chero es una forma rpida y fcil de mostrar una caja de dilogo de Fichero. Viene
con botones Ok, Cancelar y Ayuda, por lo que es estupendo para ahorrase tiempo de programacin.
Para crear una nueva caja de seleccin de chero usa:
filesel = gtk.FileSelection(title=None)
Para jar el nombre de chero, por ejemplo para mostrar un directorio especco, o establecer un chero
predeterminado, usa este mtodo:
filesel.set_filename(filename)
Para obtener el nombre de chero que el usuario ha escrito o seleccionado, usa este mtodo:
filename = filesel.get_filename()
108
Captulo 9. Miscelanea de Controles
Tambin hay referencias a los controles contenidos en el control de seleccin de cheros. Estos son los atributos:
filesel.dir_list # lista de directorios
filesel.file_list # lista de ficheros
filesel.selection_entry # entrada de seleccin
filesel.selection_text # texto de seleccin
filesel.main_vbox # caja vertical principal
filesel.ok_button # botn ok
filesel.cancel_button # botn cancelar
filesel.help_button # botn ayuda
filesel.history_pulldown # lista de historia
filesel.history_menu # men de historia
filesel.fileop_dialog
filesel.fileop_entry
filesel.fileop_file
filesel.fileop_c_dir
filesel.fileop_del_file
filesel.fileop_ren_file
filesel.button_area # rea de botones
filesel.action_area # rea de accin
Lo ms probable es que quieras usar los atributos ok_button, cancel_button, y help_button para conectar
sus seales a tus retrollamadas.
El programa de ejemplo lesel.py [examples/lesel.py] ilustra el uso del control de seleccin de cheros. Como
vers, no hay mucho ms que decir para crear un control de seleccin de cheros. Aunque en este ejemplo el
botn Ayuda aparece en pantalla, no hace nada porque no hay ninguna seal conectada a l. La gura Figura 9.14.
Ejemplo de Seleccin de Ficheros muestra la pantalla resultante:
109
Captulo 9. Miscelanea de Controles
Figura 9.14. Ejemplo de Seleccin de Ficheros
El cdigo fuente de lesel.py es:
1 #!/usr/bin/env python
2
3 # example filesel.py
4
5 import gtk
6
7 class FileSelectionExample:
8 # Get the selected filename and print it to the console
9 def file_ok_sel(self, w):
10 print "%s" % self.filew.get_filename()
11
12 def destroy(self, widget):
13 gtk.mainquit()
14
15 def __init__(self):
16 # Create a new file selection widget
17 self.filew = gtk.FileSelection("File selection")
18
110
Captulo 9. Miscelanea de Controles
19 self.filew.connect("destroy", self.destroy)
20 # Connect the ok_button to file_ok_sel method
21 self.filew.ok_button.connect("clicked", self.file_ok_sel)
22
23 # Connect the cancel_button to destroy the widget
24 self.filew.cancel_button.connect("clicked",
25 lambda w: self.filew.destroy())
26
27 # Lets set the filename, as if this were a save dialog,
28 # and we are giving a default filename
29 self.filew.set_filename("penguin.png")
30
31 self.filew.show()
32
33 def main():
34 gtk.main()
35 return 0
36
37 if __name__ == "__main__":
38 FileSelectionExample()
39 main()
9.15. Dilogo de Seleccin de Fuentes
El Dilogo de Seleccin de Fuentes permite al usuario seleccionar una fuente de forma interactiva. El dilogo
contiene un control FontSelection y botones de "OK y "Cancelar". Un botn de Aplicar tambin est
disponible en el dilogo, pero inicialmente est oculto. El Dilogo de Seleccin de Fuentes permite al usuario
seleccionar una fuente de las fuentes de sistema disponibles (las mismas que se obtienen al usarxlsfonts)).
La gura Figura 9.15. Dilogo de Seleccin de Fuentes ilustra un FontSelectionDialog :
111
Captulo 9. Miscelanea de Controles
Figura 9.15. Dilogo de Seleccin de Fuentes
El dilogo contiene un conjunto de tres chas que proporcionan:
un interface para seleccionar la fuente, el estilo y el tamao
informacin detallada sobre la fuente seleccionada
un interfaz para el mecanismo de ltrado de fuente que restringe las fuentes disponibles para seleccionar
La funcin para crear un FontSelectionDialog es:
fontseldlg = gtk.FontSelectionDialog(title)
El title (ttulo) es una cadena que se usar en el texto de la barra de ttulo.
Una instancia de un Dilogo de Seleccin de Fuentes tiene varios atributos:
fontsel
main_vbox
action_area
ok_button
apply_button
112
Captulo 9. Miscelanea de Controles
cancel_button
El atributo fontsel es una referencia al control de seleccin de fuente. main_vbox es una referencia a la
gtk.VBox que contiene el fontsel y el action_area en el dilogo. El atributo action_area es una referencia
a la gtk.HButtonBox que contiene los botones de OK, Aplicar y Cancelar. Los atributos ok_button,
cancel_button y apply_button son referencias a los botones OK, Cancelar y Aplicar que se pueden
usar para realizar las conexiones a las seales de los botones. La referencia apply_button tambin se puede
usar para mostrar el botn mediante el mtodo show() .
Puedes jar la fuente inicial que se mostrar en el dilogo usando el mtodo:
fontseldlg.set_font_name(fontname)
El argumento fontname es el nombre de una fuente de sistema completa o parcialmente especicado. Por
ejemplo:
fontseldlg.set_font_name(-adobe-courier-bold-*-*-*-*-120-*-*-*-*-*-*)
especica una fuente inicial parcialmente.
El nombre de la fuente seleccionada se puede obtener con el mtodo:
font_name = fontseldlg.get_font_name()
El Dilogo de Seleccin de Fuentes tiene un rea de previsualizacin que muestra texto usando la fuente
seleccionada. El texto que se usa en el rea de previsualizacin se puede establecer con el mtodo:
fontseldlg.set_preview_text(text)
El texto de previsualizacin se puede obtener con el mtodo:
text = fontseldlg.get_preview_text()
El programa de ejemplo calendar.py [examples/calendar.py] usa un dilogo de seleccin de fuentes para selec-
cionar la fuente que se usa para mostrar la informacin del calendario. Las lineas 105-110 denen una retrollamada
para obtener el nombre de la fuente a partir del Dilogo de Seleccin de Fuentes y lo usa para jar la fuente para
el control del calendario. Las lineas 112-131 denen el mtodo que crea un Dilogo de Seleccin de Fuentes,
congura las retrollamadas para los botones OK y Cancelar y muestra el dilogo.
113
Captulo 10. Controles Contenedores
10.1. La Caja de Eventos
Algunos controles GTK no tienen ventanas X asociadas, por lo que simplemente se dibujan encima de sus padres.
A causa de esto, no pueden recibir eventos y si se dimensionan incorrectamente, no pueden recortarse por lo que
puedes ver partes mal, etc. Si necesitas ms de estos controles, la EventBox (Caja de Eventos) es para ti.
A primera vista, el control EventBox puede aparecer completamente intil. No dibuja nada en la pantalla y no
responde a ningn evento. Sin embargo, tiene una funcin - proporciona una ventana X a sus controles hijos. Esto
es importante ya que muchos controles GTK no tienen una ventana X asociada. No tener una ventana X ahorra
memoria y mejora el rendimiento, pero tambin tiene inconvenientes. Un control sin ventana X no puede recibir
eventos, no realiza ningun recortado sobre sus contenidos y no puede establecer su color de fondo. Aunque el
nombre EventBox enfatiza la funcin de manejador de eventos, el control tambin se puede usar para recorte. (y
ms, mira el ejemplo ms abajo).
Para crear un nuevo control EventBox , usa:
event_box = gtk.EventBox()
Un control hijo se puede aadir a esta event_box:
event_box.add(widget)
El programa de ejemplo eventbox.py [examples/eventbox.py] muestra dos usos de un EventBox - una etiqueta
es creada y se recorta en una caja pequea, tiene un fondo verde y se ha congurado para que un clic de ratn en
la etiqueta haga que el programa termine. Al redimensionar la ventana se cambian cantidades en la etiqueta. La
gura Figura 10.1. Ejemplo de Caja de Eventos muestra la ventana del programa:
Figura 10.1. Ejemplo de Caja de Eventos
114
Captulo 10. Controles Contenedores
El cdigo fuente de eventbox.py [examples/eventbox.py] es:
1 #!/usr/bin/env python
2
3 # example eventbox.py
4
5 import gtk
6
7 class EventBoxExample:
8 def __init__(self):
9 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
10 window.set_title("Event Box")
11 window.connect("destroy", gtk.mainquit)
12 window.set_border_width(10)
13
14 # Create an EventBox and add it to our toplevel window
15 event_box = gtk.EventBox()
16 window.add(event_box)
17 event_box.show()
18
19 # Create a long label
20 label = gtk.Label("Click here to quit, quit, quit, quit, quit")
21 event_box.add(label)
22 label.show()
23
24 # Clip it short.
25 label.set_size_request(110, 20)
26
27 # And bind an action to it
28 event_box.set_events(gtk.gdk.BUTTON_PRESS_MASK)
29 event_box.connect("button_press_event", gtk.mainquit)
30
31 # More things you need an X window for ...
32 event_box.realize()
33 event_box.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.HAND1))
34
35 # Set background color to green
36 event_box.modify_bg(gtk.STATE_NORMAL,
37 event_box.get_colormap().alloc_color(green))
38
39 window.show()
40
41 def main():
42 gtk.main()
43 return 0
44
45 if __name__ == "__main__":
46 EventBoxExample()
47 main()
10.2. El control Alineador
El control Alignment (Alineador) te permite colocar un control dentro de su ventana en una posicin y un tamao
relativos al tamao del propio control Alignment . Por ejemplo, puede ser til para centrar un control dentro de
la ventana.
115
Captulo 10. Controles Contenedores
Slo hay dos llamadas asociadas al control Alignment :
alignment = gtk.Alignment(xalign=0.0, yalign=0.0, xscale=0.0, yscale=0.0)
alignment.set(xalign, yalign, xscale, yscale)
La funcin gtk.Alignment() crea un nuevo control Alignment con los parmetros especicados. El mtodo
set() permite alterar los parmetros de alineacin de un control Alignment existente.
Los cuatro parmetros son nmeros en coma otante que pueden estar entre 0.0 y 1.0. Los argumentos xalign y
yalign afectan a la posicin del control dentro del Alignment . Los argumentos xscale y yscale afectan a la
cantidad de espacio reservada al control.
Un control hijo puede aadirse a este Alignment usando:
alignment.add(widget)
Para un ejemplo del uso de un control Alignment, consulta el ejemplo del control de Barra de Progreso
progressbar.py [examples/progressbar.py]
10.3. Contenedor Fijo
El contenedor Fixed (Fijo) te permite colocar controles en una posicin ja dentro de su ventana, relativa a su
esquina superior izquierda. La posicin de los controles se puede cambiar dinmicamente.
Slo hay dos llamadas asociadas al control jo:
fixed = gtk.Fixed()
fixed.put(widget, x, y)
fixed.move(widget, x, y)
La funcin gtk.Fixed() te permite crear un nuevo contenedor Fixed .
El mtodo put() coloca al control en el contenedor jo en la posicin especicada por x e y.
El mtodo move() te permite mover el control especicado a una nueva posicin.
El ejemplo xed.py [examples/xed.py] ilustra cmo usar el contenedor Fixed . La gura Figura 10.2. Ejemplo
de Fijo muestra el resultado:
116
Captulo 10. Controles Contenedores
Figura 10.2. Ejemplo de Fijo
El cdigo fuente de xed.py [examples/xed.py] es:
1 #!/usr/bin/env python
2
3 # example fixed.py
4
5 import gtk
6
7 class FixedExample:
8 # This callback method moves the button to a new position
9 # in the Fixed container.
10 def move_button(self, widget):
11 self.x = (self.x+30)%300
12 self.y = (self.y+50)%300
13 self.fixed.move(widget, self.x, self.y)
14
15 def __init__(self):
16 self.x = 50
17 self.y = 50
18
19 # Create a new window
20 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
21 window.set_title("Fixed Container")
22
23 # Here we connect the "destroy" event to a signal handler
117
Captulo 10. Controles Contenedores
24 window.connect("destroy", gtk.mainquit)
25
26 # Sets the border width of the window.
27 window.set_border_width(10)
28
29 # Create a Fixed Container
30 self.fixed = gtk.Fixed()
31 window.add(self.fixed)
32 self.fixed.show()
33
34 for i in range(1, 4):
35 # Creates a new button with the label "Press me"
36 button = gtk.Button("Press me")
37
38 # When the button receives the "clicked" signal, it will call the
39 # method move_button().
40 button.connect("clicked", self.move_button)
41
42 # This packs the button into the fixed containers window.
43 self.fixed.put(button, i*50, i*50)
44
45 # The final step is to display this newly created widget.
46 button.show()
47
48 # Display the window
49 window.show()
50
51 def main():
52 # Enter the event loop
53 gtk.main()
54 return 0
55
56 if __name__ == "__main__":
57 FixedExample()
58 main()
10.4. Contenedor de Disposicin
El contenedor Layout (Disposicin) es similar al contenedor Fixed (Fijo) excepto en que implementa un rea
de desplazamiento innita (donde innito es menor que 2^32). El sistema de ventanas X tiene una limitacin que
hace uqe las ventanas slo puedan tener 32767 pxeles de ancho o alto. El contenedor Layout soluciona esta
limitacin haciendo algunos trucos exticos mediante el uso de gravedad de ventana y de bit, para que tengas un
desplazamiento suave incluso cuando tienes muchos controles en tu rea de desplazamiento.
Un contenedor Layout se crea con:
layout = gtk.Layout(hadjustment=None, vadjustment=None)
Como puedes ver, puedes especicar opcionalmente los objetos Adjustment que el control Layout usar para
su desplazamiento. Si no especicas los objetos Adjustment , unos nuevos se crearn.
Puedes aadir y mover controles en el contenedor Layout usando los dos siguientes mtodos:
layout.put(child_widget, x, y)
118
Captulo 10. Controles Contenedores
layout.move(child_widget, x, y)
El tamao del contenedor Layout se puede establecer y consultar usando los siguientes mtodos:
layout.set_size(width, height)
size = layout.get_size()
Los ltimos cuatro mtodos para los controles Layout widgets son para manipular los controles de ajuste
horizontal y vertical:
hadj = layout.get_hadjustment()
vadj = layout.get_vadjustment()
layout.set_hadjustment(adjustment)
layout.set_vadjustment(adjustment)
El programa de ejemplo layout.py [examples/layout.py] crea tres botones y los pone en un control disposicin.
Cuando se hace clic en un botn, se mueve a una posicin aleatoria en el control disposicin. La gura Figura
10.3. Ejemplo de Disposicin ilustra la ventana inicial del programa:
119
Captulo 10. Controles Contenedores
Figura 10.3. Ejemplo de Disposicin
El cdigo fuente de layout.py [examples/layout.py] es:
1 #!/usr/bin/env python
2
3 # example layout.py
4
5 import gtk
6 import whrandom
7
8 class LayoutExample:
9 def WindowDeleteEvent(self, widget, event):
10 # return false so that window will be destroyed
11 return gtk.FALSE
12
13 def WindowDestroy(self, widget, *data):
14 # exit main loop
15 gtk.mainquit()
16
17 def ButtonClicked(self, button):
18 # move the button
19 self.layout.move(button, whrandom.randint(0,500),
20 whrandom.randint(0,500))
21
22 def __init__(self):
23 # create the top level window
120
Captulo 10. Controles Contenedores
24 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
25 window.set_title("Layout Example")
26 window.set_default_size(300, 300)
27 window.connect("delete-event", self.WindowDeleteEvent)
28 window.connect("destroy", self.WindowDestroy)
29 # create the table and pack into the window
30 table = gtk.Table(2, 2, gtk.FALSE)
31 window.add(table)
32 # create the layout widget and pack into the table
33 self.layout = gtk.Layout(None, None)
34 self.layout.set_size(600, 600)
35 table.attach(self.layout, 0, 1, 0, 1, gtk.FILL|gtk.EXPAND,
36 gtk.FILL|gtk.EXPAND, 0, 0)
37 # create the scrollbars and pack into the table
38 vScrollbar = gtk.VScrollbar(None)
39 table.attach(vScrollbar, 1, 2, 0, 1, gtk.FILL|gtk.SHRINK,
40 gtk.FILL|gtk.SHRINK, 0, 0)
41 hScrollbar = gtk.HScrollbar(None)
42 table.attach(hScrollbar, 0, 1, 1, 2, gtk.FILL|gtk.SHRINK,
43 gtk.FILL|gtk.SHRINK, 0, 0)
44 # tell the scrollbars to use the layout widgets adjustments
45 vAdjust = self.layout.get_vadjustment()
46 vScrollbar.set_adjustment(vAdjust)
47 hAdjust = self.layout.get_hadjustment()
48 hScrollbar.set_adjustment(hAdjust)
49 # create 3 buttons and put them into the layout widget
50 button = gtk.Button("Press Me")
51 button.connect("clicked", self.ButtonClicked)
52 self.layout.put(button, 0, 0)
53 button = gtk.Button("Press Me")
54 button.connect("clicked", self.ButtonClicked)
55 self.layout.put(button, 100, 0)
56 button = gtk.Button("Press Me")
57 button.connect("clicked", self.ButtonClicked)
58 self.layout.put(button, 200, 0)
59 # show all the widgets
60 window.show_all()
61
62 def main():
63 # enter the main loop
64 gtk.main()
65 return 0
66
67 if __name__ == "__main__":
68 LayoutExample()
69 main()
10.5. Marcos
Los Marcos se pueden usar para encerrar un widget o un grupo de ellos dentro de una caja que, opcionalmente
puede llevar un ttulo. La posicin del ttulo y el estilo de la caja se puede alterar a tu gusto.
Un Frame (Marco) se puede crear con la siguiente funcin
frame = gtk.Frame(label=None)
121
Captulo 10. Controles Contenedores
El label (ttulo) se coloca en la esquina superior izquierda del marco de manera predeterminada. Especicando
un valor de None para el argumento label o sin especicar el argumento label har que no se visualice ningn
ttulo. El texto del ttulo se puede cambiar usando el mtodo:
frame.set_label(label)
La posicin del ttulo se puede cambiar usando el mtodo:
frame.set_label_align(xalign, yalign)
xalign y yalign toman valores entre 0.0 y 1.0. xalign indica la posicin del ttulo en la horizontal superior del
marco. yalign no se usa por ahora. El valor por defecto de xalign es 0.0 lo que coloca al ttulo en la esquina
izquierda del marco.
El siguiente mtodo modica el estilo de la caja que se usa para rodear el marco.
frame.set_shadow_type(type)
El argumento type puede tomar uno de los siguientes valores:
SHADOW_NONE # sin sombra
SHADOW_IN # sombra hacia dentro
SHADOW_OUT # sombra hacia fuera
SHADOW_ETCHED_IN # sombra abrupta hacia dentro
SHADOW_ETCHED_OUT # sombra abrupta hacia fuera (valor predeterminado)
El ejemplo frame.py [examples/frame.py] muestra el uso del control Marco. La gura Figura 10.4. Ejemplo de
Marco muestra la ventana resultante:
122
Captulo 10. Controles Contenedores
Figura 10.4. Ejemplo de Marco
EL cdigo fuente de frame.py [examples/frame.py] es:
1 #!/usr/bin/env python
2
3 # example frame.py
4
5 import gtk
6
7 class FrameExample:
8 def __init__(self):
9 # Create a new window
10 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
11 window.set_title("Frame Example")
12
13 # Here we connect the "destroy" event to a signal handler
14 window.connect("destroy", gtk.mainquit)
15 window.set_size_request(300, 300)
16
17 # Sets the border width of the window.
18 window.set_border_width(10)
19
20 # Create a Frame
21 frame = gtk.Frame()
22 window.add(frame)
23
123
Captulo 10. Controles Contenedores
24 # Set the frames label
25 frame.set_label("GTK Frame Widget")
26
27 # Align the label at the right of the frame
28 frame.set_label_align(1.0, 0.0)
29
30 # Set the style of the frame
31 frame.set_shadow_type(gtk.SHADOW_ETCHED_OUT)
32 frame.show()
33
34 # Display the window
35 window.show()
36
37 def main():
38 # Enter the event loop
39 gtk.main()
40 return 0
41
42 if __name__ == "__main__":
43 FrameExample()
44 main()
Los programas calendar.py [examples/calendar.py], label.py [examples/label.py] y spinbutton.py [exam-
ples/spinbutton.py] tambin usan Marcos.
10.6. Marcos Proporcionales
El control de marco proporcional es como un control de marco, excepto en que tambin mantiene el cociente de
proporcionalidad (esto es, el cociente del ancho entre el alto) del control hijo a un determinado valor, aadiendo
espacio extra si es necesario. Esto es til, por ejemplo, cuando quieres previsualizar una imgen ms grande.
El tamao de la previsualizacin debera variar cuando el usuario redimensione la ventana, pero el cociente de
proporcionalidad debe siempre corresponderse al de la imgen original.
Para crear un nuevo marco proporcional utiliza:
aspect_frame = gtk.AspectFrame(label=None, xalign=0.5, yalign=0.5, ratio=1.0,

obey_child=TRUE)
label especica el texto a mostrar en el ttulo. xalign y yalign especican la alineacin como en el control
Alignment . Si obey_child es TRUE, el cociente de proporcionalidad de un control hijo se corresponder con
el cociente de proporcionalidad del tamao ideal que solicite. En caso contrario, se especica dicho cociente con
el argumento ratio.
Para cambiar las opciones de un marco proporcional existente, puedes utilizar:
aspect_frame.set(xalign=0.0, yalign=0.0, ratio=1.0, obey_child=TRUE)
Como ejemplo, el programa aspectframe.py [examples/aspectframe.py] usa un AspectFrame para presentar
un rea de dibujo cuyo cociente de proporcionalidad ser siempre 2:1, no importa si el usuario redimensiona la
ventana contenedora. La gura Figura 10.5. Ejemplo de Marco Proporcional muestra la ventana del programa:
124
Captulo 10. Controles Contenedores
Figura 10.5. Ejemplo de Marco Proporcional
El cdigo fuente del programa aspectframe.py [examples/aspectframe.py] es:
1 #!/usr/bin/env python
2
3 # example aspectframe.py
4
5 import gtk
6
7 class AspectFrameExample:
8 def __init__(self):
9 window = gtk.Window(gtk.WINDOW_TOPLEVEL);
10 window.set_title("Aspect Frame")
11 window.connect("destroy", gtk.mainquit)
12 window.set_border_width(10)
13
14 # Create an aspect_frame and add it to our toplevel window
15 aspect_frame = gtk.AspectFrame("2x1", # label
16 0.5, # center x
17 0.5, # center y
18 2, # xsize/ysize = 2
19 gtk.FALSE) # ignore childs aspect
20 window.add(aspect_frame)
21 aspect_frame.show()
22
23 # Now add a child widget to the aspect frame
24 drawing_area = gtk.DrawingArea()
25
26 # Ask for a 200x200 window, but the AspectFrame will give us a 200x100
27 # window since we are forcing a 2x1 aspect ratio
28 drawing_area.set_size_request(200, 200)
29 aspect_frame.add(drawing_area)
125
Captulo 10. Controles Contenedores
30 drawing_area.show()
31 window.show()
32
33 def main():
34 gtk.main()
35 return 0
36
37 if __name__ == "__main__":
38 AspectFrameExample()
39 main()
10.7. Controles de Panel
Los controles de paneles son tiles cuando quieres dividir un rea en dos partes, con el tamao relativo de las
dos partes controlado por el usuario. Una barra se dibuja entre las dos partes con un mango que el usuario puede
arrastrar para cambiar la relacin. La divisin puede ser horizontal (HPaned) o vertical (VPaned).
Para crear una nueva ventana con panel, haz una llamada a uno de:
hpane = gtk.HPaned()
o
vpane = gtk.VPaned()
Despus de crear el control de panel, tienes que aadir hijos a sus dos mitades. Para hacer eso, usa los mtodos:
paned.add1(child)
paned.add2(child)
El mtodo add1() aade el control hijo a la izquierda o arriba del control de panel. EL mtodo add2() aade un
control hijo a la derecha o abajo del panel.
El programa de ejemplo paned.py [examples/paned.py] crea parte de la interfaz de usuario de un programa de
correo electrnico imaginario. Una ventana se divide en dos partes verticalmente, donde la parte de arriba es una
lista de correos electrnicos y la parte de abajo es el texto del mensaje electrnico. La mayora del programa es
bastante sencillo. Hay un par de puntos en los que hacer hincapie: no se puede aadir texto a un control Text hasta
que se realiza. Esto podra conseguirse llamando al mtodo realize() , pero como demostracin de una tcnica
alternativa, conectamos un manejador para la seal "realize" para aadir el texto. Adems, necesitamos aadir la
opcin SHRINK (encoger) a algunos de los elementos de la tabla que contiene la ventana de texto y sus barras de
desplazamiento, para que cuando la parte de abajo se haga ms pequea, las secciones correctas se encojan en
vez de que desaparezcan por la parte de abajo de la ventana. La gura Figura 10.6. Ejemplo de Panel muestra el
resultado de ejecutar el programa:
126
Captulo 10. Controles Contenedores
Figura 10.6. Ejemplo de Panel
El cdigo fuente del programa paned.py [examples/paned.py] es:
1 #!/usr/bin/env python
2
3 # example paned.py
4
5 import gtk, gobject
6
7 class PanedExample:
8 # Create the list of "messages"
9 def create_list(self):
10 # Create a new scrolled window, with scrollbars only if needed
11 scrolled_window = gtk.ScrolledWindow()
12 scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
13
127
Captulo 10. Controles Contenedores
14 model = gtk.ListStore(gobject.TYPE_STRING)
15 tree_view = gtk.TreeView(model)
16 scrolled_window.add_with_viewport (tree_view)
17 tree_view.show()
18
19 # Add some messages to the window
20 for i in range(10):
21 msg = "Message #%d" % i
22 iter = model.append()
23 model.set(iter, 0, msg)
24
25 cell = gtk.CellRendererText()
26 column = gtk.TreeViewColumn("Messages", cell, text=0)
27 tree_view.append_column(column)
28
29 return scrolled_window
30
31 # Add some text to our text widget - this is a callback that is invoked
32 # when our window is realized. We could also force our window to be
33 # realized with GtkWidget.realize, but it would have to be part of a
34 # hierarchy first
35 def insert_text(self, buffer):
36 iter = buffer.get_iter_at_offset(0)
37 buffer.insert(iter,
38 "From: pathfinder@nasa.gov\n"
39 "To: mom@nasa.gov\n"
40 "Subject: Made it!\n"
41 "\n"
42 "We just got in this morning. The weather has been\n"
43 "great - clear but cold, and there are lots of fun sights.\n"
44 "Sojourner says hi. See you soon.\n"
45 " -Path\n")
46
47 # Create a scrolled text area that displays a "message"
48 def create_text(self):
49 view = gtk.TextView()
50 buffer = view.get_buffer()
51 scrolled_window = gtk.ScrolledWindow()
52 scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
53 scrolled_window.add(view)
54 self.insert_text(buffer)
55 scrolled_window.show_all()
56 return scrolled_window
57
58 def __init__(self):
59 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
60 window.set_title("Paned Windows")
61 window.connect("destroy", gtk.mainquit)
62 window.set_border_width(10)
63 window.set_size_request(450, 400)
64
65 # create a vpaned widget and add it to our toplevel window
66 vpaned = gtk.VPaned()
67 window.add(vpaned)
68 vpaned.show()
69
70 # Now create the contents of the two halves of the window
71 list = self.create_list()
72 vpaned.add1(list)
128
Captulo 10. Controles Contenedores
73 list.show()
74
75 text = self.create_text()
76 vpaned.add2(text)
77 text.show()
78 window.show()
79
80 def main():
81 gtk.main()
82 return 0
83
84 if __name__ == "__main__":
85 PanedExample()
86 main()
10.8. Puertos de Visin
Es poco probable que necesites usar el control Viewport (Puerto de Visin) directamente. Es mucho ms probable
que uses el control ScrolledWindow, el cual usa un Viewport.
Un control de puerto de visin te permite colocar un control ms grande dentro de l de tal forma que puedes ver
una parte de l de una vez. Usa Adjustments para denir el rea que se ve.
Un Viewport se crea con la funcin:
viewport = gtk.Viewport(hadjustment=None, vadjustment=None)
Como puedes ver puedes especicar los Adjustments horizontal y vertical que el control usa cuando lo crees.
Crear sus propios ajustes si le pasas None como el valor de los argumentos o simplemente no le pasas argumentos.
Puedes consultar y jar los ajustes despus de que el control se haya creado usando los siguientes cuatro mtodos:
viewport.get_hadjustment()
viewport.get_vadjustment()
viewport.set_hadjustment(adjustment)
viewport.set_vadjustment(adjustment)
El otro mtodo que se usa para modicar la apariencia es:
viewport.set_shadow_type(type)
Los valores posibles para el parmetro type son:
SHADOW_NONE # sin sombra
SHADOW_IN # sombra hacia adentro
SHADOW_OUT # sombra hacia afuera
SHADOW_ETCHED_IN # sombra abrupta hacia adentro
129
Captulo 10. Controles Contenedores
SHADOW_ETCHED_OUT # sombra abrupta hacia fuera
10.9. Ventanas de Desplazamiento
Las ventanas de desplazamiento se usan para crear un rea de desplazamiento con otro control dentro de ella.
Puede insertar cualquier tipo de control dentro de una ventana de desplazamiento, y ser accesible da igual su
tamao usando barras de desplazamiento.
La siguiente funcin se usa para crear una nueva ventana de desplazamiento.
scrolled_window = gtk.ScrolledWindow(hadjustment=None, vadjustment=None)
Donde el primer argumento es el ajuste para la direccin horizontal, y el segundo, el ajuste para la direccin
vertical. Casi siempre se ponen a None o no se especican.
scrolled_window.set_policy(hscrollbar_policy, vscrollbar_policy)
Este mtodo especica la poltica a usar con respecto a las barras de desplazamiento. El primer argumento le ja
la poltica a la barra de desplazamiento horizontal, y el segundo, la poltica de la barra de desplazamiento vertical.
La poltica puede tomar los valores POLICY_AUTOMATIC o POLICY_ALWAYS. POLICY_AUTOMATIC
automticamente decidir si es necesario las barras de desplazamiento, mientras que POLICY_ALWAYS siempre
dejar las barras de desplazamiento visibles.
Entonces puedes colocar tu objeto dentro de la ventana de desplazamiento usando el siguiente mtodo.
scrolled_window.add_with_viewport(child)
El programa de ejemplo scrolledwin.py [examples/scrolledwin.py] coloca una tabla con 100 botones biestado
dentro de una ventana de desplazamiento. Slo he comantado las partes que pueden ser nuevas para ti. La gura
Figura 10.7. Ejemplo de Ventana de Desplazamiento muestra la ventana del programa:
130
Captulo 10. Controles Contenedores
Figura 10.7. Ejemplo de Ventana de Desplazamiento
El cdigo fuente de scrolledwin.py [examples/scrolledwin.py] es:
1 #!/usr/bin/env python
2
3 # example scrolledwin.py
4
5 import gtk
6
7 class ScrolledWindowExample:
8 def destroy(self, widget):
9 gtk.mainquit()
10
11 def __init__(self):
12 # Create a new dialog window for the scrolled window to be
13 # packed into.
14 window = gtk.Dialog()
15 window.connect("destroy", self.destroy)
16 window.set_title("ScrolledWindow example")
17 window.set_border_width(0)
18 window.set_size_request(300, 300)
19
20 # create a new scrolled window.
21 scrolled_window = gtk.ScrolledWindow()
22 scrolled_window.set_border_width(10)
23
131
Captulo 10. Controles Contenedores
24 # the policy is one of POLICY AUTOMATIC, or POLICY_ALWAYS.
25 # POLICY_AUTOMATIC will automatically decide whether you need
26 # scrollbars, whereas POLICY_ALWAYS will always leave the scrollbars
27 # there. The first one is the horizontal scrollbar, the second, the
28 # vertical.
29 scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
30
31 # The dialog window is created with a vbox packed into it.
32 window.vbox.pack_start(scrolled_window, gtk.TRUE, gtk.TRUE, 0)
33 scrolled_window.show()
34
35 # create a table of 10 by 10 squares.
36 table = gtk.Table(10, 10, gtk.FALSE)
37
38 # set the spacing to 10 on x and 10 on y
39 table.set_row_spacings(10)
40 table.set_col_spacings(10)
41
42 # pack the table into the scrolled window
43 scrolled_window.add_with_viewport(table)
44 table.show()
45
46 # this simply creates a grid of toggle buttons on the table
47 # to demonstrate the scrolled window.
48 for i in range(10):
49 for j in range(10):
50 buffer = "button (%d,%d)" % (i, j)
51 button = gtk.ToggleButton(buffer)
52 table.attach(button, i, i+1, j, j+1)
53 button.show()
54
55 # Add a "close" button to the bottom of the dialog
56 button = gtk.Button("close")
57 button.connect_object("clicked", self.destroy, window)
58
59 # this makes it so the button is the default.
60 button.set_flags(gtk.CAN_DEFAULT)
61 window.action_area.pack_start( button, gtk.TRUE, gtk.TRUE, 0)
62
63 # This grabs this button to be the default button. Simply hitting
64 # the "Enter" key will cause this button to activate.
65 button.grab_default()
66 button.show()
67 window.show()
68
69 def main():
70 gtk.main()
71 return 0
72
73 if __name__ == "__main__":
74 ScrolledWindowExample()
75 main()
Prueba a cambiarle el tamao a la ventana. Notars cmo reaccionan las barras de desplazamiento. Puede que
tambin quieras usar el mtodo set_size_request() para jar el tamao por defecto de la ventana o de otros
controles.
132
Captulo 10. Controles Contenedores
10.10. Cajas de Botones
Las ButtonBoxes (Cajas de Botones) proporcionan un sistema fcil de agrupar rpidamente botones. Vienen en
variedades horizontales y verticales. Puedes crear una nueva ButtonBox con una de las siguiente llamadas, que
crean una caja horizontal o vertical, respectivamente:
hbutton_box = gtk.HButtonBox()
vbutton_box = gtk.VButtonBox()
Los nicos mtodos de las cajas de botones afectan a la disposicin de los botones.
La disposicin de los botones dentro de la caja se establece usando:
button_box.set_layout(layout_style)
El argumento layout_style puede tomar uno de los siguientes valores:
BUTTONBOX_DEFAULT_STYLE # estilo predeterminado
BUTTONBOX_SPREAD # esparcidos
BUTTONBOX_EDGE # filo
BUTTONBOX_START # principio
BUTTONBOX_END # fin
El valor actual de layout_style se puede consultar usando:
layout_style = button_box.get_layout()
Los botones se aaden a la ButtonBox usando el tpico mtodo del Container (Contenedor):
button_box.add(widget)
El programa de ejemplo buttonbox.py [examples/buttonbox.py] ilustra todos los tipos de disposicin de las
ButtonBoxes. La ventana resultante es:
133
Captulo 10. Controles Contenedores
El cdigo fuente del programa buttonbox.py [examples/buttonbox.py] es:
1 #!/usr/bin/env python
134
Captulo 10. Controles Contenedores
2
3 # example buttonbox.py
4
5 import gtk
6
7 class ButtonBoxExample:
8 # Create a Button Box with the specified parameters
9 def create_bbox(self, horizontal, title, spacing, layout):
10 frame = gtk.Frame(title)
11
12 if horizontal:
13 bbox = gtk.HButtonBox()
14 else:
15 bbox = gtk.VButtonBox()
16
17 bbox.set_border_width(5)
18 frame.add(bbox)
19
20 # Set the appearance of the Button Box
21 bbox.set_layout(layout)
22 bbox.set_spacing(spacing)
23
24 button = gtk.Button(stock=gtk.STOCK_OK)
25 bbox.add(button)
26
27 button = gtk.Button(stock=gtk.STOCK_CANCEL)
28 bbox.add(button)
29
30 button = gtk.Button(stock=gtk.STOCK_HELP)
31 bbox.add(button)
32
33 return frame
34
35 def __init__(self):
36 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
37 window.set_title("Button Boxes")
38
39 window.connect("destroy", gtk.mainquit)
40
41 window.set_border_width(10)
42
43 main_vbox = gtk.VBox(gtk.FALSE, 0)
44 window.add(main_vbox)
45
46 frame_horz = gtk.Frame("Horizontal Button Boxes")
47 main_vbox.pack_start(frame_horz, gtk.TRUE, gtk.TRUE, 10)
48
49 vbox = gtk.VBox(gtk.FALSE, 0)
50 vbox.set_border_width(10)
51 frame_horz.add(vbox)
52
53 vbox.pack_start(self.create_bbox(gtk.TRUE, "Spread (spacing 40)",
54 40, gtk.BUTTONBOX_SPREAD),
55 gtk.TRUE, gtk.TRUE, 0)
56
57 vbox.pack_start(self.create_bbox(gtk.TRUE, "Edge (spacing 30)",
58 30, gtk.BUTTONBOX_EDGE),
59 gtk.TRUE, gtk.TRUE, 5)
60
135
Captulo 10. Controles Contenedores
61 vbox.pack_start(self.create_bbox(gtk.TRUE, "Start (spacing 20)",
62 20, gtk.BUTTONBOX_START),
63 gtk.TRUE, gtk.TRUE, 5)
64
65 vbox.pack_start(self.create_bbox(gtk.TRUE, "End (spacing 10)",
66 10, gtk.BUTTONBOX_END),
67 gtk.TRUE, gtk.TRUE, 5)
68
69 frame_vert = gtk.Frame("Vertical Button Boxes")
70 main_vbox.pack_start(frame_vert, gtk.TRUE, gtk.TRUE, 10)
71
72 hbox = gtk.HBox(gtk.FALSE, 0)
73 hbox.set_border_width(10)
74 frame_vert.add(hbox)
75
76 hbox.pack_start(self.create_bbox(gtk.FALSE, "Spread (spacing 5)",
77 5, gtk.BUTTONBOX_SPREAD),
78 gtk.TRUE, gtk.TRUE, 0)
79
80 hbox.pack_start(self.create_bbox(gtk.FALSE, "Edge (spacing 30)",
81 30, gtk.BUTTONBOX_EDGE),
82 gtk.TRUE, gtk.TRUE, 5)
83
84 hbox.pack_start(self.create_bbox(gtk.FALSE, "Start (spacing 20)",
85 20, gtk.BUTTONBOX_START),
86 gtk.TRUE, gtk.TRUE, 5)
87
88 hbox.pack_start(self.create_bbox(gtk.FALSE, "End (spacing 20)",
89 20, gtk.BUTTONBOX_END),
90 gtk.TRUE, gtk.TRUE, 5)
91
92 window.show_all()
93
94 def main():
95 # Enter the event loop
96 gtk.main()
97 return 0
98
99 if __name__ == "__main__":
100 ButtonBoxExample()
101 main()
10.11. Barra de Herramientas
Las Toolbars (Barras de Herramientas) se usan normalmente para agrupar un nmero de controles para
simplicar la personalizacin de su apariencia y disposicin. Tpicamente una barra de herramientas consiste
en botones con iconos, etiquetas y pistas, pero cualquier otro control se puede poner en una barra de herramientas.
Finalmente, los elementos se pueden colocar horizontal o verticalmente y se pueden ver los botones con iconos,
texto, o ambos.
Crear una barra de herramientas se consigue (como uno podra sospechar) con la siguiente funcin:
toolbar = gtk.Toolbar()
136
Captulo 10. Controles Contenedores
Despus de crear una barra de herramientas uno puede aadir al principio, al nal o en otro posicin, items (textos
simples) o elementos (cualquier tipo de control) en la barra de herramientas. Para describir un item necesitamos
un texto, un texto para la pista, un texto privado para la pista, un icono para el botn y una retrollamada. Por
ejemplo, para aadir al principio o al nal un item puedes usar los siguientes mtodos:
toolbar.append_item(text, tooltip_text, tooltip_private_text, icon, callback,

user_data=None)
toolbar.prepend_item(text, tooltip_text, tooltip_private_text, icon, callback, user_data)
Si quieres usar el mtodo insert_item(), el nico parmetro adicional que debe especicarse, es la posicin en
la cual el item debe insertarse, as:
toolbar.insert_item(text, tooltip_text, tooltip_private_text, icon, callback,
user_data, position)
Para aadir espacios entre items de la barra de herramientas de forma sencilla, puedes usar los siguientes mtodos:
toolbar.append_space()
toolbar.prepend_space()
toolbar.insert_space(position)
Si es necesario, la orientacin de una barra de herramientas, su estilo y el hecho de que las pistas estn disponibles,
se puede cambiar sobre la marcha usando los siguientes mtodos:
toolbar.set_orientation(orientation)
toolbar.set_style(style)
toolbar.set_tooltips(enable)
Donde la orientation puede ser ORIENTATION_HORIZONTAL o ORIENTATION_VERTICAL. El style
se usa para especicar la apariencia de la barra de herramientas y puede ser TOOLBAR_ICONS (iconos),
TOOLBAR_TEXT (texto), o TOOLBAR_BOTH (ambos). El argumento enable puede ser o TRUE o FALSE.
Para mostrar algunas otras cas que se pueden hacer con una barra de herramientas veamos el siguiente programa
de ejemplo toolbar.py [examples/toolbar.py] (interrumpiremos el listado con algunas explicaciones adicionales):
1 #!/usr/bin/env python
2
3 # example toolbar.py
4
5 import gtk
6
7 class ToolbarExample:
8 # This method is connected to the Close button or
9 # closing the window from the WM
10 def delete_event(self, widget, event=None):
137
Captulo 10. Controles Contenedores
11 gtk.mainquit()
12 return gtk.FALSE
13
Este principio debera resultarte familiar si no es tu primer programa PyGTK. No obstante hay una cosa ms,
vamos a importar un bonito dibujo XPM (gtk.xpm [examples/gtk.xpm]) para que nos sirva de icono para todos
los botones. La linea 8 empieza la clase de ejemplo ToolbarExample y las lineas 10-12 denen el mtodo de
retrollamada que nalizar el programa.
14 # thats easy... when one of the buttons is toggled, we just
15 # check which one is active and set the style of the toolbar
16 # accordingly
17 def radio_event(self, widget, toolbar):
18 if self.text_button.get_active():
19 toolbar.set_style(gtk.TOOLBAR_TEXT)
20 elif self.icon_button.get_active():
21 toolbar.set_style(gtk.TOOLBAR_ICONS)
22 elif self.both_button.get_active():
23 toolbar.set_style(gtk.TOOLBAR_BOTH)
24
25 # even easier, just check given toggle button and enable/disable
26 # tooltips
27 def toggle_event(self, widget, toolbar):
28 toolbar.set_tooltips(widget.get_active())
29
Las lineas 17-28 son dos mtodos de retrollamada que se llamarn cuando uno de los botones de la barra de
herramientas se active. Debera conocer cosas como esta si ya has usado botones biestado (y botones de exclusin
mtua).
30 def __init__(self):
31 # Here is our main window (a dialog) and a handle for the handlebox
32 # Ok, we need a toolbar, an icon with a mask (one for all of
33 # the buttons) and an icon widget to put this icon in (but
34 # well create a separate widget for each button)
35 # create a new window with a given title, and nice size
36 dialog = gtk.Dialog()
37 dialog.set_title("GTKToolbar Tutorial")
38 dialog.set_size_request(450, 250)
39 dialog.set_resizable(gtk.TRUE)
40
41 # typically we quit if someone tries to close us
42 dialog.connect("delete_event", self.delete_event)
43
44 # to make it nice well put the toolbar into the handle box,
45 # so that it can be detached from the main window
46 handlebox = gtk.HandleBox()
47 dialog.vbox.pack_start(handlebox, gtk.FALSE, gtk.FALSE, 5)
48
Lo anterior debera ser comn a cualquier otra aplicacin PyGTK. Inicializacin de una instancia de
ToolbarExample, creacin de la ventana, etc. Slo hay una cosa que probablemente necesite ms expli-
cacin: una caja con mango (HandleBox). Una caja con mango es simplemente otra caja cualquiera que puede
usarse para meter controles dentro. La diferencia entre ella y las cajas tpicas es que puede despegarse de la
138
Captulo 10. Controles Contenedores
ventana padre (o, de hecho, la caja con mango permanece en el padre, pero se reduce a un rectngulo muy
pequeo, mientras que todos sus contenidos cambian de padre a una nueva ventana otante). Normalmente es
bueno tener una barra de herramientas desplegable, por lo que estos dos controles suelen ir juntos normalmente.
49 # toolbar will be horizontal, with both icons and text, and
50 # with 5pxl spaces between items and finally,
51 # well also put it into our handlebox
52 toolbar = gtk.Toolbar()
53 toolbar.set_orientation(gtk.ORIENTATION_HORIZONTAL)
54 toolbar.set_style(gtk.TOOLBAR_BOTH)
55 toolbar.set_border_width(5)
56 handlebox.add(toolbar)
57
Bien, lo que hacemos arriba es una simple inicializacin del control de la barra de herramientas.
58 # our first item is (close) button
59 iconw = gtk.Image() # icon widget
60 iconw.set_from_file("gtk.xpm")
61 close_button = toolbar.append_item(
62 "Close", # button label
63 "Closes this app", # this buttons tooltip
64 "Private", # tooltip private info
65 iconw, # icon widget
66 self.delete_event) # a signal
67 toolbar.append_space() # space after item
En el cdigo anterior puedes ver el caso ms simple: aadir un botn a la barra de herramientas. Justo antes de
aadir el nuevo item, tenemos que construir un control de imgen que servir como icono para este item; este
paso tiene que repetirse para cada item nuevo. Justo despus del item aadimos tambin espacio, para que los
items siguientes no se tocan unos a otros. Como puedes ver el mtodo append_item() devuelve una referencia a
nuestro control de botn recin creado, para que podamos trabajar con l de la manera normal.
69 # now, lets make our radio buttons group...
70 iconw = gtk.Image() # icon widget
71 iconw.set_from_file("gtk.xpm")
72 icon_button = toolbar.append_element(
73 gtk.TOOLBAR_CHILD_RADIOBUTTON, # type of element
74 None, # widget
75 "Icon", # label
76 "Only icons in toolbar", # tooltip
77 "Private", # tooltip private string
78 iconw, # icon
79 self.radio_event, # signal
80 toolbar) # data for signal
81 toolbar.append_space()
82 self.icon_button = icon_button
Aqui empezamos a crear un grupo de botones de exclusin mtua. Para hacer esto usamos el mtodo
append_element() . De hecho, usando este mtodo, uno puede tambin puede aadir items normales o incluso
espacios (type = gtk.TOOLBAR_CHILD_SPACE (espacio) o gtk.TOOLBAR_CHILD_BUTTON (botn)). En
el ejemplo anterior hemos empezado a crear un grupo de botones de exclusin mtua. Cuando se crean otros
139
Captulo 10. Controles Contenedores
botones de exclusin mtua se necesita una referencia al botn anterior en el grupo, para que se pueda construir
una lista de botones fcilmente (mira la seccin RadioButtons de este tutorial). Tambin tenemos una referencia
al botn en la instancia de ToolbarExample para acceder a l ms tare.
84 # following radio buttons refer to previous ones
85 iconw = gtk.Image() # icon widget
86 iconw.set_from_file("gtk.xpm")
87 text_button = toolbar.append_element(
88 gtk.TOOLBAR_CHILD_RADIOBUTTON,
89 icon_button,
90 "Text",
91 "Only texts in toolbar",
92 "Private",
93 iconw,
94 self.radio_event,
95 toolbar)
96 toolbar.append_space()
97 self.text_button = text_button
98
99 iconw = gtk.Image() # icon widget
100 iconw.set_from_file("gtk.xpm")
101 both_button = toolbar.append_element(
102 gtk.TOOLBAR_CHILD_RADIOBUTTON,
103 text_button,
104 "Both",
105 "Icons and text in toolbar",
106 "Private",
107 iconw,
108 self.radio_event,
109 toolbar)
110 toolbar.append_space()
111 self.both_button = both_button
112 both_button.set_active(gtk.TRUE)
Creamos otros botones de exclusin mtua de la misma forma excepto que le pasamos uno de los botones creados
al mtodo append_element() para especicar el grupo.
Al nal tenemos que establecer el estado de uno de los botones manualmente (si no todos tienen el estado activo,
impediendonos que los vayamos intercambiando).
114 # here we have just a simple toggle button
115 iconw = gtk.Image() # icon widget
116 iconw.set_from_file("gtk.xpm")
117 tooltips_button = toolbar.append_element(
118 gtk.TOOLBAR_CHILD_TOGGLEBUTTON,
119 None,
120 "Tooltips",
121 "Toolbar with or without tips",
122 "Private",
123 iconw,
124 self.toggle_event,
125 toolbar)
126 toolbar.append_space()
127 tooltips_button.set_active(gtk.TRUE)
140
Captulo 10. Controles Contenedores
Un botn biestado se puede crear de la forma obvia (si ya has creado botones de exclusin mtua).
129 # to pack a widget into toolbar, we only have to
130 # create it and append it with an appropriate tooltip
131 entry = gtk.Entry()
132 toolbar.append_widget(entry, "This is just an entry", "Private")
133
134 # well, it isnt created within the toolbar, so we must still show it
135 entry.show()
Como vers, aadir cualquier tipo de control a una barra de herramientas es fcil. La nica cosa que tienes que
recordar es que este control debe mostrarse manualmente (al contrario que los items, que se mostrarn de golpe
con la barra de herramientas).
137 # thats it ! lets show everything.
138 toolbar.show()
139 handlebox.show()
140 dialog.show()
141
142 def main():
143 # rest in gtk_main and wait for the fun to begin!
144 gtk.main()
145 return 0
146
147 if __name__ == "__main__":
148 ToolbarExample()
149 main()
La linea 140 termina la denicin de la clase ToolbarExample. Las lineas 142-145 denen la funcin main()
que simplemente llama a la funcin gtk.main() para empezar el bucle de procesamiento de eventos. Las lineas
147-149 crean una instancia de ToolbarExample y luego entran en el bucle de procesamiento de eventos. Asi
termina el tutorial de la barra de herramientas. Por supuesto, para apreciarla en su mximo esplendor necesitas
tambin el icono XPM, gtk.xpm [examples/gtk.xpm]. La gura Figura 10.8. Ejemplo de Barra de Herramientas
muestar la ventana resultante:
141
Captulo 10. Controles Contenedores
Figura 10.8. Ejemplo de Barra de Herramientas
10.12. Fichas
El control NoteBook (Fichas) es una coleccin de "pginas" que se solapan unas con otras; cada pgina contiene
informacin diferente y slo una es visible al mismo tiempo. Este control se ha hecho muy popular ltimamente
en la programacin de interfaces grcas de usuario, y es una buena manera de mostrar bloques de informacin
similar que guardan una separacin en la pantalla.
La primera funcin que necesitas saber, como probablemente adivines, se usa para crear un nuevo control de
chas.
notebook = gtk.Notebook()
Una vez que has creado las chas, hay unos cuantos mtodos que manipulan el control de chas. Vemoslos
individualmente.
El primero que trataremos especica cmo colocar los indicadores de pgina. Estos indicadores o "pestaas"
como se les conoce, se pueden colocar de cuatro maneras: arriba, abajo, izquierda o derecha.
notebook.set_tab_pos(pos)
pos ser uno de las siguientes, que son bastante descriptivas:
142
Captulo 10. Controles Contenedores
POS_LEFT # izquierda
POS_RIGHT # derecha
POS_TOP # arriba
POS_BOTTOM # abajo
POS_TOP es el valor predeterminado.
Lo siguiente que trataremos ser cmo aadir pginas a las chas. Hay tres formas de aadir pginas a un
NoteBook. Veamos las dos primeras ya que son bastante similares.
notebook.append_page(child, tab_label)
notebook.prepend_page(child, tab_label)
Estos mtodos aaden pginas a las chas insertndolas al nal (append), o al principio (prepend). child es
el control que se colocar dentro de la pgina en cuestin, y tab_label es el ttulo para la pgina que se
est aadiendo. El control child debe crearse por separado, y normalmente es un conjunto de opciones de
conguracin dentro de otro control contenedor, como una tabla.
El ltimo mtodo para aadir una pgina a las chas contiene todas las propiedades de los otros dos, y adems te
permite especicar en qu posicin se insertar la pgina en las chas.
notebook.insert_page(child, tab_label, position)
Los parmetros son los mismos que en append() y prepend() excepto en que contiene un parmetro extra,
position. Este parmetro se usa para especicar en qu lugar la pgina se insertar; la primera pgina est en la
posicin cero.
Ahora que sabemos cmo aadir una pgina, veamos cmo podemos borrar una pgina de las chas.
notebook.remove_page(page_num)
Este mtodo borra la pgina especicada por page_num de las chas contenidas en la variable notebook.
Para saber cul es la pgina actual de las chas utiliza el mtodo:
page = notebook.get_current_page()
Los prximos dos mtodos son simples llamadas para mover la pgina hacia alante o hacia atrs. Simplemente
utilizalos en el control de chas sobre el que quieras operar.
Nota
Cuando el notebook tiene como pgina actual la ltima pgina, y se llama a next_page() , no ocurre
nada. De forma anloga, si el notebook est en la primera pgina, y se llama a prev_page() , no pasa
nada.
143
Captulo 10. Controles Contenedores
notebook.next_page()
notebook.prev_page()
Este mtodo ja la pgina "activa". Si quieres que las chas comiencen con la pgina 5 activa, usars este mtodo.
Si no lo usas, el valor predeterminado de las chas es mostrar la primera pgina.
notebook.set_current_page(page_num)
Los siguientes dos mtodos aaden o borran las pestaas y el borde respectivamente.
notebook.set_show_tabs(show_tabs)
notebook.set_show_border(show_border)
El siguiente mtodo es til cuando tienes un gran nmero de pginas, y las pestaas no caben en la pgina. Te
permite desplazar las pestaas usando dos botones de echas.
notebook.set_scrollable(scrollable)
show_tabs (mostrar pestaas), show_border (mostrar border) y scrollable (desplazable) pueden ser TRUE
o FALSE.
Ahora veamos un ejemplo, est ampliado a partir del cdigo testgtk.py que viene con la distribucin PyGTK.
El programa notebook.py [examples/notebook.py] crea una ventana con unas chas y seis botones. Las chas
contienen 11 pginas, aadidas de tres formas diferentes, al principio, en medio o al nal. Los botones te permiten
rotar la posicin de las pestaas, aadir o borrar las pestaas y el borde, borrar una pgina, cambiar las pginas
hacia delante y hacia atrs, y salir del programa. La gura Figura 10.9. Ejemplo de Fichas muestra la ventana del
programa:
144
Captulo 10. Controles Contenedores
Figura 10.9. Ejemplo de Fichas
El cdigo fuente de notebook.py [examples/notebook.py] es:
1 #!/usr/bin/env python
2
3 # example notebook.py
4
5 import gtk
6
7 class NotebookExample:
8 # This method rotates the position of the tabs
9 def rotate_book(self, button, notebook):
10 notebook.set_tab_pos((notebook.get_tab_pos()+1) %4)
11
12 # Add/Remove the page tabs and the borders
13 def tabsborder_book(self, button, notebook):
14 tval = gtk.FALSE
15 bval = gtk.FALSE
16 if self.show_tabs == gtk.FALSE:
17 tval = gtk.TRUE
18 if self.show_border == gtk.FALSE:
19 bval = gtk.TRUE
20
21 notebook.set_show_tabs(tval)
22 self.show_tabs = tval
23 notebook.set_show_border(bval)
24 self.show_border = bval
145
Captulo 10. Controles Contenedores
25
26 # Remove a page from the notebook
27 def remove_book(self, button, notebook):
28 page = notebook.get_current_page()
29 notebook.remove_page(page)
30 # Need to refresh the widget --
31 # This forces the widget to redraw itself.
32 notebook.draw((0,0,-1,-1))
33
34 def delete(self, widget, event=None):
35 gtk.mainquit()
36 return gtk.FALSE
37
38 def __init__(self):
39 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
40 window.connect("delete_event", self.delete)
41 window.set_border_width(10)
42
43 table = gtk.Table(3,6,gtk.FALSE)
44 window.add(table)
45
46 # Create a new notebook, place the position of the tabs
47 notebook = gtk.Notebook()
48 notebook.set_tab_pos(gtk.POS_TOP)
49 table.attach(notebook, 0,6,0,1)
50 notebook.show()
51 self.show_tabs = gtk.TRUE
52 self.show_border = gtk.TRUE
53
54 # Lets append a bunch of pages to the notebook
55 for i in range(5):
56 bufferf = "Append Frame %d" % (i+1)
57 bufferl = "Page %d" % (i+1)
58
59 frame = gtk.Frame(bufferf)
60 frame.set_border_width(10)
61 frame.set_size_request(100, 75)
62 frame.show()
63
64 label = gtk.Label(bufferf)
65 frame.add(label)
66 label.show()
67
68 label = gtk.Label(bufferl)
69 notebook.append_page(frame, label)
70
71 # Now lets add a page to a specific spot
72 checkbutton = gtk.CheckButton("Check me please!")
73 checkbutton.set_size_request(100, 75)
74 checkbutton.show ()
75
76 label = gtk.Label("Add page")
77 notebook.insert_page(checkbutton, label, 2)
78
79 # Now finally lets prepend pages to the notebook
80 for i in range(5):
81 bufferf = "Prepend Frame %d" % (i+1)
82 bufferl = "PPage %d" % (i+1)
83
146
Captulo 10. Controles Contenedores
84 frame = gtk.Frame(bufferf)
85 frame.set_border_width(10)
86 frame.set_size_request(100, 75)
87 frame.show()
88
89 label = gtk.Label(bufferf)
90 frame.add(label)
91 label.show()
92
93 label = gtk.Label(bufferl)
94 notebook.prepend_page(frame, label)
95
96 # Set what page to start at (page 4)
97 notebook.set_current_page(3)
98
99 # Create a bunch of buttons
100 button = gtk.Button("close")
101 button.connect("clicked", self.delete)
102 table.attach(button, 0,1,1,2)
103 button.show()
104
105 button = gtk.Button("next page")
106 button.connect("clicked", lambda w: notebook.next_page())
107 table.attach(button, 1,2,1,2)
108 button.show()
109
110 button = gtk.Button("prev page")
111 button.connect("clicked", lambda w: notebook.prev_page())
112 table.attach(button, 2,3,1,2)
113 button.show()
114
115 button = gtk.Button("tab position")
116 button.connect("clicked", self.rotate_book, notebook)
117 table.attach(button, 3,4,1,2)
118 button.show()
119
120 button = gtk.Button("tabs/border on/off")
121 button.connect("clicked", self.tabsborder_book, notebook)
122 table.attach(button, 4,5,1,2)
123 button.show()
124
125 button = gtk.Button("remove page")
126 button.connect("clicked", self.remove_book, notebook)
127 table.attach(button, 5,6,1,2)
128 button.show()
129
130 table.show()
131 window.show()
132
133 def main():
134 gtk.main()
135 return 0
136
137 if __name__ == "__main__":
138 NotebookExample()
139 main()
Espero que esto te ayude en tu camino para crear chas en tus programas PyGTK.
147
Captulo 11. Control Men
Hay dos formas de crear mens: la forma fcil y la dicil. Las dos tienen sus usos, pero normalmente puedes
usar el Itemfactory (Factoria de Elementos) (la forma fcil). La forma "difcil" es crear los mens usando las
llamadas directamente. La forma fcil consiste en usar las llamadas a GtkItemFactory . Esto es mucho ms
simple, pero cada enfoque tiene sus ventajas y desventajas.
La Itemfactory es mucho ms fcil de usar, y ms fcil de aadir mens, aunque escribir unas cuantas funciones
auxiliares para crear mens usando el mtodo manual puede ser mucho mejor en trminos de usabilidad. Con la
Itemfactory, no es posible aadir imgenes o el carcter / a los mens.
11.1. Creacin de Mens Manual
Siguiendo la tradicin docente pura, primero te ensearemos la forma difcil. :)
Hay tres controles involucrados en la creacin de una barra de mens y de submens:
un elemento de men, que es lo que el usuario va a seleccionar, por ejemplo, "Guardar"
un men, que actua como contenedor para elementos de men, y
una barra de men, que es un contenedor para cada men individual.
Esto es algo complicado por el hecho de que los controles de elementos de men se usan para dos cosas distintas.
Son tanto los controles que se colocan en el men, y el control que se coloca en la barra de men, que, cuando se
selecciona, activa el men.
Veamos las funciones que se usan para crear mens y barras de mens. La primera funcin se usa para crear una
nueva barra de men:
menu_bar = gtk.MenuBar()
Esta funcin bastante autoexplicativa crea una nueva barra de mens. Puedes usar el mtodo add() de
GtkContainer para meter la barra de mens en una ventana, o los mtodos pack de GtkBox para meterlo en
una caja - igual que los botones.
menu = gtk.Menu()
Esta funcin devuelve una referencia a un nuevo men; nunca se mostrar (con el mtodo show() ), es slo un
contenedor para los elementos de mens. Espero que esto se aclare un poco cuando veas el ejemplo ms abajo.
La siguiente funcin se usa para crear elementos de mens que se colocan en el men (y la barra de mens):
menu_item = gtk.MenuItem(label=None)
El parmetro label, si existe, se analizar buscando caracteres mnemnicos. Esta llamada se usa para crear
elementos de men que se van a visualizar. Acuerdate de diferenciar entre un "men" como el que creas con
gtk.Menu() y un "elemento de men" como el que creas con gtk.MenuItem() . El elemento de men ser en
148
Captulo 11. Control Men
realidad un botn con una accin asociada, mientras que un men ser un contenedor que contiene elementos de
men.
Una vez que has creado un elemento de men tienes que meterlo en un men. Esto se consigue con el mtodo
append() . Para poder saber cundo el usuario selecciona un elemento, necesitamos conectarlo a la seal "activate"
de la forma habitual. Por tanto, si queremos crear un men estndard Archivo , con las opciones Abrir, Guardar,
y Salir, el cdigo sera algo asi como:
file_menu = gtk.Menu() # Dont need to show menus
# Create the menu items
open_item = gtk.MenuItem("Abrir")
save_item = gtk.MenuItem("Guardar")
quit_item = gtk.MenuItem("Salir")
# Add them to the menu
file_menu.append(open_item)
file_menu.append(save_item)
file_menu.append(quit_item)
# Conecta las funciones de retrollamada a la seal "activate"
open_item.connect_object("activate", menuitem_response, "file.open")
save_item.connect_object("activate", menuitem_response, "file.save")
# conectamos el elemento quit a nuestra funcin de salida
quit_item.connect_object ("activate", destroy, "file.quit")
# necesitamos mostrar los elementos de men
open_item.show()
save_item.show()
quit_item.show()
En este punto tenemos nuestro men. Ahora necesitamos crear una barra de men y un elemento de men para la
entrada Archivo , que aadiremos a nuestro men. El cdigo es el siguiente:
menu_bar = gtk.MenuBar()
window.add(menu_bar)
menu_bar.show()
file_item = gtk.MenuItem("Archivo")
file_item.show()
Ahora necesitamos asociar el men con file_item. Esto se hace con el mtodo:
menu_item.set_submenu(submenu)
Por tanto, nuestro ejemplo contina asi:
menu_item.set_submenu(file_menu)
Lo nico que nos queda es aadir el men a la barra de mens, lo cual se consigue con el mtodo:
149
Captulo 11. Control Men
menu_bar.append(child)
que en nuestro caso es as:
menu_bar.append(file_item)
Si queremos el men justicado a la derecha en la barra de mens, como los mens de ayuda, podemos usar el
siguiente mtodo (de nuevo en file_item en nuestro ejemplo) antes de aadirlo a la barra de mens.
menu_item.set_right_justified(right_justified)
Aqui tienes un resumen de los pasos necesarios para crear una barra de mens con mens en ella:
Crea un nuevo men con gtk.Menu()
Usa varias llamadas a gtk.MenuItem() una para cada elemento que quieras tener en tu men. Y usa el mtodo
append() para poner cada uno de estos elementos en el men.
Crea un elemento de men usando gtk.MenuItem(). Este ser la raiz del men, el texto que aparezca aqui
estar en la propia barra de mens.
Usa el mtodo set_submenu() para aadir el men al elemento raiz del men (el que creamos en el paso
anterior).
Crea una nueva barra de mens usando gtk.MenuBar(). Este paso slo hay que hacerlo una vez cuando
estemos creando una serie de mens en una barra de mens.
Usa el mtodo append() para poner el men raiz en la barra de mens.
Crear un men emergente es casi lo mismo. La diferencia es que el men no se visualiza "automticamente" por
una barra de mens, sino explcitamente llamando al mtodo popup() desde un evento de pulsacin de botn, por
ejemplo. Sigue estos pasos:
Crea una retrollamada que maneje el evento. Necesita tener el siguiente formato:
def handler(widget, event):
y usar el evento para saber donde mostrar el men.
En el manejador del evento, si el evento es una pulsacin de botn, trata el evento como un evento de botn
(realmente lo es) y usalo como en el cdigo de ejemplo, para pasar informacin al mtodo popup() .
Enlaza el manejador del evento al control con:
widget.connect_object("event", handler, menu)
150
Captulo 11. Control Men
donde widget es el control que estas conectando, handler es la funcin manejadora, y menu es un men creado
con GtkMenu(). Esto puede ser un men que tambin est en una barra de mens, como se muestra en el
cdigo de ejemplo.
11.2. Ejemplo de Men Manual
Esto debera hacerlo. Veamos el programa de ejemplo menu.py [examples/menu.py] para ayudarnos a claricar
los conceptos. La gura Figura 11.1. Ejemplo de Men muestra la ventana del programa:
Figura 11.1. Ejemplo de Men
El cdigo fuente de menu.py [examples/menu.py] es:
1 #!/usr/bin/env python
2
3 # example menu.py
4
5 import gtk
6
7 class MenuExample:
8 def __init__(self):
9 # create a new window
10 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
11 window.set_size_request(200, 100)
12 window.set_title("GTK Menu Test")
13 window.connect("delete_event", gtk.mainquit)
14
15 # Init the menu-widget, and remember -- never
16 # show() the menu widget!!
17 # This is the menu that holds the menu items, the one that
18 # will pop up when you click on the "Root Menu" in the app
19 menu = gtk.Menu()
20
21 # Next we make a little loop that makes three menu-entries for
22 # "test-menu". Notice the call to gtk_menu_append. Here we are
23 # adding a list of menu items to our menu. Normally, wed also
24 # catch the "clicked" signal on each of the menu items and setup a
25 # callback for it, but its omitted here to save space.
26 for i in range(3):
27 # Copy the names to the buf.
28 buf = "Test-undermenu - %d" % i
29
30 # Create a new menu-item with a name...
151
Captulo 11. Control Men
31 menu_items = gtk.MenuItem(buf)
32
33 # ...and add it to the menu.
34 menu.append(menu_items)
35
36 # Do something interesting when the menuitem is selected
37 menu_items.connect("activate", self.menuitem_response, buf)
38
39 # Show the widget
40 menu_items.show()
41
42 # This is the root menu, and will be the label
43 # displayed on the menu bar. There wont be a signal handler attached,
44 # as it only pops up the rest of the menu when pressed.
45 root_menu = gtk.MenuItem("Root Menu")
46
47 root_menu.show()
48
49 # Now we specify that we want our newly created "menu" to be the
50 # menu for the "root menu"
51 root_menu.set_submenu(menu)
52
53 # A vbox to put a menu and a button in:
54 vbox = gtk.VBox(gtk.FALSE, 0)
55 window.add(vbox)
56 vbox.show()
57
58 # Create a menu-bar to hold the menus and add it to our main window
59 menu_bar = gtk.MenuBar()
60 vbox.pack_start(menu_bar, gtk.FALSE, gtk.FALSE, 2)
61 menu_bar.show()
62
63 # Create a button to which to attach menu as a popup
64 button = gtk.Button("press me")
65 button.connect_object("event", self.button_press, menu)
66 vbox.pack_end(button, gtk.TRUE, gtk.TRUE, 2)
67 button.show()
68
69 # And finally we append the menu-item to the menu-bar -- this is the
70 # "root" menu-item I have been raving about =)
71 menu_bar.append (root_menu)
72
73 # always display the window as the last step so it all splashes on
74 # the screen at once.
75 window.show()
76
77 # Respond to a button-press by posting a menu passed in as widget.
78 #
79 # Note that the "widget" argument is the menu being posted, NOT
80 # the button that was pressed.
81 def button_press(self, widget, event):
82 if event.type == gtk.gdk.BUTTON_PRESS:
83 widget.popup(None, None, None, event.button, event.time)
84 # Tell calling code that we have handled this event the buck
85 # stops here.
86 return gtk.TRUE
87 # Tell calling code that we have not handled this event pass it on.
88 return gtk.FALSE
89
152
Captulo 11. Control Men
90 # Print a string when a menu item is selected
91 def menuitem_response(self, widget, string):
92 print "%s" % string
93
94 def main():
95 gtk.main()
96 return 0
97
98 if __name__ == "__main__":
99 MenuExample()
100 main()
Tambin puedes hacer un elemento de men insensitivo y, usando una tabla de atajos, conectar teclas a
retrollamadas de mens.
11.3. Usando la Factoria de Elementos
Ahora que te hemos enseado la forma difcil, as es como lo haras usando las llamadas a gtk.ItemFactory.
11.4. Ejemplo de Factoria de Elementos
El programa de ejemplo itemfactory.py [examples/itemfactory.py] usa la gtk.ItemFactory. La gura Figura
11.2. Ejemplo de Factoria de Elementos muestra la ventana del programa:
Figura 11.2. Ejemplo de Factoria de Elementos
153
Captulo 11. Control Men
El cdigo fuente de itemfactory.py [examples/itemfactory.py] es:
1 #!/usr/bin/env python
2
3 # example itemfactory.py
4
5 import gtk
6
7 class ItemFactoryExample:
8 # Obligatory basic callback
9 def print_hello(self, w, data):
10 print "Hello, World!"
11
12
# Esta es la estructura de la Factoria de Elementos usada para generar nuevos mens
13 # Item 1: La ruta del men. La letra despus del subrayado indica
14 # una tecla de atajo cuando el men se abra
15 # Item 2: La tecla de atajo para el elemento
16 # Item 3: La retrollamada
17 # Item 4: La accin de retrollamada. Esto cambia los parmetros con
18 # los que la retrollamada se llama. El valor predeterminado es 0
19 # Item 5: El tipo de elemento, usado para definir el tipo al que pertenece el

elemento
20 # Aqui estn los posibles valores
21
22 # NULL -> "<Item>"
23 # "" -> "<Item>"
24 # "<Title>" -> ttulo
25 # "<Item>" -> simple
26 # "<CheckItem>" -> activacin
27 # "<ToggleItem>" -> biestado
28 # "<RadioItem>" -> exclusin mtua
29 # <path> -> ruta de un elemento de exclusin mtua
30 # "<Separator>" -> separador
31 # "<Branch>" -> contenedor de nuevos elementos
32 # "<LastBranch>" -> rama justificada a la derecha
33
34 def get_main_menu(self, window):
35 accel_group = gtk.AccelGroup()
36
37 # This function initializes the item factory.
38 # Param 1: The type of menu - can be MenuBar, Menu,
39 # or OptionMenu.
40 # Param 2: The path of the menu.
41 # Param 3: A reference to an AccelGroup. The item factory sets up
42 # the accelerator table while generating menus.
43 item_factory = gtk.ItemFactory(gtk.MenuBar, "<main>", accel_group)
44
45 # This method generates the menu items. Pass to the item factory
46 # the list of menu items
47 item_factory.create_items(self.menu_items)
48
49 # Attach the new accelerator group to the window.
50 window.add_accel_group(accel_group)
51
52 # need to keep a reference to item_factory to prevent its destruction
53 self.item_factory = item_factory
54 # Finally, return the actual menu bar created by the item factory.
154
Captulo 11. Control Men
55 return item_factory.get_widget("<main>")
56
57 def __init__(self):
58 self.menu_items = (
59 ( "/_File", None, None, 0, "<Branch>" ),
60 ( "/File/_New", "<control>N", self.print_hello, 0, None ),
61 ( "/File/_Open", "<control>O", self.print_hello, 0, None ),
62 ( "/File/_Save", "<control>S", self.print_hello, 0, None ),
63 ( "/File/Save _As", None, None, 0, None ),
64 ( "/File/sep1", None, None, 0, "<Separator>" ),
65 ( "/File/Quit", "<control>Q", gtk.mainquit, 0, None ),
66 ( "/_Options", None, None, 0, "<Branch>" ),
67 ( "/Options/Test", None, None, 0, None ),
68 ( "/_Help", None, None, 0, "<LastBranch>" ),
69 ( "/_Help/About", None, None, 0, None ),
70 )
71 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
72 window.connect("destroy", gtk.mainquit, "WM destroy")
73 window.set_title("Item Factory")
74 window.set_size_request(300, 200)
75
76 main_vbox = gtk.VBox(gtk.FALSE, 1)
77 main_vbox.set_border_width(1)
78 window.add(main_vbox)
79 main_vbox.show()
80
81 menubar = self.get_main_menu(window)
82
83 main_vbox.pack_start(menubar, gtk.FALSE, gtk.TRUE, 0)
84 menubar.show()
85 window.show()
86
87 def main():
88 gtk.main()
89 return 0
90
91 if __name__ == "__main__":
92 ItemFactoryExample()
93 main()
Por ahora esto es slo un ejemplo. Una explicacin y muchos comentarios vendrn despus.
155
Captulo 12. rea de Dibujo
El control DrawingArea (rea de Dibujo) proporciona un lienzo simple en el que se puede dibujar usando los
mtodos de gtk.DrawingArea. Un DrawingArea se crea con la funcin:
drawing_area = gtk.DrawingArea()
Un DrawingArea (rea de Dibujo) se crea con un tamao de (0,0) por lo que deberas usar el siguiente mtodo
para hacer el drawing_area visible:
drawing_area.set_size_request(ancho, alto)
12.1. Contexto Grco
Hay unos cuantos mtodos para dibujar en un rea de dibujo y todos requieren un contexto grco (gtk.gdk.GC)
, que encapsula la informacin necesaria para dibujar. Los atributos de un contexto grco son:
background # fondo
cap_style # estilo de fin de linea
clip_mask # mscara de recorte
clip_x_origin # orgen x del rectngulo de recorte
clip_y_origin # orgen y del rectngulo de recorte
fill # relleno
font # fuente
foreground # color de frente
function # funcin
graphics_exposures # exposiciones grficas
join_style # estilo de unin
line_style # estilo de linea
line_width # ancho de linea
stipple # patrn de relleno
sub_window # subventana
tile # ttulo
ts_x_origin # orgen x
ts_y_origin # orgen y
background (fondo) especica el gtk.gdk.Color que se usa para dibujar el fondo.
foreground (frente) especica el gtk.gdk.Color que se usa para dibujar el color de primer plano.
Para crear un gtk.gdk.Color se usa el mtodo alloc_color() de la clase gtk.gdk.Colormap (Mapa de
Color). El mapa de color asociado a un control se puede obtener con el mtodo:
colormap = widget.get_colormap()
Se puede especicar un gtk.gdk.Color cmo una cadena de texto (por ejemplo, "red" (rojo), "orange" (naranja),
"navajo white" (blanco navajo) denida en el chero rgb.txt de X Window), o cmo un triple de rojo, verde y
azl de enteros en el rango de 0 a 65535. Adems, puedes especicar si el color es modicable (se puede cambiar
156
Captulo 12. rea de Dibujo
despus pero no puede compartirse) y si se debe hacer una bsqueda y quedarse con el color ms parecido de entre
los existentes si el color exacto no est disponible. El mtodo alloc_color() se dene as:
color = colormap.alloc_color(red, green, blue, writeable=FALSE, best_match=TRUE)
color = colormap.alloc_color(spec, writeable=FALSE, best_match=TRUE)
Por ejemplo:
navajowhite = colormap.alloc(navajo white)
cyan = colormap.alloc(0, 65535, 65535)
cap_style especica el estilo de n de linea que se usa cuando se dibuja el nal de una linea que no esta unida
a otras. Los estilos disponibles son:
CAP_NOT_LAST igual que CAP_BUTT para lineas con un ancho distinto de cero. Para lineas de
ancho igual a cero, el punto nal de la linea no se dibujar.
CAP_BUTT los nales de las lineas se dibujan como cuadrados y se extienden hasta las
coordenadas del punto nal.
CAP_ROUND los nales de las lineas se dibujan como semicrculos con el dimetro igual al
ancho de la linea y centrados en el punto nal.
CAP_PROJECTING los nales de las lineas se dibujan como cuadrados y se extienden la mitad del
ancho ms all del punto nal.
clip_mask especica un gtk.gdk.Pixmap que se usa para recortar el dibujo.
clip_x_origin y clip_y_origin especican los valores x e y del orgen del rectngulo de recorte relativos a
la esquina superior izquierda del drawing_area (rea de dibujo).
fill especica el estilo de relleno que se usar al dibujar. Los estilos de relleno disponibles son:
SOLID dibuja con el color de primer plano.
TILED dibuja con un pixmap cuadriculado.
STIPPLED dibuja con un mapa de bits de patrn. Los pxeles correspondientes a los bits del
mapa de bits que estn a uno se dibujarn con el color de primer plano; los pxeles
correspondientes a los bits que no estn a uno se dejarn sin modicar.
OPAQUE_STIPPLED dibuja usando el mapa de bits de patrn. Los pxeles correspondientes a los bits
en el mapa de bits de patrn que estn a uno se dibujarn con el color de primer
plano; los pxeles correspondientes a los bits que no estn a uno se dibujarn con
el color de fondo.
font es la gtk.gdk.Font (Fuente) que se usa cmo la fuente predeterminada para dibujar texto.
Nota
El uso del atributo font est obsoleto.
function especica cmo se combinan los valores de los bits en los pxeles de orgen con los valores de los
bits en los pxeles de destino para producir el resultado nal. Los 16 valores diferentes se corresponden con las
posibles tablas de verdad 2x2. Slo un par de estos valores es til normalmente; para imgenes a color, slo
COPY, XOR e INVERT generalmente son tiles. Para mapas de bits, AND y OR tambin suelen ser tiles. Los
valores de funcin son:
157
Captulo 12. rea de Dibujo
COPY # Copiar
INVERT # Invertir
XOR # XOR
CLEAR # Limpiar
AND # Y
AND_REVERSE # Y al revs
AND_INVERT # Y invertida
NOOP # Nada
OR # O
EQUIV # equivalencia
OR_REVERSE # O al revs
COPY_INVERT # Copiar invertido
OR_INVERT # O invertido
NAND # NAND
SET # Fijar
graphics_exposures especica si las exposiciones grcas estn activadas (TRUE) o desactivadas (FALSE).
Cuando graphics_exposures es TRUE, un fallo al copiar un pxel en una operacin de dibujo producir un
evento expose; si la copia tiene xito, se producir un evento noexpose.
join_style especica el estilo de unin que se usa cuando las lineas se juntan en un ngulo. Los estilos
disponibles son:
JOIN_MITER los lados de cada linea se extienden para unirse en un ngulo.
JOIN_ROUND los lados de las dos lineas se unen en un arco circular.
JOIN_BEVEL los lados de las dos lineas se unen con una linea recta que tiene el mismo ngulo
con cada linea.
line_style especica el estilo con el que se dibuja una linea. Los estilos disponibles son:
LINE_SOLID las lineas se dibujan solidas.
LINE_ON_OFF_DASH se dibujan los segmentos impares; los segmentos pares no se dibujan.
LINE_DOUBLE_DASH los segmentos impares son normales. Los segmentos pares se dibujan con el color
de fondo si el estilo de relleno es SOLID, o con el color de fondo aplicado a la
mscara del patrn si el estilo de relleno es STIPPLED.
line_width especica el ancho con el que se dibujan las lineas.
stipple especica el gtk.gdk.Pixmap que se usar para dibujo con patrn cuando el relleno est puesto a
STIPPLED o a OPAQUE_STIPPLED.
sub_window especica el modo de dibujo de una gtk.gdk.Window que tiene hijas gtk.gdk.Window. Los
valores posibles son:
CLIP_BY_CHILDREN slo se dibuja en la propia ventana pero no en sus ventanas hijas.
INCLUDE_INFERIORS dibuja en la ventana y en sus ventanas hijas.
tile especica el gtk.gdk.Pixmap que se usar para dibujo cuadriculado cuando el relleno esta puesto a
TILED.
ts_x_origin y ts_y_origin especican la posicin iniciales de los mapas de bits de patrn y de dibujo
cuadriculado).
Se puede crear un nuevo Contexto Grco con una llamada al mtodo gtk.gdk.Window new_gc() :
gc = widget.window.new_gc(foreground=None, background=None, font=None,
158
Captulo 12. rea de Dibujo
function=-1, fill=-1, tile=None,
stipple=None, clip_mask=None, subwindow_mode=-1,
ts_x_origin=-1, ts_y_origin=-1, clip_x_origin=-1,
clip_y_origin=-1, graphics_exposures=-1,
line_width=-1, line_style=-1, cap_style=-1
join_style=-1)
Para crear un nuevo Contexto Grco con este mtodo, el control debe ser del tipo de los que tienen una
gtk.gdk.Window y el control debe estar realizado (es decir, la gtk.gdk.Window ha sido creada).
Los atributos del Contexto Grco pueden dejarse sin tocar o especicarse en el mtodo new_gc() usando
argumentos de palabras clave de Python.
Los atributos individuales de un gtk.gdk.GC se pueden establecer asignndole un valor al atributo. Por ejemplo:
gc.cap_style = CAP_BUTT
gc.line_width = 10
gc.fill = SOLD
gc.foreground = micolor
o usando los siguientes mtodos:
gc.set_foreground(color)
gc.set_background(color)
gc.set_function(function)
gc.set_fill(fill)
gc.set_tile(tile)
gc.set_stipple(stipple)
gc.set_ts_origin(x, y)
gc.set_clip_origin(x, y)
gc.set_clip_mask(mask)
gc.set_clip_rectangle(rectangle)
gc.set_subwindow(mode)
gc.set_exposures(exposures)
gc.set_line_attributes(line_width, line_style, cap_style, join_style)
El patrn intermitente que se usa cuando el estilo de linea es LINE_ON_OFF_DASH o LINE_DOUBLE_DASH
se puede jar usando el siguiente mtodo:
gc.set_dashes(offset, dash_list)
donde offset (desplazamiento) es el ndice del valor inicial en dash_list y dash_list (lista de intermitencia)
es una lista o tupla que contiene los nmeros de los pxeles a dibujar o saltar para formar los segmentos. Los
segmentos se dibujan empezando con el nmero de pxeles en la posicin de desplazamiento; entonces, el siguiente
nmero de pxeles no se dibuja; y luego el siguiente nmero es dibujado; y as, recorriendo todos los nmeros de
la lista de intermitencia y empezando otra vez cuando se llega al nal. Por ejemplo, si la lista de intermitencia es
(2, 4, 8, 16) y el desplazamiento es 1, los segmentos se dibujarn as: dibuja 4 pxeles, sltate 8 pxeles, dibuja 16
pxeles, sltate 2 pxeles, dibuja 4 pxeles y as sucesivamente.
Se puede copiar un gtk.gdk.GC existente usando el mtodo:
159
Captulo 12. rea de Dibujo
gc.copy(src_gc)
Los atributos de gc sern los mismos que los de src_gc.
12.2. Mtodos de Dibujo
Hay un conjunto general de mtodos que se pueden usar para dibujar en el rea de dibujo. Estos mtodos de
dibujo funcionan en cualquier gtk.gdk.Drawable (Dibujable), que es una gtk.gdk.Window (Ventana) o un
gtk.gdk.Pixmap (Mapa de Pxeles). Los mtodos de dibujo son:
drawable.draw_point(gc, x, y) # dibuja_punto
gc es el Contexto Grco a usar para hacer el dibujo.
x e y son las coordenadas del punto.
drawable.draw_line(gc, x1, y1, x2, y2) # dibuja linea
gc es el Contexto Grco.
x1 e y1 especican el punto de inicio de la linea. x2 e y2 especican el punto nal de la linea.
drawable.draw_rectangle(gc, filled, x, y, width, height) # dibuja rectngulo
gc es el Contexto Grco.
filled es un valor booleano que indica si el rectngulo debe ser rellenado con el color de primer plano o no.
x e y son las coordenadas de la esquina superior izquierda del rectngulo.
width y height son el ancho y el alto del rectngulo.
drawable.draw_arc(gc, filled, x, y, width, height, angle1, angle2) # dibuja arco
gc es el Contexto Grco.
filled es un valor booleano que indica si el arco debe ser rellenado con el color de primer plano o no.
x e y son las coordenadas de la esquina superior izquierda del rectngulo que bordea al arco. width y height
son el ancho y el alto del rectngulo que bordea al arco.
angle1 es el ngulo inicial del arco, relativo a la posicin de las 3 en punto del reloj, en el sentido contrario de
las agujas del reloj, en seseinta y cuatroavos de grado.
angle2 es el ngulo nal del arco, relativo a angle1, en seseinta y cuatroavos de grado en el sentido de las agujas
del reloj.
160
Captulo 12. rea de Dibujo
drawable.draw_polygon(gc, filled, points) # dibuja polgono
gc es el Contexto Grco.
filled es un valor booleano que especica si el polgono debe ser rellenado con el color de primer plano o no.
points es una lista de pares de coordenadas en tuplas, por ejemplo [ (0,0), (2,5), (3,7), (4,11) ], de los puntos que
se van a dibujar como un polgono conectado.
drawable.draw_string(font, gc, x, y, string) # dibuja cadena
drawable.draw_text(font, gc, x, y, string) # dibuja texto
font es la gtk.gdk.Font (fuente) que se usar para pintar la cadena.
gc es el Contexto Grco.
x e y son las coordenadas del punto donde se empezar a dibujar la cadena, es decir, la lnea de base izquierda.
string es la cadena de caracteres a dibujar.
Nota
Ambos mtodos draw_string() y draw_text() estn obsoletos - en su lugar usa un pango.Layout
con el mtodo draw_layout() .
drawable.draw_layout(gc, x, y, layout) # dibuja disposicin
gc es el Contexto Grco.
x e y son las coordenadas del punto desde el que se empieza a dibujar la disposicin.
layout es el pango.Layout que se va a dibujar.
drawable.draw_drawable(gc, src, xsrc, ysrc, xdest, ydest, width, height) # dibuja

dibujable
gc es el Contexto Grco.
src es el dibujable de orgen.
xsrc e ysrc son las coordenadas de la esquina superior izquierda del rectngulo en el dibujable de orgen.
xdest e ydest son las coordenadas de la esquina superior izquierda en el rea de dibujo.
width y height son el ancho y el alto del rea del dibujable de orgen que ser copiada en el drawable. Si
width o height es -1 entonces el ancho o el alto completo del dibujable se usar.
drawable.draw_image(gc, image, xsrc, ysrc, xdest, ydest, width, height) # dibuja imgen
161
Captulo 12. rea de Dibujo
gc es el Contexto Grco.
image es la imgen orgen.
xsrc e ysrc son las coordenadas de la esquina superior izquierda del rectngulo en el dibujable orgen.
xdest e ydest son las coordenadas de la esquina superior izquierda del rectngulo en el rea de dibujo.
width y height son el ancho y el alto del rea del dibujable orgen que se copiar en el dibujable destino. Si
width o height es -1 entonces se usar el ancho o el alto completo de la imgen.
drawable.draw_points(gc, points) # dibuja puntos
gc es el Contexto Grco.
points es una lista o tupla de pares de coordenadas en tuplas, por ejemplo [ (0,0), (2,5), (3,7), (4,11) ], de los
puntos a dibujar.
drawable.draw_segments(gc, segs) # dibuja segmentos
gc es el Contexto Grco.
segs es una lista o tupla de pares de coordenadas iniciales y nales en tuplas, por ejemplo [ (0,0, 1,5), (2,5, 1,7),
(3,7, 1,11), (4,11, 1,13) ], de los segmentos de lineas a dibujar.
drawable.draw_lines(gc, points) # dibuja lineas
gc es el Contexto Grco.
points es una lista o tupla de pares de coordenadas en tuplas, por ejemplo [ (0,0), (2,5), (3,7), (4,11) ], de los
puntos a conectar con lineas.
drawable.draw_rgb_image(gc, x, y, width, height, dith, rgb_buf, rowstride) # dibuja

imagen rgb
drawable.draw_rgb_32_image(gc, x, y, width, height, dith, buf, rowstride) # dibuja

imagen rgb 32
drawable.draw_gray_image(gc, x, y, width, height, dith, buf, rowstride) # dibuja

imagen en escala de grises


gc es el Contexto Grco.
x e y son las coordenadas de la esquina superior izquierda del rectngulo que bordea la imgen.
width y height son el ancho y el alto del rectngulo que bordea la imgen.
dith es el mtodo de mezclado y se explica a continuacin:
Para el mtodo draw_rgb_image() , rgb_buf es el conjunto de los datos de la imgen RGB codicados en una
cadena como una secuencia de triples de pxeles RGB de 8 bits. Para el mtodo draw_rgb_32_image() , buf es
162
Captulo 12. rea de Dibujo
el conjunto de los datos de la imgen RGB codicados en una cadena como una secuencia de triples de pxeles
RGB de 8 bits con relleno de 8 bits (4 caracteres por cada pxel RGB). Para el mtodo draw_gray_image() , buf
es el conjunto de datos de la imgen codicados en una cadena como pxeles de 8 bits.
rowstride es el nmero de caracteres desde el principio de una la hasta el principio de la siguiente la en la
imgen. rowstride normalmente es 3 * ancho en el mtodo draw_rgb_image() ; 4 * ancho para el mtodo
draw_rgb_32_image(); y el ancho para el mtodo draw_gray_image() . Si rowstride es 0 entonces la linea
se repetir un nmero de veces igual al alto.
Los tipos de mezclado son:
RGB_DITHER_NONE # Nunca usar mezclado
RGB_DITHER_NORMAL # Usar mezclado cuando se usen 8 bits por pxel (o menos)
slamente.
RGB_DITHER_MAX # Usar mezclado cuando se usen 16 bits por pxel o menos.
El programa de ejemplo drawingarea.py [examples/drawingarea.py] muestra el uso de la mayora de los mtodos
de DrawingArea . La gura Figura 12.1. Ejemplo de rea de Dibujo muestra la ventana resultante:
Figura 12.1. Ejemplo de rea de Dibujo
163
Captulo 12. rea de Dibujo
El cdigo fuente drawingarea.py [examples/drawingarea.py] est abajo y usa el pixmap gtk.xpm [exam-
ples/gtk.xpm] :
1 #!/usr/bin/env python
2
3 # example drawingarea.py
4
5 import gtk
6 import operator
7 import time
8 import string
9
10 class DrawingAreaExample:
11 def __init__(self):
12 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
13 window.set_title("Drawing Area Example")
14 window.connect("destroy", gtk.mainquit)
15 self.area = gtk.DrawingArea()
16 self.area.set_size_request(400, 300)
17 self.pangolayout = self.area.create_pango_layout("")
18 window.add(self.area)
19 self.area.connect("expose-event", self.area_expose_cb)
20 self.area.show()
21 window.show()
22
23 def area_expose_cb(self, area, event):
24 self.style = self.area.get_style()
25 self.gc = self.style.fg_gc[gtk.STATE_NORMAL]
26 self.draw_point(10,10)
27 self.draw_points(110, 10)
28 self.draw_line(210, 10)
29 self.draw_lines(310, 10)
30 self.draw_segments(10, 100)
31 self.draw_rectangles(110, 100)
32 self.draw_arcs(210, 100)
33 self.draw_pixmap(310, 100)
34 self.draw_polygon(10, 200)
35 self.draw_rgb_image(110, 200)
36 return gtk.TRUE
37
38 def draw_point(self, x, y):
39 self.area.window.draw_point(self.gc, x+300, y+300)
40 self.pangolayout.set_text("Point", -1)
41 self.area.window.draw_layout(self.gc, x+5, y+50, self.pangolayout)
42 return
43
44 def draw_points(self, x, y):
45 points = [(x+10,y+10), (x+10,y), (x+40,y+30),
46 (x+30,y+10), (x+50,y+10)]
47 self.area.window.draw_points(self.gc, points)
48 self.pangolayout.set_text("Points", -1)
49 self.area.window.draw_layout(self.gc, x+5, y+50, self.pangolayout)
50 return
51
52 def draw_line(self, x, y):
53 self.area.window.draw_line(self.gc, x+10, y+10, x+20, y+30)
54 self.pangolayout.set_text("Line", -1)
55 self.area.window.draw_layout(self.gc, x+5, y+50, self.pangolayout)
164
Captulo 12. rea de Dibujo
56 return
57
58 def draw_lines(self, x, y):
59 points = [(x+10,y+10), (x+10,y), (x+40,y+30),
60 (x+30,y+10), (x+50,y+10)]
61 self.area.window.draw_lines(self.gc, points)
62 self.pangolayout.set_text("Lines", -1)
63 self.area.window.draw_layout(self.gc, x+5, y+50, self.pangolayout)
64 return
65
66 def draw_segments(self, x, y):
67 segments = ((x+20,y+10, x+20,y+70), (x+60,y+10, x+60,y+70),
68 (x+10,y+30 , x+70,y+30), (x+10, y+50 , x+70, y+50))
69 self.area.window.draw_segments(self.gc, segments)
70 self.pangolayout.set_text("Segments", -1)
71 self.area.window.draw_layout(self.gc, x+5, y+80, self.pangolayout)
72 return
73
74 def draw_rectangles(self, x, y):
75 self.area.window.draw_rectangle(self.gc, gtk.FALSE, x, y, 80, 70)
76 self.area.window.draw_rectangle(self.gc, gtk.TRUE, x+10, y+10, 20, 20)
77 self.area.window.draw_rectangle(self.gc, gtk.TRUE, x+50, y+10, 20, 20)
78 self.area.window.draw_rectangle(self.gc, gtk.TRUE, x+20, y+50, 40, 10)
79 self.pangolayout.set_text("Rectangles", -1)
80 self.area.window.draw_layout(self.gc, x+5, y+80, self.pangolayout)
81 return
82
83 def draw_arcs(self, x, y):
84 self.area.window.draw_arc(self.gc, gtk.FALSE, x+10, y, 70, 70,
85 0, 360*64)
86 self.area.window.draw_arc(self.gc, gtk.TRUE, x+30, y+20, 10, 10,
87 0, 360*64)
88 self.area.window.draw_arc(self.gc, gtk.TRUE, x+50, y+20, 10, 10,
89 0, 360*64)
90 self.area.window.draw_arc(self.gc, gtk.TRUE, x+30, y+10, 30, 50,
91 210*64, 120*64)
92 self.pangolayout.set_text("Arcs", -1)
93 self.area.window.draw_layout(self.gc, x+5, y+80, self.pangolayout)
94 return
95
96 def draw_pixmap(self, x, y):
97 pixmap, mask = gtk.gdk.pixmap_create_from_xpm(
98 self.area.window, self.style.bg[gtk.STATE_NORMAL], "gtk.xpm")
99
100 self.area.window.draw_drawable(self.gc, pixmap, 0, 0, x+15, y+25,
101 -1, -1)
102 self.pangolayout.set_text("Pixmap", -1)
103 self.area.window.draw_layout(self.gc, x+5, y+80, self.pangolayout)
104 return
105
106 def draw_polygon(self, x, y):
107 points = [(x+10,y+60), (x+10,y+20), (x+40,y+70),
108 (x+30,y+30), (x+50,y+40)]
109 self.area.window.draw_polygon(self.gc, gtk.TRUE, points)
110 self.pangolayout.set_text("Polygon", -1)
111 self.area.window.draw_layout(self.gc, x+5, y+80, self.pangolayout)
112 return
113
114 def draw_rgb_image(self, x, y):
165
Captulo 12. rea de Dibujo
115 b = 80*3*80*[\0]
116 for i in range(80):
117 for j in range(80):
118 b[3*80*i+3*j] = chr(255-3*i)
119 b[3*80*i+3*j+1] = chr(255-3*abs(i-j))
120 b[3*80*i+3*j+2] = chr(255-3*j)
121 buff = string.join(b, )
122 self.area.window.draw_rgb_image(self.gc, x, y, 80, 80,
123 gtk.gdk.RGB_DITHER_NONE, buff, 80*3)
124 self.pangolayout.set_text("RGB Image", -1)
125 self.area.window.draw_layout(self.gc, x+5, y+80, self.pangolayout)
126 return
127
128 def main():
129 gtk.main()
130 return 0
131
132 if __name__ == "__main__":
133 DrawingAreaExample()
134 main()
166
Captulo 13. Control de Vista de Texto
13.1. Perspectiva general de la Vista de Texto
El control TextView y sus objetos asociados (TextBuffers, TextMarks, TextIters, TextTags y
TextTagTables) proporcionan un potente marco para edicin multilinea de textos.
Un TextBuffer (Buffer de Texto) contiene el texto que se visualizar en uno o ms controles TextView (Vista
de Texto)
En GTK+ 2.0 el texto se codica en UTF-8 lo cual signica que un caracter puede codicarse con varios bytes.
Dentro de un TextBuffer es necesario diferenciar entre ndices de carcteres (llamados desplazamientos) e
ndices de bytes (llamados ndices).
Los TextIters (Iteradores de Texto) proporcionan una representacin voltil de la posicin entre dos carcteres
en un TextBuffer . Los TextIters son vlidos hasta que el nmero de carcteres en el TextBuffer cambia;
Por ejemplo, siempre que se inserten o se borren carcteres en el TextBuffer todos los TextIters se invalidan.
Los TextIters son la principal forma de especicar localizaciones en un TextBuffer para manipular texto.
Los TextMarks (Marcas de Texto) se proporcionan para permitir almacenar posiciones en un TextBuffer que
se mantienen entre modicaciones del buffer. Una marca es cmo un TextIter (representa una posicin entre
dos carcteres en un TextBuffer) pero si el texto alrededor de la marca se borra, la marca permanece donde el
texto borrado estuvo. De la misma forma, si se inseta texto en la marca, la marca acaba bien a la izquierda o a
la derecha del texto insertado, dependiendo de la gravedad de la marca - gravedad a la derecha deja la marca a la
derecha del texto insertado mientras que gravedad a la izquierda deja la marca a la izquierda. Las TextMarks se
pueden asociar a un nombre o dejarlas annimas si no se les da un nombre. Cada TextBuffer tiene dos marcas
predenidas llamadas insert (insertar) y selection_bound (lmite de seleccin). Estas marcas se reeren al
punto de insercin y al lmite de la seleccin (la seleccin est entre las marcas insert y selection_bound).
Las TextTags (Etiquetas de Texto) son objetos que especican un conjunto de atributos que se pueden aplicar
a un rango de texto en un TextBuffer. Cada TextBuffer tiene una TextTagTable (Tabla de Etiquetas de
Texto) que contiene las etiquetas disponibles en ese buffer. Las TextTagTables se pueden compartir entre
TextBuffers para ofrecer consistencia. Los TextTags normalmente se usan para cambiar la apariencia de un
rango de texto pero tambin pueden usarse para evitar que un rango de texto sea editado.
13.2. Vistas de Texto
Slo hay una funcin para crear un control TextView (Vista de Texto).
textview = gtk.TextView(buffer=None)
Cuando se crea una TextView tambin se crear un TextBuffer (Buffer de Texto) asociado y una
TextTagTable (Tabla de Etiquetas de Texto) de forma predeterminada. Si quieres usar un TextBuffer
ya existente puedes especicarlo en el mtodo anterior. Para cambiar el TextBuffer que usa una TextView usa
el siguiente mtodo:
textview.set_buffer(buffer)
Usa el siguiente mtodo para obtener una referencia al TextBuffer a partir de una TextView:
167
Captulo 13. Control de Vista de Texto
buffer = textview.get_buffer()
Un control de TextView no tiene barras de desplazamiento para ajustar la vista en caso de que el texto sea
ms grande que la ventana. Para incluir barras de desplazamiento, tienes que aadir la TextView a una
ScrolledWindow (Ventana de Desplazamiento).
Una TextView se puede usar para permitir al usuario editar un cuerpo de texto, o para visualizar varias lineas de
un texto de slo lectura para el usuario. Para cambiar entre estos modos de operacin, utiliza el siguiente mtodo:
textview.set_editable(valor)
El argumento valor puede ser TRUE o FALSE y especica si el usuario puede editar el contenido del control
TextView . El modo de edicin de la TextView puede cambiarse en rangos de texto dentro del TextBuffer
usando TextTags.
Puedes obtener el modo actual de edicin usando el mtodo:
setting = textview.get_editable()
Cuando la TextView no es editable probablemente deberas ocultar el cursor usando el mtodo:
textview.set_cursor_visible(valor)
El argumento valor puede ser TRUE o FALSE y especica si el cursor debe ser visible. La TextView puede
ajustar las lineas de texto que son demasiado largas para que quepan en una nica linea de la ventana. El
comportamiento predeterminado es no ajustar las lineas. Esto se puede cambiar usando el mtodo:
textview.set_wrap_mode(wrap_mode)
Este mtodo te permite especicar que el texto debe ajustarse en los lmites de palabras o caracteres. El argumento
word_wrap puede ser:
gtk.WRAP_NONE # sin ajuste
gtk.WRAP_CHAR # ajuste por caracteres
gtk.WRAP_WORD # ajuste por palabras
La justicacin predetermianda del texto en una TextView se puede jar y obtener usando los mtodos:
textview.set_justification(justification)
justification = textview.get_justification()
donde justification puede ser:
gtk.JUSTIFY_LEFT # justificacin a la izquierda
168
Captulo 13. Control de Vista de Texto
gtk.JUSTIFY_RIGHT # justificacin a la derecha
gtk.JUSTIFY_CENTER # justificacin al centro
Nota
La justificacin ser JUSTIFY_LEFT si el modo de ajuste es WRAP_NONE. Las etiquetas
asociadas con un TextBuffer pueden cambiar la justicacin predeterminada.
Se pueden modicar y ver otros atributos predeterminados en una TextView como el margen izquierdo, el margen
derecho, las tabulaciones y la indentacin de prrafos, usando los siguientes mtodos:
# margen izquierdo
textview.set_left_margin(left_margin)
left_margin = textview.get_left_margin()
# margen derecho
textview.set_right_margin(right_margin)
right_margin = textview.get_right_margin()
# indentacin
textview.set_indent(indent)
indent = textview.get_indent()
textview.set_pixels_above_lines(pixels_above_line)
pixels_above_line = textview.get_pixels_above_lines()
textview.set_pixels_below_lines(pixels_below_line)
pixels_below_line = textview.get_pixels_below_lines()
textview.set_pixels_inside_wrap(pixels_inside_wrap)
pixels_inside_wrap = textview.get_pixels_inside_wrap()
# tabulaciones
textview.set_tabs(tabs)
tabs = textview.get_tabs()
left_margin, right_margin, indent, pixels_above_lines, pixels_below_lines y
pixels_inside_wrap se especican en pxeles. Los valores predeterminados de estos parmetros se
pueden modicar con etiquetas asociadas a un TextBuffer. tabs es un pango.TabArray.
El programa de ejemplo textview-basic.py [examples/textview-basic.py] ilustra el uso bsico del control
TextView:
169
Captulo 13. Control de Vista de Texto
Figura 13.1. Ejemplo bsico de Vista de Texto
El cdigo fuente del programa es:
1 #!/usr/bin/env python
2
3 # example textview-basic.py
4
5 import gtk
6
7 class TextViewExample:
8 def toggle_editable(self, checkbutton, textview):
9 textview.set_editable(checkbutton.get_active())
10
11 def toggle_cursor_visible(self, checkbutton, textview):
12 textview.set_cursor_visible(checkbutton.get_active())
13
170
Captulo 13. Control de Vista de Texto
14 def toggle_left_margin(self, checkbutton, textview):
15 if checkbutton.get_active():
16 textview.set_left_margin(50)
17 else:
18 textview.set_left_margin(0)
19
20 def toggle_right_margin(self, checkbutton, textview):
21 if checkbutton.get_active():
22 textview.set_right_margin(50)
23 else:
24 textview.set_right_margin(0)
25
26 def new_wrap_mode(self, radiobutton, textview, val):
27 if radiobutton.get_active():
28 textview.set_wrap_mode(val)
29
30 def new_justification(self, radiobutton, textview, val):
31 if radiobutton.get_active():
32 textview.set_justification(val)
33
34 def close_application(self, widget):
35 gtk.mainquit()
36
37 def __init__(self):
38 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
39 window.set_resizable(gtk.TRUE)
40 window.connect("destroy", self.close_application)
41 window.set_title("TextView Widget Basic Example")
42 window.set_border_width(0)
43
44 box1 = gtk.VBox(gtk.FALSE, 0)
45 window.add(box1)
46 box1.show()
47
48 box2 = gtk.VBox(gtk.FALSE, 10)
49 box2.set_border_width(10)
50 box1.pack_start(box2, gtk.TRUE, gtk.TRUE, 0)
51 box2.show()
52
53 sw = gtk.ScrolledWindow()
54 sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
55 textview = gtk.TextView()
56 textbuffer = textview.get_buffer()
57 sw.add(textview)
58 sw.show()
59 textview.show()
60
61 box2.pack_start(sw)
62 # Load the file textview-basic.py into the text window
63 infile = open("textview-basic.py", "r")
64
65 if infile:
66 string = infile.read()
67 infile.close()
68 textbuffer.set_text(string)
69
70 hbox = gtk.HButtonBox()
71 box2.pack_start(hbox, gtk.FALSE, gtk.FALSE, 0)
72 hbox.show()
171
Captulo 13. Control de Vista de Texto
73
74 vbox = gtk.VBox()
75 vbox.show()
76 hbox.pack_start(vbox, gtk.FALSE, gtk.FALSE, 0)
77 # check button to toggle editable mode
78 check = gtk.CheckButton("Editable")
79 vbox.pack_start(check, gtk.FALSE, gtk.FALSE, 0)
80 check.connect("toggled", self.toggle_editable, textview)
81 check.set_active(gtk.TRUE)
82 check.show()
83 # check button to toggle cursor visiblity
84 check = gtk.CheckButton("Cursor Visible")
85 vbox.pack_start(check, gtk.FALSE, gtk.FALSE, 0)
86 check.connect("toggled", self.toggle_cursor_visible, textview)
87 check.set_active(gtk.TRUE)
88 check.show()
89 # check button to toggle left margin
90 check = gtk.CheckButton("Left Margin")
91 vbox.pack_start(check, gtk.FALSE, gtk.FALSE, 0)
92 check.connect("toggled", self.toggle_left_margin, textview)
93 check.set_active(gtk.FALSE)
94 check.show()
95 # check button to toggle right margin
96 check = gtk.CheckButton("Right Margin")
97 vbox.pack_start(check, gtk.FALSE, gtk.FALSE, 0)
98 check.connect("toggled", self.toggle_right_margin, textview)
99 check.set_active(gtk.FALSE)
100 check.show()
101 # radio buttons to specify wrap mode
102 vbox = gtk.VBox()
103 vbox.show()
104 hbox.pack_start(vbox, gtk.FALSE, gtk.FALSE, 0)
105 radio = gtk.RadioButton(None, "WRAP__NONE")
106 vbox.pack_start(radio, gtk.FALSE, gtk.TRUE, 0)
107 radio.connect("toggled", self.new_wrap_mode, textview, gtk.WRAP_NONE)
108 radio.set_active(gtk.TRUE)
109 radio.show()
110 radio = gtk.RadioButton(radio, "WRAP__CHAR")
111 vbox.pack_start(radio, gtk.FALSE, gtk.TRUE, 0)
112 radio.connect("toggled", self.new_wrap_mode, textview, gtk.WRAP_CHAR)
113 radio.show()
114 radio = gtk.RadioButton(radio, "WRAP__WORD")
115 vbox.pack_start(radio, gtk.FALSE, gtk.TRUE, 0)
116 radio.connect("toggled", self.new_wrap_mode, textview, gtk.WRAP_WORD)
117 radio.show()
118
119 # radio buttons to specify justification
120 vbox = gtk.VBox()
121 vbox.show()
122 hbox.pack_start(vbox, gtk.FALSE, gtk.FALSE, 0)
123 radio = gtk.RadioButton(None, "JUSTIFY__LEFT")
124 vbox.pack_start(radio, gtk.FALSE, gtk.TRUE, 0)
125 radio.connect("toggled", self.new_justification, textview,
126 gtk.JUSTIFY_LEFT)
127 radio.set_active(gtk.TRUE)
128 radio.show()
129 radio = gtk.RadioButton(radio, "JUSTIFY__RIGHT")
130 vbox.pack_start(radio, gtk.FALSE, gtk.TRUE, 0)
131 radio.connect("toggled", self.new_justification, textview,
172
Captulo 13. Control de Vista de Texto
132 gtk.JUSTIFY_RIGHT)
133 radio.show()
134 radio = gtk.RadioButton(radio, "JUSTIFY__CENTER")
135 vbox.pack_start(radio, gtk.FALSE, gtk.TRUE, 0)
136 radio.connect("toggled", self.new_justification, textview,
137 gtk.JUSTIFY_CENTER)
138 radio.show()
139
140 separator = gtk.HSeparator()
141 box1.pack_start(separator, gtk.FALSE, gtk.TRUE, 0)
142 separator.show()
143
144 box2 = gtk.VBox(gtk.FALSE, 10)
145 box2.set_border_width(10)
146 box1.pack_start(box2, gtk.FALSE, gtk.TRUE, 0)
147 box2.show()
148
149 button = gtk.Button("close")
150 button.connect("clicked", self.close_application)
151 box2.pack_start(button, gtk.TRUE, gtk.TRUE, 0)
152 button.set_flags(gtk.CAN_DEFAULT)
153 button.grab_default()
154 button.show()
155 window.show()
156
157 def main():
158 gtk.main()
159 return 0
160
161 if __name__ == "__main__":
162 TextViewExample()
163 main()
Las lineas 8-32 denen las retrollamadas para los botones de exclusin mtua y los botones de activacin que se
usan para cambiar los atributos predeterminados de la TextView. Las lineas 53-61 crean una ScrolledWindow
para contener la TextView. La ScrolledWindow se coloca en una VBox con los botones que se crean en las
lineas 70-138. El TextBuffer asociado con la TextView se rellena con el contenido del archivo fuente en las
lineas 62-68.
13.3. Buffers de Texto
El TextBuffer (Buffer de Texto) es el componente principal del sistema de edicin de texto de PyGTK. Contiene
el texto, las TextTag (Etiquetas de Texto) en una TextTagTable (Tabla de Etiquetas de Texto) y las TextMark
(Marcas de Texto) que juntos describen cmo debe visualizarse el texto y permiten al usuario modicar el texto
interactivamente. Como ya se dijo en la seccin anterior, un TextBuffer est asociado con una o ms TextView
(Vistas de Texto), que muestran el contenido del TextBuffer.
Un TextBuffer se puede crear automticamente cuando se crea una TextView o se puede crear con la funcin:
textbuffer = TextBuffer(tabla=None)
donde tabla es una TextTagTable. Si no se especica tabla (o si es None) una TextTagTable se crear para
el Buffer de Texto.
173
Captulo 13. Control de Vista de Texto
Hay un montn de mtodos que se pueden usar para:
insertar y borrar texto en un buffer
crear, borrar y manipular marcas
manipular el cursor y la seleccin
crear, aplicar y borrar etiquetas
especicar y manipular TextIter (Iteradores de Texto)
obtener informacin de estado
13.3.1. Informacin de estado de un Buffer de Texto
Puedes saber el nmero de lineas en un textbuffer usando el mtodo:
line_count = textbuffer.get_line_count()
De manera anloga puedes saber el nmero de caracteres en el textbuffer usando:
char_count = textbuffer.get_char_count()
Cuando el contenido del textbuffer cambia la bandera de modicacin del buffer de texto se activa. El estado
de la bandera de modicacin se puede consultar usando el mtodo:
modified = textbuffer.get_modified()
Si el programa guarda el contenido del buffer de texto el siguiente mtodo se puede usar para reiniciar la bandera
de modicacin:
textbuffer.set_modified(setting)
13.3.2. Creacin de Iteradores de Texto
Un TextIter se usa para especicar una localizacin dentro de un TextBuffer entre dos caracteres. Los
mtodos de TextBuffer que manipulan texto usan Iteradores de Texto para especicar dnde se aplicar el
mtodo. Los Iteradores de Texto tienen un gran nmero de mtodos que se describen en la seccin TextIter.
Los mtodos bsicos del TextBuffer que se usan para crear TextIters son:
iter = textbuffer.get_iter_at_offset(char_offset)
iter = textbuffer_get_iter_at_line(line_number)
iter = textbuffer.get_iter_at_line_offset(line_number, line_offset)
174
Captulo 13. Control de Vista de Texto
iter = textbuffer.get_iter_at_mark(mark)
get_iter_at_offset() crea un iterador que se situa despus de tantos caracteres como diga el argumento
char_offset a partir del comienzo del buffer de texto.
get_iter_at_line() crea un iterador que est justo antes del primer caracter en la linea que diga el parmetro
line_number.
get_iter_at_line_offset() crea un iterador que est justo detrs del carcter especicado por el parmetro
line_offset en la linea especicada por el parmetro line_number.
get_iter_at_mark() crea un iterador que est en la misma posicin que la marca especicada por el parmetro
mark.
Los siguientes mtodos crean uno o ms iteradores en localizaciones especcas del buffer de texto:
startiter = textbuffer.get_start_iter()
enditer = textbuffer_get_end_iter()
startiter, enditer = textbuffer.get_bounds()
start, end = textbuffer.get_selection_bounds()
get_start_iter() crea un iterador que est justo antes del primer caracter en el buffer de texto.
get_end_iter() crea un iterador que est justo despus del ltimo caracter en el buffer de texto.
get_bounds() crea una tupla de dos iteradores que estn justo antes del primer caracter y justo detrs del ltimo
caracter del buffer de texto respectivamente.
get_selection_bounds() crea una tupla de dos iteradores que estn en las mismas posiciones que las marcas
insert y selection_bound en el buffer de texto.
13.3.3. Insercin, Obtencin y Eliminacin de Texto
El texto de un TextBuffer se puede jar con el mtodo:
textbuffer.set_text(text)
Este mtodo reemplaza el contenido actual del buffer de texto con el texto que se le pasa como parmetro.
El mtodo ms general para insertar caracteres en un buffer de texto es:
textbuffer.insert(iter, text)
el cual inserta el texto text en la posicin del buffer de texto especicada por el iterador iter.
Si quieres simular la insercin de texto que producira un usuario interactivo usa este mtodo:
175
Captulo 13. Control de Vista de Texto
result = textbuffer.insert_interactive(iter, text, default_editable)
el cual inserta el texto text en la posicin del buffer de texto especicada por el iterador iter pero slo si la
posicin es editable (es decir, no tiene una etiqueta que especique que el texto no es editable) y el argumento
default_editable es TRUE. El resultado indica si el texto fue insertado o no.
El argumento default_editable indica si es editable o no cuando el texto no tiene una etiqueta que lo especi-
que; default_editable normalmente se determina llamando al mtodo get_editable() de TextView.
Otros mtodos que insertan texto son:
textbuffer.insert_at_cursor(text)
result = textbuffer.insert_at_cursor_interactive(text, default_editable)
textbuffer.insert_range(iter, start, end)
result = textbuffer.insert_range_interactive(iter, start, end, default_editable)
insert_at_cursor() es una funcin auxiliar que inserta el texto en la posicin actual del cursor.
insert_range() copia el texto, pixbuffers y etiquetas entre start y end de un TextBuffer (si las etiquetas
pertenecen a otro buffer de texto la tabla de etiquetas debe ser la misma) y los inserta en el buffer de texto en la
posicin especicada por iter.
Las versiones interactivas de estos mtodos funcionan de la misma forma excepto que slo insertarn el texto si
las posiciones son editables.
Finalmente, el texto se puede insertar y asociar a etiquetas al mismo tiempo usando los mtodos:
textbuffer.insert_with_tags(iter, text, tag1, tag2, ...)
textbuffer.insert_with_tags_by_name(iter, text, tagname1, tagname2, ...)
insert_with_tags() inserta el texto text en el buffer de texto en la posicin especicada por iter y le aplica
las etiquetas especicadas.
insert_with_tags_by_name() hace lo mismo pero te permite especicar las etiquetas por su nombre.
El texto de un buffer de texto se puede borrar usando los mtodos:
textbuffer.delete(start, end)
result = textbuffer.delete_interactive(start, end, default_editable)
delete() borra el texto entre los iteradores start y end en el buffer de texto.
delete_interactive() borra todo el texto editable (determinado por las etiquetas de texto aplicables y el
argumento default_editable ) entre start y end.
176
Captulo 13. Control de Vista de Texto
Puedes obtener una copia del texto de un buffer de texto usando los mtodos:
text = textbuffer.get_text(start, end, include_hidden_chars=TRUE)
text = textbuffer.get_slice(start, end, include_hidden_chars=TRUE)
get_text() devuelve una copia del texto en el buffer de texto entre start y end; si el argumento
include_hidden_chars es FALSE el texto que no se visualice no se devuelve. Los caracteres que
representan imgenes incrustadas o controles, son excluidos.
get_slice() es igual que get_text() excepto que el texto que devuelve incluye un carcter 0xFFFC por cada
imgene incrustada o control.
13.3.4. Marcas de Texto
Las TextMarks (Marcas de Texto) son similares a los TextIters ya que tambin especican posiciones en un
TextBuffer entre dos caracteres. Sin embargo, las Marcas de Texto mantienen su posicin aunque el buffer
cambie. Los mtodos de las Marcas de Texto se describirn en la seccin TextMark.
Un buffer de texto contiene dos marcas de fbrica: la marca insert (insertar) y la marca selection_bound
(lmite de la seleccin). La marca insert es la posicin predeterminada de insercin del texto y la marca
selection_bound combinada con la marca insert mark denen un rango de seleccin.
Las marcas de fbricas se pueden recuperar con los mtodos:
insertmark = textbuffer.get_insert()
selection_boundmark = textbuffer.get_selection_bound()
Las marcas insert y selection_bound se puden colocar simultneamente en una posicin usando el mtodo:
textbuffer.place_cursor(where)
where es un iterador de texto que especica la posicin. El mtodo place_cursor() es necesario para evitar
crear una seleccin temporal si las marcas se movieran individualmente.
Las TextMarks se crean usando el mtodo:
mark = textbuffer.create_mark(mark_name, where, left_gravity=FALSE)
donde mark_name es el nombre que se le asigna a la marca (puede ser None para crear una marca annima),
where es el iterador de texto que especica la posicin de la marca en el buffer de texto y left_gravity indica
dnde se pondr la marca cuando se inserte texto en la marca (a la izquierda si es TRUE o a la derecha si es
FALSE).
Se puede mover una marca en el buffer de texto usando los mtodos:
textbuffer.move_mark(mark, where)
177
Captulo 13. Control de Vista de Texto
textbuffer.move_mark_by_name(name, where)
mark especica la marca que se va a mover. name especica el nombre de la marca que se va a mover. where es
un iterador de texto qeu especica la nueva posicin.
Una marca se puede borrar de un buffer de texto usando los mtodos:
textbuffer.delete_mark(mark)
textbuffer.delete_mark_by_name(name)
Se puede recuperar una marca a partir de su nombre con el mtodo:
mark = textbuffer.get_mark(name)
13.3.5. Creacin y Uso de Etiquetas de Texto
Las TextTags (Etiquetas de Texto) contienen uno o ms atributos (por ejemplo, colores de frente y de fondo,
fuentes de texto, editabilidad) que se pueden aplicar a uno o ms rangos de texto en un buffer de texto. Los
atributos que se pueden especicar en una TextTag se describirn en la seccin TextTag .
Una TextTag se puede crear con atributos e instalada en la TextTagTable (Tabla de Etiquetas de Texto) de un
TextBuffer (Buffer de Texto) usando el siguiente mtodo:
tag = textbuffer.create_tag(name=None, attr1=val1, attr2=val2, ...)
donde name es una cadena de texto que especica el nombre de la etiqueta o None si la etiqueta es una etiqueta
annima y los pares de clave-valor especican los atributos que la etiqueta tendr. Mira la seccin TextTag para
ms informacin acerca de qu atributos se pueden establecer mediante las propiedades de una TextTag
Una etiqueta se puede aplicar a un rango de texto en un buffer de texto usando los mtodos:
textbuffer.apply_tag(tag, start, end)
textbuffer.apply_tag_by_name(name, start, end)
tag es la etiqueta que se va a aplicar al texto. name es el nombre de la etiqueta a aplicar. start (comienzo) y
end (nal) son los iteradores de texto que especican el rango de texto que ser afectado por la etiqueta.
Se puede borrar una etiqueta de un rango de texto usando los mtodos:
textbuffer.remove_tag(tag, start, end)
textbuffer.remove_tag_by_name(name, start, end)
Se pueden borrar todas las etiquetas de un rango de texto usando el mtodo:
178
Captulo 13. Control de Vista de Texto
textbuffer.remove_all_tags(start, end)
13.3.6. Insercin de Imgenes y Controles
Adems de texto, un TextBuffer puede contener imgenes y un punto de anclaje para controles. Se puede aadir
un control a una TextView en un punto de anclaje. Se puede aadir un control diferente en cada TextView que
tenga un buffer con un punto de anclaje.
Se puede insertar un pixbuf con el siguiente mtodo:
textbuffer.insert_pixbuf(iter, pixbuf)
donde iter especica la posicin en el textbuffer donde insertar el pixbuf. La imgen contar como un
caracter y ser representada en lo que devuelve get_slice() (pero no en lo que devuelve get_text() ) como el
caracter Unicode "0xFFFC".
Un control GTK+ se puede insertar en una TextView en una posicin del buffer especicada por un
TextChildAnchor (Anclaje de Hijo del Texto). El TextChildAnchor contar como un carcter representado
por "0xFFFC" de manera similar a un pixbuf.
El TextChildAnchor se puede crear e insertar en el buffer usando este mtodo:
anchor = text_buffer.create_child_anchor(iter)
donde iter es la posicin del anclaje.
Tambin se puede crear e insertar un TextChildAnchor con dos operaciones por separado:
anchor = gtk.TextChildAnchor()
text_buffer.insert_child_anchor(iter, anchor)
Despus se puede aadir el control al TextView en la posicin del anclaje usando el mtodo:
text_view.add_child_at_anchor(child, anchor)
Se puede obtener la lista de controles en una posicin especica del buffer usando el mtodo:
widget_list = anchor.get_widgets()
Tambin se puede aadir un control al TextView usando el mtodo:
text_view.add_child_in_window(child, which_window, xpos, ypos)
179
Captulo 13. Control de Vista de Texto
donde el controle child se coloca en la ventana which_window en la posicin especicada por xpos e ypos.
El parmetro which_window indica en cul de las ventanas que componen el control TextView se colocar el
control:
gtk.TEXT_WINDOW_TOP # ventana superior del texto
gtk.TEXT_WINDOW_BOTTOM # ventana inferior del texto
gtk.TEXT_WINDOW_LEFT # ventana izquierda del texto
gtk.TEXT_WINDOW_RIGHT # ventana derecha del texto
gtk.TEXT_WINDOW_TEXT # ventana de texto del texto
gtk.TEXT_WINDOW_WIDGET # ventana de control del texto
13.4. Iteradores de Texto
Los TextIters (Iteradores de Texto) representan una posicin entre dos caracteres en un TextBuffer. Los
TextIters se crean normalmente usando un mtodo de la clase TextBuffer. Los TextIters se invalidan
cuando el nmero de caracteres de un TextBuffer cambia (excepto para el TextIter que se usa para insercin
o borrado). Insertar o borrar pixbuffers o anclajes tambin invalidan un TextIter .
Hay un gran nmero de mtodos asociados con un objeto TextIter . Se agrupan en las siguientes secciones
segn funciones similares.
13.4.1. Atributos de los Iteradores de Texto
El TextBuffer que contiene el TextIter se puede recuperar usando el mtodo:
buffer = iter.get_buffer()
Los siguientes mtodos se pueden usar para obtener la posicin del TextIter en el TextBuffer:
offset = iter.get_offset() # devuelve el desplazamiento en el buffer
line_number = iter.get_line() # devuelve el nmero de linea
line_offset = iter.get_line_offset() # devuelve el desplazamiento en la linea
numchars = iter.get_chars_in_line() # devuelve el nmero de caracteres en la linea
13.4.2. Atributos de Texto de un Iterador de Texto
El objeto PangoLanguage que se usa en una determinada posicin del iterador en el TextBuffer se obtiene
llamando al mtodo:
language = iter.get_language()
Hay otro mtodo ms general para obtener los atributos de texto en una posicin de un TextIter :
result = iter.get_attributes(values)
180
Captulo 13. Control de Vista de Texto
donde result indica si el parmetro values (un objeto de la clase TextAttributes ) fue modicado. El
parmetro values se obtiene usando el siguiente mtodo de la clase TextView :
values = textview.get_default_attributes()
Los siguientes atributos se pueden obtener a partir de un objeto de la clase TextAttributes (no est implemen-
tado en PyGTK <=1.99.15):
bg_color color de fondo
fg_color color de frente
bg_stipple bitmap de patrn de fondo
fg_stipple bitmap de patrn de frente
rise desplazamiento del texto sobre la linea base
underline estilo de subrayado
strikethrough indica si el texto aparece tachado
draw_bg TRUE si algunas banderas afectan al dibujado del fondo
justication estilo de la justicacin
direction la direccin del texto
font PangoFontDescription en uso
font_scale escala de la fuente en uso
left_margin posicin del mrgen izquierdo
right_margin posicin del mrgen derecho
pixels_above_lines espacio en pxeles sobre una linea
pixels_below_lines espacio en pxeles debajo de una linea
pixels_inside_wrap espacio en pxeles entre lineas solapadas
tabs PangoTabArray en uso
wrap_mode modo de ajuste en uso
language PangoLanguage en uso
invisible si el texto es invisible (sin implementar en GTK+ 2.0)
bg_full_height si el fondo est ocupando el alto completo de linea
editable si el texto es editable
realized si el texto est realizado
pad1
pad2
pad3
pad4
13.4.3. Copiar un Iterador de Texto
Se puede duplicar un TextIter usando el mtodo:
iter_copy = iter.copy()
13.4.4. Recuperar Texto y Objetos
Se pueden obtener varias cantidades de texto y objetods de un TextBuffer usando los siguientes mtodos
TextBuffer :
char = iter.get_char() # devuelve un caracter o 0 si se ha llegado al final del buffer
text = start.get_slice(end)
# devuelve el texto entre los iteradores de principio y fin
181
Captulo 13. Control de Vista de Texto
text = start.get_text(end) # devuelve el texto entre los iteradores de principio y fin
pixbuf = iter.get_pixbuf() # devuelve el pixbuf en esa posicin (o None)
anchor = iter.get_child_anchor() # devuelve el anclaje (o None)
mark_list = iter.get_marks() # devuelve una lista de marcas
tag_list = iter.get_toggled_tags()
# devuelve una lista de etiquetas que estn activadas o desactivadas
tag_list = iter.get_tags() # devuelve una lista de etiquetas por prioridades
13.4.5. Comprobar Condiciones en un Iterador de Texto
Las condiciones de una etiqueta en un TextIter se pueden comprobar usando los siguientes mtodos:
result = iter.begins_tag(tag=None) # TRUE si la etiqueta est activada en el iterador
result = iter.ends_tag(tag=None)
# TRUE si la etiqueta est desactivada en el iterador
result = iter.toggles_tag(tag=None)
# TRUE si la etiqueta est activa o desactivada en el iterador
result = iter.has_tag(tag) # TRUE si existe la etiqueta en el iterador
Estos mtodos devuelven TRUE si el parmetro tag satisface la condicin en el iter. Si el parmetro tag es
None en los primeros tres mtodos entonces el resultado es TRUE si cualquier etiqueta satisface la condicin en
el iterador.
Los siguientes mtodos indican si el texto en la posicin del iterador es editable o permite insercin de texto:
result = iter,editable()
result = iter.can_insert(default_editability)
El mtodo editable() indica si el iter est en un rango editable de texto mientras que el mtodo can_insert()
indica si el texto se puede insertar en el iter considerando la editabilidad predeterminada de la TextView, el
TextBuffer y las etiquetas aplicables. La editabilidad predeterminada se obtiene con el mtodo:
default_editability = textview.get_editable()
La equivalencia de dos TextIters se puede determinar con el mtodo:
are_equal = lhs.equal(rhs)
Dos TextIters se pueden comparar con el mtodo:
182
Captulo 13. Control de Vista de Texto
result = lhs.compare(rhs)
El result ser: -1 si lhs es menor que rhs; 0 si lhs es igual que rhs; y, 1 si lhs es mayor que rhs.
Para determinar si un TextIter est entre otros dos TextIters usa el mtodo:
result = iter.in_range(start, end)
El result ser TRUE si iter est entre start y end. Atencin: start y end deben estar en un orden
ascendente. Esto se puede garantizar con el mtodo:
first.order(second)
que reordenar los desplazamientos para que first est antes que second.
13.4.6. Comprobar la localizacin de un Iterador de Texto
La posicin de un TextIter con respecto al texto en un TextBuffer se puede determinar con los siguientes
mtodos:
result = iter.starts_word() # empieza palabra
result = iter.ends_word() # termina palabra
result = iter.inside_word() # dentro de palabra
result = iter.starts_sentence() # empieza frase
result = iter.ends_sentence() # termina frase
result = iter.inside_sentence() # dentro de frase
result = starts_line() # empieza linea
result = iter.ends_line() # termina linea
result ser TRUE si el TextIter est en la posicin dada. Estos mtodos son autoexplicativos. La denicin
de los elementos de texto y sus lmites se determina por el lenguaje usado en el TextIter. Fjate que una linea
es una coleccin de frases similar a un prrafo.
Los siguientes mtodos se pueden usar para determinar si un TextIter est al principio o al nal de un
TextBuffer:
result = iter.is_start()
result = iter.is_end()
result es TRUE si el TextIter est al principio o al nal del TextBuffer.
183
Captulo 13. Control de Vista de Texto
Ya que un TextBuffer puede contener mltiples caracteres que se visualizan efectivamente como una posicin
del cursor (por ejemplo retorno de carro y nueva linea o una letra con un smbolo de acento) es posible que un
TextIter podra estar en una posicin que no corresponde con una posicin de cursor. El siguiente mtodo
indica si un iterador est en una posicin del cursor:
result = iter.is_cursor_position()
13.4.7. Movimiento a travs del Texto
Los TextIters se pueden mover por un TextBuffer en varias unidades de texto. La denicin de las unidades
de texto se establece en el objeto PangoLanguage que se use en la posicin del TextIter . Los mtodos bsicos
son:
result = iter.forward_char() # avanzar un caracter
result = iter.backward_char() # retroceder un caracter
result = iter.forward_word_end() # avanzar hasta el final de la palabra
result = iter.backward_word_start() # retroceder al principio de la palabra
result = iter.forward_sentence_end() # avanzar al final de la frase
result = iter.backward_sentence_start() # retroceder al principio de la frase
result = iter.forward_line() # avanzar al principio de la linea
result = iter.backward_line() # retroceder al principio de la linea
result = iter.forward_to_line_end() # avanzar al final de la linea
result = iter.forward_cursor_position() # avanzar una posicin del cursor
result = iter.backward_cursor_position() # retroceder una posicin del cursor
result es TRUE si el TextIter se movi y FALSE si el TextIter est al principio o al nal del TextBuffer.
Todos estos mtodos (excepto forward_to_line_end()) tiene mtodos equivalentes que reciben una cantidad
(que puede ser positiva o negativa) para mover el TextIter en mltiples unidades de texto:
result = iter.forward_chars(count)
result = iter.backward_chars(count)
result = iter.forward_word_ends(count)
result = iter.backward_word_starts(count)
result = iter.forward_sentence_ends(count)
result = iter.backward_sentence_starts(count)
result = iter.forward_lines(count)
184
Captulo 13. Control de Vista de Texto
result = iter.backward_lines(count)
result = iter.forward_cursor_positions(count)
result = iter.backward_cursor_positions(count)
13.4.8. Moverse a una Posicin Especca
Un TextIter se puede mover a una posicin especca en el TextBuffer usando los siguientes mtodos:
iter.set_offset(char_offset) # moverse al desplazamiento de caracteres especfico
iter.set_line(line_number) # moverse al principio de la linea dada como parmetro
iter.set_line_offset(char_on_line)
# moverse al caracter especificado en la linea actual
iter.forward_to_end() # moverse al final del buffer
Adems, un TextIter se puede mover a una posicin donde una etiqueta est activada o desactivada usando los
mtodos:
result = iter.forward_to_tag_toggle(tag)
result = iter.backward_to_tag_taoggle(tag)
result es TRUE si el TextIter se movi a la nueva posicin donde exista la etiqueta tag . Si la etiqueta tag
es None entonces el TextIter se mover a la siguiente posicin donde exista una etiqueta.
13.4.9. Buscar en el Texto
Una bsqueda de una cadena de texto en un TextBuffer se hace con los siguientes mtodos:
match_start, match_end = iter.forward_search(str, flags, limit=None) # bsqueda

hacia adelante
match_start, match_end = iter.backward_search(str, flags, limit=None) # bsqueda

hacia atrs
El valor de retorno es una tupla que contiene los TextIters que indican la posicin del primer caracter que
coincide con la bsqueda y la posicin del primer caracter despus del encuentro. str es la cadena a buscar. El
parmetro flags modica las condiciones de la bsqueda y puede tomar los siguientes valores:
gtk.TEXT_SEARCH_VISIBLE_ONLY # se ignoran los caracteres invisibles
gtk.TEXT_SEARCH_TEXT_ONLY # se ignoran los pixbuffers y los anclajes de hijos
limit es un parmetro opcional que limita el rango de la bsqueda.
185
Captulo 13. Control de Vista de Texto
13.5. Marcas de Texto
Una TextMark (Marca de Texto) indica una posicin en un TextBuffer entre dos caracteres que se mantiene
aunque se modique el buffer. Las TextMarks se crean, se mueven y se borran usando los mtodos del
TextBuffer que se describen en la seccin TextBuffer .
Un TextBuffer tiene dos marcas de fbrica llamadas: insert y selection_bound que se reeren al punto de
insercin y el lmite de la seleccin (puede que se reeran a la misma posicin).
El nombre de una TextMark se puede recuperar usando el mtodo:
name = textmark.get_name()
Por defecto las marcas que no son insert no son visibles (esa marca se muestra como una barra vertical). La
visibilidad de una marca se puede activar y obtener usando los mtodos:
setting = textmark.get_visible()
textmark.set_visible(setting)
donde setting es TRUE si la marca es visible.
El TextBuffer que contiene una TextMark se puede recuperar usando el mtodo:
buffer = textmark.get_buffer()
Puedes determinar si una TextMark ha sido borrada usando el mtodo:
setting = textmark.get_deleted()
La gravedad izquierda de una TextMark se puede recuperar usando el mtodo:
setting = textmark.get_left_gravity()
La gravedad izquierda de una TextMark indica si donde acabar la marca despus de una insercin. Si la gravedad
izquierda es TRUE la marca se pondr a la izquierda de la insercin; si es FALSE, a la derecha de la insercin
13.6. Etiquetas de Texto y Tablas de Etiquetas
Las etiquetas de texto especican atributos que se pueden aplicar a un rango de texto en un buffer de texto. Cada
buffer de texto tiene una tabla de etiquetas de texto que contiene las etiquetas de texto que se pueden aplicar dentro
del buffer. Las tablas de etiquetas de texto se pueden usar en ms de un buffer de texto para ofrecer estilos de texto
consistentes.
13.6.1. Etiquetas de Texto
Las TextTags (Etiquetas de Texto) pueden tener nombre o ser annimas. Una TextTag se crea usando la funcin:
186
Captulo 13. Control de Vista de Texto
tag = gtk.TextTag(name=None)
Si el name (nombre) no se especica o si es None la tag (etiqueta) ser annima. Las TextTags tambin se
pueden crear usando el mtodo de TextBuffer create_tag() que tambin te permite especicar los atributos y
aade la etiqueta a la tabla de etiquetas del buffer (vese la subseccin TextBuffer).
Los atributos que pueden aparecer en una TextTag son:
187
Captulo 13. Control de Vista de Texto
name Lectura / Escrit-
ura
Nombre de la etiqueta de texto. None si es annima.
background Escritura Color de fondo como una cadena de texto
foreground Escritura Color de frente como una cadena de texto
background-gdk Lectura / Escrit-
ura
Color de fondo como un GdkColor
foreground-gdk Lectura / Escrit-
ura
Color de frente como un GdkColor
background-stipple Lectura / Escrit-
ura
Bitmap a usar como una mscara cuando se dibuje el texto de fondo
foreground-stipple Lectura / Escrit-
ura
Bitmap a usar como una mscara cuando se dibuje el texto de frente
font Lectura / Escrit-
ura
Descripcin de la fuente como una cadena de texto, por ejemplo, "Sans
Italic 12"
font-desc Lectura / Escrit-
ura
Descripcin de la feunte como un objeto PangoFontDescription
family Lectura / Escrit-
ura
Nombre de la familia de la fuente, por ejemplo, Sans, Helvetica, Times,
Monospace
style Lectura / Escrit-
ura
Estilo de la fuente como un PangoStyle, por ejemplo,
PANGO_STYLE_ITALIC.
variant Lectura / Escrit-
ura
Variante de la fuente como un PangoVariant, por ejemplo,
PANGO_VARIANT_SMALL_CAPS.
weight Lectura / Escrit-
ura
Peso de la fuente como un entero, mira los valores predenidos en
PangoWeight; por ejemplo, PANGO_WEIGHT_BOLD.
stretch Lectura / Escrit-
ura
Estrechamiento de la fuente como un PangoStretch, por ejemplo,
PANGO_STRETCH_CONDENSED.
size Lectura / Escrit-
ura
Tamao de fuente en unidades Pango.
size-points Lectura / Escrit-
ura
Tamao de fuente en puntos
scale Lectura / Escrit-
ura
Tamao de fuente como un factor de escala relativo al tamao de fuente
predeterminado. Esta propiedad se adapta a los cambios en el tema, etc,
por tanto se recomienda su uso. Pango tiene algunos valores predenidos
tales como PANGO_SCALE_X_LARGE.
pixels-above-lines Lectura / Escrit-
ura
Pxeles de espacio blanco por encima de los prrafos
pixels-below-lines Lectura / Escrit-
ura
Pxeles de espacio blanco por debajo de los prrafos
pixels-inside-wrap Lectura / Escrit-
ura
Pxeles de espacio blanco entre las lineas de un prrafo
editable Lectura / Escrit-
ura
Si el texto puede modicarse por el usuario
wrap-mode Lectura / Escrit-
ura
Si las lineas no se ajustan, se ajustan en limites de palabra o se ajustan
en limites de caracteres
justication Lectura / Escrit-
ura
Justicacin izquierda, derecha o central
direction Lectura / Escrit-
ura
Direccin del Texto, por ejemplo, derecha a izquierda o izquierda a
derecha
left-margin Lectura / Escrit-
ura
Ancho del mrgen izquierdo en pxeles
indent Lectura / Escrit-
ura
Cantidad de indentado para los prrafos, en pxeles
strikethrough Lectura / Escrit-
ura
Si hay que tachar el texto
right-margin Lectura / Escrit-
ura
Ancho del mrgen derecho en pxeles
underline Lectura / Escrit-
ura
Estilo de subrayado para este texto
rise Lectura / Escrit-
ura
Desplazamiento del texto por encima de la linea base (por debajo de la
linea base si es negativo) en pxeles
background-full-height Lectura / Escrit-
ura
Si el color de fondo rellena la altura completa de la linea o slo la altura
de los caracteres marcados
language Lectura / Escrit-
ura
El idioma en el que est el texto, como un cdigo ISO. Pango puede
usar esto como una ayuda para visualizar el texto. Si no entiendes este
parmetro, probablemente no lo necesitas.
tabs Lectura / Escrit-
ura
Tabulaciones personalizadas para el texto
invisible Lectura / Escrit-
ura
Si el texto est oculto. No implementado en GTK 2.0
188
Captulo 13. Control de Vista de Texto
Se pueden establecer los atributos con este mtodo:
tag.set_property(name, value)
Donde name es una cadena de texto que contiene el nombre de la propiedad y value es el valor que se le va a
poner.
De la misma forma, el valor de un atributo se puede recuperar con el mtodo:
value = tag.get_property(name)
Ya que la etiqueta no tiene un valor para cada atributo hay una serie de propiedades booleanas que indican si el
atributo ha sido establecido:
background-set Lectura / Escritura
foreground-set Lectura / Escritura
background-stipple-set Lectura / Escritura
foreground-stipple-set Lectura / Escritura
family-set Lectura / Escritura
style-set Lectura / Escritura
variant-set Lectura / Escritura
weight-set Lectura / Escritura
stretch-set Lectura / Escritura
size-set Lectura / Escritura
scale-set Lectura / Escritura
pixels-above-lines-set Lectura / Escritura
pixels-below-lines-set Lectura / Escritura
pixels-inside-wrap-set Lectura / Escritura
editable-set Lectura / Escritura
wrap-mode-set Lectura / Escritura
justication-set Lectura / Escritura
direction-set Lectura / Escritura
left-margin-set Lectura / Escritura
indent-set Lectura / Escritura
strikethrough-set Lectura / Escritura
right-margin-set Lectura / Escritura
underline-set Lectura / Escritura
rise-set Lectura / Escritura
background-full-height-set Lectura / Escritura
language-set Lectura / Escritura
tabs-set Lectura / Escritura
invisible-set Lectura / Escritura
Por tanto, para obtener el atributo de una etiqueta, primero tienes que comprobar si el atributo ha sido establecido
en la etiqueta. Por ejemplo, para obtener un valor vlido de justicacin tienes que hacer algo as como:
if tag.get_property("justification-set"):
justification = tag.get_property("justification")
La prioridad predeterminada de una etiqueta es el orden en el que se aade a la TextTagTable. Las etiquetas con
prioridad ms alta tienen preferencia si hay mltiples etiquetas para establecer el mismo atributo para un rango de
texto. La prioridad se puede obtener y jar con los mtodos:
189
Captulo 13. Control de Vista de Texto
priority = tag.get_priority()
tag.set_priority(priority)
La prioridad de una etiqueta debe estar entre 0 y uno menos del tamao de la TextTagTable.
13.6.2. Tablas de Etiquetas de Texto
Una TextTagTable (Tabla de Etiquetas de Texto) se crea al crear un TextBuffer . Tambin se puede crear una
TextTagTable con la funcin:
table = TextTagTable()
Se puede aadir una TextTag (Etiqueta de Texto) a una TextTagTable usando el mtodo:
table.add(tag)
La etiqueta tag no debe estar ya en la tabla y no debe tener el mismo nombre que otra etiqueta en la tabla.
Puedes buscar una etiqueta en una tabla usando el mtodo:
tag = table.lookup(name)
El mtodo devuelve la etiqueta tag en la tabla que tenga el nombre name o None si no hay ninguna etiqueta con
ese nombre.
Se puede borrar una TextTag de una TextTagTable con el mtodo:
table.remove(tag)
El tamao de la TextTagTable se puede consultar con el mtodo:
size = table.get_size()
13.7. Un ejemplo de Vista de Texto
El programa de ejemplo testtext.py [examples/testtext.py] (que se deriva del programa testtext.c incluido
en la distribucin GTK+ 2.0.x) demuestra el uso del control TextView y sus objetos asociados: TextBuffers,
TextIters, TextMarks, TextTags, TextTagTables. La gura Figura 13.2. Ejemplo de Vista de Texto ilustra
su funcionamiento:
190
Captulo 13. Control de Vista de Texto
Figura 13.2. Ejemplo de Vista de Texto
El programa testtext.py [examples/testtext.py] dene unas cuantas clases adems de la clase principal TestText:
La clase Buffer , en las lineas 99-496, es una subclase de la clase gtk.TextBuffer . Proporciona las
capacidades de edicin del buffer que usan los objetos View.
191
Captulo 13. Control de Vista de Texto
La clase View , lineas 498-1126, es una subclase de la clase gtk.Window y contiene un objeto gtk.TextView
que usa un objeto Buffer en lugar de un objeto gtk.TextBuffer . Proporciona una ventana y visualiza los
contenidos de un objeto Buffer adems de una barra de men.
La clase FileSel , lineas 73-97, es una subclase de la clase gtk.FileSelection para proporcionar una
seleccin de cheros para los contenidos de la clase Buffer .
La clase Stack proporciona objetos de pilas simples.
La ventana de ciclo de color se implementa usando etiquetas de texto que se aplican a una seccin del texto
en un buffer. Las lineas 109-115 (en el mtodo __init__() ) crean estas etiquetas y las lineas 763-784 (en el
mtodo do_apply_colors() ) aplican las etiquetas de colores a una seccin del texto de dos en dos caracteres.
Las lienas 202-239 proporcionan los mtodos (color_cycle_timeout(), set_colors() y cycle_colors())
que producen el ciclo de color cuando est activado. El ciclo de color se activa estableciendo (linea 220) la
propiedad foreground_gdk de las etiquetas individuales color_tags (que tambin establecen la propiedad
foreground_set ). El ciclo de color se desactiva poniendo la propiedad foreground_set a FALSE (linea
222). Los colores se cambian periodicamente al desplazar el tono del color ( start_hue (line 237))
Un nuevo Buffer se rellena con un contenido de ejemplo cuando se selecciona el men Test->Example (el mtodo
fill_example_buffer() en las lineas 302-372). El buffer de ejemplo contien texto de varios colores, estilos,
idiomas y pixbuffers. El mtodo init_tags() (lineas 260-300) establece una variedad de TextTags para usarlas
con el texto de ejemplo. La seal de evento de estas etiquetas se conecta al mtodo tag_event_handler()
(lineas 241-256) para ilustrar la captura de los eventos de botn y movimiento.
El modo de ajuste del control TextView est puesto a WRAP_WORD (linea 580) y las ventanas de borde del
TextView se visualizan al establecer su tamao en las lineas 587-588 y las lineas 596-597. Las ventanas del borde
derecho e izquierdo se usan para mostrar los nmeros de linea y las ventanas de borde superior e inferior muestran
las posiciones de tabulacin cuando se utilizan tabulaciones personalizadas. Las ventanas de borde se actualizan
cuando se recibe la seal "expose-event" en el TextView (lineas 590 y 599) El mtodo line_numbers_expose()
(lineas 1079-1116) determina si las ventanas de borde izquierdo o derecho tienen un evento de exposicin y si es
as calculan el tamao del rea de exposicin. Entonces la localizacin del principio de la linea y el nmero de
linea para cada linea en el rea de exposicin se calcula en el mtodo get_lines() (lineas 1057-1077). Los
nmeros de linea se dibujan en la ventana de borde en la posicin (transformada por la linea 1109).
Las posiciones personalizadas de tabulacin se visualizan en las ventanas de borde superior e inferior de una
forma similar (lineas 1013-1055). Slo se visualizan cuando el cursor se mueve dentro de un rango de texto
que tiene el atributo de tabulaciones propias. Esto se detecta manejando la seal "mark-set" en el mtodo
cursor_set_handler() (lineas 999-1011) e invalidando las ventanas de borde superior e inferior si la marca a
activar es la marca insert .
Los controles movibles se aaden al objeto View con el mtodo do_add_children() (lineas 892-899) el cual
llama al mtodo add_movable_children() (lines 874-890). Los hijos son gtk.Labels (Etiquetas) que pueden
arrastrarse por las ventanas que forman parte de un control TextView .
De la misma forma, los controles se aaden a las ventanas del TextView de una View y el Buffer usando el
mtodo do_add_focus_children() (lineas 901-949).
192
Captulo 14. Control de Vista de rbol
Este captulo estar disponible en una fecha futura.
193
Captulo 15. Controles sin documentar
Todos estos controles necesitan voluntarios! :) Por favor, considerad contribuir a nuestro tutorial.
Si tienes que usar alguno de estos controles que estn sin documentar, te recomiendo encarecidamente que le
eches un vistazo a los archivos *.c en la distribucin de PyGTK. Los nombres de los mtodos de PyGTK son muy
descriptivos. Una vez que entiendes como funcionan las cosas, no es muy difcil averiguar como usar un control
simplemente mirando la denicin de sus mtodos. Esto, adems de algunos ejemplos del cdigo de otros, no
debera ser un problema.
Cuando realmente entiendas todos los mtodos de un nuevo control sin documentar, por favor piensa en escribir
un tutorial sobre l para que otros puedan beneciarse de tu tiempo.
15.1. Etiqueta de Aceleracin
15.2. Men de Opciones
15.3. Elementos de Men
15.3.1. Elemento de Men de Activacin
15.3.2. Elemento de Men de Exclusin Mtua
15.3.3. Elemento de Men de Separacin
15.3.4. Elemento de Men de Cascada
15.4. Curvas
15.5. Dilogo de Mensaje
15.6. Curva Gamma
15.7. Enchufes y Clavijas
194
Captulo 16. Cambiar Atributos de
Controles
Este captulo describe los mtodos usados para modicar controles (y en objetos). Esto puede ser usado para
cambiar el estilo, el espaciamiento, el tamao, etc.
El mtodo:
widget.activate()
hace que el control emita la seal "activate".
El mtodo:
widget.set_sensitive(sensitive)
cambia la sensitivadd del control (es decir, si reacciona a eventos). Si sensitive es TRUE el control recibir
eventos; si es FALSE el control no recibir eventos. Un control que est insensitivo normalmente se visualiza en
un tono gris.
El mtodo:
widget.set_size_request(width, height)
establece el tamao del control para que tenga el ancho dado por el parmetro width y el alto dado por el
parmetro height.
16.1. Mtodos de Banderas de Controles
Los mtodos:
widget.set_flags(flags)
widget.unset_flags(flags)
flags = widget.flags()
ponen, quitan y leen las banderas de los objetos gtk.Object y gtk.Widget . Las flags (banderas) pueden ser
cualquiera de las banderas estandar:
IN_DESTRUCTION # en destruccin
FLOATING # flotando
RESERVED_1 # reservada 1
RESERVED_2 # reservada 2
TOPLEVEL # nivel ms alto
NO_WINDOW # no ventana
REALIZED # realizado
195
Captulo 16. Cambiar Atributos de
Controles
MAPPED # mapeado
VISIBLE # visible
SENSITIVE # sensitivo
PARENT_SENSITIVE # padre sensitivo
CAN_FOCUS # puede recibir el foco
HAS_FOCUS # tiene el foco
CAN_DEFAULT # puede ser el control predeterminado
HAS_DEFAULT # es el control predeterminado
HAS_GRAB # tiene la exclusividad de los eventos
RC_STYLE # estilo rc
COMPOSITE_CHILD # hijo compuesto
NO_REPARENT # no reparentado
APP_PAINTABLE # aplicacin pintable
RECEIVES_DEFAULT # recibe predeterminado
DOUBLE_BUFFERED # tiene doble buffer
El mtodo:
widget.grab_focus()
permite a un control adquirir el foco asumiendo que tiene la bandera CAN_FOCUS activada.
16.2. Mtodos de Visualizacin de Controles
Los mtodos:
widget.show()
widget.show_all()
widget.hide()
widget.hide_all()
widget.realize()
widget.unrealize()
widget.map()
widget.unmap()
controlan la visualizacin de los controles.
El mtodo show() (mostrar) hace que el control se visualice al llamar a los mtodos realize() y map() .
El mtodo hide() (ocultar) hace que el control se oculte y tambin lo desmapea usando el mtodo unmap() si es
necesario.
Los mtodos show_all() (mostrar todos) y hide_all() (ocultar todos) hacen que el control y todos sus hijos se
muestren o se oculten.
El mtodo realize() (realizar) hace que se reserven los recursos que necesita el control incluyendo su ventana.
196
Captulo 16. Cambiar Atributos de
Controles
El mtodo unrealize() (desrealizar) libera la ventana del control y otros recursos. Desrealizar un control tambin
lo oculta y desmapea.
El mtodo map() (mapear) hace que se reserve espacio en la pantalla para el control; esto slo se aplica a los
controles que necesitan ser manipulados por el manejador de ventanas. Mapear un control tambin lo realiza si es
necesario.
El mtodo unmap() (desmapear) elimina un control de la pantalla y tambin lo oculta si es necesario.
16.3. Atajos de Teclador de Controles
Los siguientes mtodos:
widget.add_accelerator(accel_signal, accel_group, accel_key, accel_mods, accel_flags)
widget.remove_accelerator(accel_group, accel_key, accel_mods)
aaden y eliminan atajos de tecla a un gtk.AcceleratorGroup (Grupo de Atajos de Teclado) que deben
asociarse al control de nivel ms alto para manejar los atajos de teclado.
El parmetro accel_signal es una seal que el control puede emitir.
El parmetro accel_key es una tecla del teclado para usarla como atajo de teclado.
El parmetro accel_mods es un grupo de modicadores que se aaden a la tecla accel_key (por ejemplo Shift
(maysculas), Control, etc.):
SHIFT_MASK
LOCK_MASK
CONTROL_MASK
MOD1_MASK
MOD2_MASK
MOD3_MASK
MOD4_MASK
MOD5_MASK
BUTTON1_MASK
BUTTON2_MASK
BUTTON3_MASK
BUTTON4_MASK
BUTTON5_MASK
RELEASE_MASK
El parmetro accel_flags es un conjunto de opciones sobre cmo se muestra la informacin del atajo de teclado.
Los valores vlidos son:
ACCEL_VISIBLE # mostrar la tecla de aceleracin en el control
ACCEL_LOCKED # no permitir que la ventana del atajo de teclado cambie
Un grupo de atajos de teclado se crea con la funcin:
197
Captulo 16. Cambiar Atributos de
Controles
accel_group = gtk.AccelGroup()
El grupo accel_group se aade una ventana de alto nivel con el siguiente mtodo:
window.add_accel_group(accel_group)
Ejemplo de cmo aadir un atajo de teclado:
menu_item.add_accelerator("activate", accel_group,
ord(Q), gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE)
16.4. Mtodos para el Nombre de los Controles
Los siguientes mtodos de controles cambian y leen el nombre de un control:
widget.set_name(name)
name = widget.get_name()
El parmetro name es la cadena de caracteres que se asocia al control. Esto es til para especicar estilos que
se usan en controles especcos dentro de una aplicacin. El nombre del control puede usarse para limitar la
aplicacin del estilo a diferencia de usar la clase del control. Mira el captulo sobre cmo usar cheros rc de GTK
para ms informacin.
16.5. Estilos de Controles
Los siguientes mtodos cambian y leen el estilo asociado a un control:
widget.set_style(style)
style = widget.get_style()
La siguiente funcin:
style = get_default_style()
obtiene el estilo predeterminado.
Un estilo contiene la informacin grca que necesita un control para dibujarse a s mismo en sus diferentes
estados:
STATE_NORMAL # El estado durante la operacin normal
STATE_ACTIVE # El control est activado, como cuando se pulsa un botn
STATE_PRELIGHT # El puntero del ratn est sobre el control
STATE_SELECTED # El control est seleccionado
198
Captulo 16. Cambiar Atributos de
Controles
STATE_INSENSITIVE # El control est desactivado
Un estilo contiene los siguientes atributos:
fg # una lista de 5 colores de frente, uno para cada estado
bg # una lista de 5 colores de fondo
light # una lista de 5 colores, creados en el mtodo set_style()
dark # una lista de 5 colores, creados en el mtodo set_style()
mid # una lista de 5 colores, creados en el mtodo set_style()
text # una lista de 5 colores
base # una lista de 5 colores
text_aa # una lista de 5 colores a medio camino entre text/base
black # el color negro
white # el color blanco
font_desc # la descripcin de fuente pango predeterminada
xthickness #
ythickness #
fg_gc # una lista de 5 contextos grficos - creados en el mtodo set_style()
bg_gc # una lista de 5 contextos grficos - creados en el mtodo set_style()
light_gc # una lista de 5 contextos grficos - creados en el mtodo set_style()
dark_gc # una lista de 5 contextos grficos - creados en el mtodo set_style()
mid_gc # una lista de 5 contextos grficos - creados en el mtodo set_style()
text_gc # una lista de 5 contextos grficos - creados en el mtodo set_style()
base_gc # una lista de 5 contextos grficos - creados en el mtodo set_style()
black_gc # una lista de 5 contextos grficos - creados en el mtodo set_style()
white_gc # una lista de 5 contextos grficos - creados en el mtodo set_style()
bg_pixmap # una lista de 5 pixmaps
Cada atributo se puede leer directamente como style.black y style.fg_gc[gtk.STATE_NORMAL]. Todos
los atributos son de solo lectura excepto style.black, style.white, style.black_gc y style.white_gc.
Un estilo existente se puede copiar para una modicacin posterior usando el mtodo:
new_style = style.copy()
lo cual copia los atributos del estilo excepto las listas de contextos grcos y las listas de colores light, dark y mid.
El estilo actual se puede obtener con:
style = widget.get_style()
Para cambiar el estilo de un control (por ejemplo, para cambiar el color de frente), los siguientes mtodos de los
controles deben usarse:
widget.modify_fg(state, color)
widget.modify_bg(state, color)
widget.modify_text(state, color)
199
Captulo 16. Cambiar Atributos de
Controles
widget.modify_base(state, color)
widget.modify_font(font_desc)
widget.set_style(style)
Al jar el estilo se reservarn los colores del estilo y crearn los contextos grcos. La mayora de los controles se
redibujarn automticamente despus de cambiar el estilo. Si el estilo es None entonces el control volver a usar
su estilo predeterminado.
No todos los cambios al estilo afectarn al control. Por ejemplo, cambiar el color de fondo de una Label no
cambiar el color de fondo porque el control Label no tiene su propia ventana gtk.gdk.WIndow. El fondo de
una etiqueta depende del color de fondo del padre de la etiqueta. El uso de una EventBox para contener una
Etiqueta permite cambiar el color de fondo de la etiqueta. Mira la seccin EventBox para ver un ejemplo.
200
Captulo 17. Temporizadores, Entrada/Salida
y Funciones de Inactividad
17.1. Temporizadores
Puede que estes preguntndote cmo hacer que GTK haga algo til cuando est dentro de la funcin main(). Bien,
tienes varias opciones. Usando la siguiente funcin puedes crear un temporizador que ser llamado en intervalos
regulares.
timeout_handler_id = timeout_add(interval, function, ...)
El argumento interval es el nmero de milisegundos entre llamadas sucesivas a tu funcin. El argumento
function es la operacin que deseas que se llame. Cualquier argumento despus del segundo se pasar a tu
funcin como datos. El valor de retorno es un entero, "timeout_handler_id" que se puede utilizar para eliminar el
temporizador llamando a:
timeout_remove(timeout_handler_id)
Tambin puedes parar el temporizador devolviendo cero o FALSE desde tu funcin. Obviamente esto signica
que si quieres que el temporizador se siga llamando, debes devolver un valor distinto de cero, como TRUE.
Tu funcin ser algo parecido a:
def timeout_callback(...):
El nmero de argumentos a tu funcin debe coincidir con el nmero de argumentos de datos especicados en
timeout_add().
17.2. Monitorizar la Entrada/Salida
Puedes comprobar si hay algo para leer o escribir a un chero (bien a un chero Python o a un chero de ms bajo
nivel del Sistema Operativo) y automticamente invocar una funcin. Esto es especialmente til para aplicaciones
de red. La funcin:
imput_handler_id = input_add_full(source, condition, callback)
Donde el primer argumento (source) es el chero abierto (objeto de chero de Python o descriptor de chero de
ms bajo nivel) que quieres monitorizar. El mtodo input_add_full() usa el descriptor de chero internamente
asi que lo sacar del objeto de chero Python si es necesario. El segundo argumento (condition) especica qu
es lo que quieres monitorizar. Puede ser cualquiera de:
INPUT_READ - Llama a tu funcin cuando hay datos disponibles para leer de tu
fichero.
INPUT_WRITE - Llama a tu funcin cuando el fichero est listo para escritura.
201
Captulo 17. Temporizadores,
Entrada/Salida y Funciones de
Inactividad
INPUT_EXCEPTION - Llama a tu funcin cuando se produce una excepcin en tu fichero
Estas constantes se denen en el mdulo gtk.gdk module. Estoy seguro de que ya te has dado cuenta que el tercer
argumento, callback , es la funcin que quieres que se llame cuando las condiciones anteriores se cumplen.
El valor de retorno, input_handler_id se puede usar para parar de monitorizar el chero usando la siguiente
funcin:
input_remove(imput_handler_id)
Tu funcin ser algo parecido a:
def input_callback(source, condition):
Donde source y condition son los que especicastes antes. El valor de source ser el descriptor de chero de
bajo nivel y no el objeto chero Python (es decir, el valor que devuelve el mtodo de chero de Python fileno()).
17.3. Funciones de Inactividad
Qu pasa si quieres que se llame a una funcin cuando no est pasando nada? Usa la funcin:
idle_handler_id = idle_add(callback, ...)
Cualquier argumento ms all del primero (se indican con ...) se pasan a la funcin callback en orden. El valor
de retorno idle_handler_id se utiliza como una referencia al manejador.
Esto hace que GTK llame a la funcin especicada cuando no est pasando nada ms.
idle_remove(idle_handler_id)
No explicar el signicado de los argumentos ya que son iguales a los explicados anteriormente. La funcin que
se le pasa como primer argumento a idle_add() ser llamada siempre que se presente la oportunidad. Como con
las otras, devolviendo FALSE har que ya no se llame ms.
Tu funcin debe ser algo similar a:
def callback(...):
Los argumentos que se le pasen a tu funcin son los mismos que especicastes en la funcin idle_add() .
202
Captulo 18. Procesamiento Avanzado
de Eventos y Seales
18.1. Mtodos de Seales
Los mtodos de seales son mtodos de la clase Gobject que se heredan en los GtkObjects incluyendo todos los
controles GTK.
18.1.1. Conectar y Desconectar Manejadores de Seales
handler_id = object.connect(name, cb, cb_args)
handler_id = object.connect_after(name, cb, cb_args)
handler_id = object.connect_object(name, cb, slot_object, cb_args)
handler_id = object.connect_object_after(name, cb, slot_object, cb_args)
object.disconnect(handler_id)
Los primeros cuatro mtodos conectan un manejador de seales (cb) a un objeto GtkObject (object) para
la seal especicada por name, y devuelven un valor handler_id que identica la conexin. cb_args
son cero o ms argumentos que sern pasados al manejador cb. Los mtodos connect_after() y
connect_object_after() har que se llame a sus manejadores despus de todos los dems manejadores
(incluyendo los manejadores predeterminados) que estn conectados a esa seal. Cada manejador de seales de
un objeto tiene su propio conjunto de argumentos. Debes referirte a la documentacin GTK para averiguar qu
argumentos deben usarse por un manejador de seales aunque hay informacin para los controles comunes en el
apndice GTK Signals. El manejador de seales general es algo as como:
def signal_handler(object, ...., cb_args):
Los manejadores de seales que se denen como un mtodo de una clase Python (especicados en los mtodos
connect() como self.cb) tendrn un argumento adicional como primer argumento, la instancia del objeto self:
signal_handler(self, object, ...., cb_args)
Los mtodos connect_object() y connect_object_after() llaman al manejador de seales con el
slot_object en lugar del object como primer argumento:
def signal_handler(slot_object, ...., func_args):
def signal_handler(self, slot_object, ...., func_args):
El mtodo disconnect() elimina la conexin entre un manejador de seal y un objeto seal. El argumento
handler_id especica la conexin a eliminar.
203
Captulo 18. Procesamiento Avanzado
de Eventos y Seales
18.1.2. Bloquear y Desbloquear Manejadores de Seales
Los siguientes mtodos:
object.handler_block(handler_id)
object.handler_unblock(handler_id)
bloquean y desbloquean el manejador de seales especicado por el argumento handler_id. Cuando un
manejador de seales est bloqueado no se invocar cuando la seal se produzca.
18.1.3. Emitir y Parar Seales
Los siguientes mtodos:
object.emit(name, ...)
object.emit_stop_by_name(name)
emiten y paran la seal especicada por el argumento name respectivamente. Emitir la seal hace que el manejador
predeterminado y los manejadores de usuario se ejecuten. El mtodo emit_stop_by_name() abortar la emisin
de seales actual.
18.2. Emisin y Propagacin de Seales
La emisin de seales es el proceso por el cual GTK ejectua todos los manejadores para una seal y objeto
especcos.
Ten en cuenta que el valor de retorno de una emisin de seales es el valor de retorno del ltimo manejador
ejecutado. Como las seales de eventos son todas del tipo RUN_LAST, este valor ser el del manejador
predeterminado (dado por GTK), a menos que uses el mtodo connect_after().
La forma en la que un evento se trata (tal como "button_press_event") es:
Empieza en el control donde se produjo el evento.
Emite la seal genrica "event". Si ese manejador devuelve un valor de TRUE, para todo el procesamiento.
En caso contrario, emite una seal especca "button_press_event". Si eso devuelve TRUE, para todo el
procesamiento.
En caso contrario, ve al padre del control y repite los dos pasos anteriores.
Continua hasta que algn manejador devuelva TRUE, o hasta que se llegue al control de ms alto nivel.
Algunas consecuencias de lo anterior son:
El valor de retorno de tu manejador no tendr efecto si hay un manejador predeterminado, a menos que lo
conectes con connect_after().
Para evitar que el manejador predeterminado se llame, tienes que usar el mtodo connect() y usar
emit_stop_by_name() - el valor de retorno slo afecta a la propagacin de la seal, no a la emisin ac-
tual.
204
Captulo 19. Tratamiento de Selecciones
19.1. Perspectiva General de la Seleccin
Uno de los mecanismos de comunicacin entre procesos que hay disponibles en X y GTK es las selecciones.
Una seleccin identica una porcin de datos, por ejemplo, un trozo de texto, seleccionado por el usuario de
alguna manera, por ejemplo, arrastrando con el ratn. Slo una aplicacin en un display (Nota del traductor:
esto es terminologa X) (el dueo) puede poseer una seleccin particular en un momento dado, por lo que
cuando una aplicacin solicita una seleccin, el dueo anterior debe indicarle al usuario que la seleccin ha sido
RELINQUISHED (!). Otras aplicaciones pueden solicitar el contenido de una seleccin de diferentes maneras,
llamadas objetivos. Pueden haber muchas selecciones, pero la mayora de las aplicaciones X slo tratarn una, la
seleccin primaria.
En la mayora de los casos, no es necesario que una aplicacin PyGTK trate directamente las selecciones. Los
controles estndares, como el control Entry , ya tienen la capacidad de solicitar la seleccin cuando sea necesario
(por ejemplo, cuando el usuario arrastra el ratn sobre el texto), y de recuperar el contenido de la seleccin de otros
controles o aplicaciones (por ejemplo, cuando el usuario hace clic en el segundo botn del ratn). Sin embargo,
puede haber casos en los que quieras darle a los controles la capacidad de proporcionar la seleccin, o puede que
quieras recuperar objetivos no disponibles en principio.
A fundamental concept needed to understand selection handling is that of the atom. An atom is an integer that
uniquely identies a string (on a certain display). Certain atoms are predened by the X server, GTK.
19.2. Recuperar la Seleccin
Recuperar la seleccin es un proceso asncrono. Para empezar el proceso hay que llamar a:
result = widget.selection_convert(selection, target, time=0)
Esto convierte la seleccin selection en el formato especicado por el objetivo target. La seleccin
selection es un tomo correspondiente al tipo de seleccin; las selecciones comunes son las cadenas de texto:
PRIMARY # primaria
SECONDARY # secundaria
Si es posible, el campo tiempo time debera ser el momento en el que se produjo el evento que ocasion la
seleccin. Esto ayuda a cerciorarse que los eventos ocurren en el orden en el que el usuario los solicita. Sin
embargo, si no est disponible (por ejemplo, si la conversin se produjo en una seal "clicked"), entonces puedes
utilizar 0, lo que signica el momento actual. El resultado ser TRUE si la conversin tuvo xito o FALSE en caso
contrario.
Cuando el dueo de la seleccin responde a la peticin, una seal "selection_received" (seleccin_recibida) se
envia a tu aplicacin. El manejador de esta seal recibe un objeto de tipo gtk.SelectionData , que tiene los
siguientes atributos:
selection # seleccin
target # objetivo
type # tipo
format # formato
205
Captulo 19. Tratamiento de
Selecciones
data # datos
selection y target son los valores que tu diste en el mtodo selection_convert() .
type es un tomo que identica el tipo de datos que ha devuelto el dueo de la seleccin. Algunos valores
posibles son "STRING", una cadena de caracteres latin-1, "ATOM", una serie de tomos, "INTEGER", un entero,
"image/x-xpixmap", etc. La mayora de los objetivos slo pueden devolver un tipo.
La lista de tomos estndares en X y GTK es:
PRIMARY
SECONDARY
ARC
ATOM
BITMAP
CARDINAL
COLORMAP
CURSOR
CUT_BUFFER0
CUT_BUFFER1
CUT_BUFFER2
CUT_BUFFER3
CUT_BUFFER4
CUT_BUFFER5
CUT_BUFFER6
CUT_BUFFER7
DRAWABLE
FONT
INTEGER
PIXMAP
POINT
RECTANGLE
RESOURCE_MANAGER
RGB_COLOR_MAP
RGB_BEST_MAP
RGB_BLUE_MAP
RGB_DEFAULT_MAP
RGB_GRAY_MAP
RGB_GREEN_MAP
RGB_RED_MAP
STRING
VISUALID
WINDOW
WM_COMMAND
WM_HINTS
WM_CLIENT_MACHINE
WM_ICON_NAME
WM_ICON_SIZE
WM_NAME
WM_NORMAL_HINTS
WM_SIZE_HINTS
WM_ZOOM_HINTS
MIN_SPACE
NORM_SPACE
MAX_SPACE END_SPACE,
SUPERSCRIPT_X
SUPERSCRIPT_Y
206
Captulo 19. Tratamiento de
Selecciones
SUBSCRIPT_X
SUBSCRIPT_Y
UNDERLINE_POSITION
UNDERLINE_THICKNESS
STRIKEOUT_ASCENT
STRIKEOUT_DESCENT
ITALIC_ANGLE
X_HEIGHT
QUAD_WIDTH
WEIGHT
POINT_SIZE
RESOLUTION
COPYRIGHT
NOTICE
FONT_NAME
FAMILY_NAME
FULL_NAME
CAP_HEIGHT
WM_CLASS
WM_TRANSIENT_FOR
CLIPBOARD
format da la longitud de las unidades (por ejemplo caracteres) en bits. Normalmente puedes olvidar esto cuando
recibes datos.
data son los datos devueltos en forma de cadena de texto.
PyGTK empaqueta todos los datos devueltos en una cadena de texto. Esto hace que sea fcil manipular objetivos
de cadenas de texto. Para obetener objetivos de otros tipos (como ATOM o INTEGER) el programa debe extraer
la informacin de la cadena de texto devuelta. PyGTK proporciona dos mtodos para obtener texto y una lista de
objetivos a partir de los datos devueltos:
text = selection_data.get_text()
targets = selection_data.get_targets()
donde text es una cadena de texto que contiene el texto de la seleccin y targets es una lista de los objetivos
que acepta la seleccin.
Dado un gtk.SelectionData que contiene una lista de objetivos el mtodo:
has_text = selection_data.targets_include_text()
devolver TRUE si uno o ms de los objetivos pueden tener texto.
El programa de ejemplo getselection.py [examples/getselection.py] ensea cmo recibir un objetivo "STRING"
o "TARGETS" desde la seleccin primaria y luego imprimir los datos correspondientes en la consola cuando se
hace clic en el botn asociado. La gura Figura 19.1. Ejemplo de Obtencin de la Seleccin muestra la ventana
del programa:
207
Captulo 19. Tratamiento de
Selecciones
Figura 19.1. Ejemplo de Obtencin de la Seleccin
El cdigo fuente de getselection.py [examples/getselection.py] es:
1 #!/usr/bin/env python
2
3 # example getselection.py
4
5 import gtk
6
7 class GetSelectionExample:
8 # Signal handler invoked when user clicks on the
9 # "Get String Target" button
10 def get_stringtarget(self, widget):
11 # And request the "STRING" target for the primary selection
12 ret = widget.selection_convert("PRIMARY", "STRING")
13 return
14
15 # Signal handler invoked when user clicks on the "Get Targets" button
16 def get_targets(self, widget):
17 # And request the "TARGETS" target for the primary selection
18 ret = widget.selection_convert("PRIMARY", "TARGETS")
19 return
20
21 # Signal handler called when the selections owner returns the data
22 def selection_received(self, widget, selection_data, data):
23 # Make sure we got the data in the expected form
24 if str(selection_data.type) == "STRING":
25 # Print out the string we received
26 print "STRING TARGET: %s" % selection_data.get_text()
27
28 elif str(selection_data.type) == "ATOM":
29 # Print out the target list we received
30 targets = selection_data.get_targets()
31 for target in targets:
32 name = str(target)
33 if name != None:
34 print "%s" % name
35 else:
36 print "(bad target)"
37 else:
38 print "Selection was not returned as \"STRING\" or \"ATOM\"!"
39
40 return gtk.FALSE
41
42
43 def __init__(self):
44 # Create the toplevel window
45 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
208
Captulo 19. Tratamiento de
Selecciones
46 window.set_title("Get Selection")
47 window.set_border_width(10)
48 window.connect("destroy", gtk.mainquit)
49
50 vbox = gtk.VBox(gtk.FALSE, 0)
51 window.add(vbox)
52 vbox.show()
53
54 # Create a button the user can click to get the string target
55 button = gtk.Button("Get String Target")
56 eventbox = gtk.EventBox()
57 eventbox.add(button)
58 button.connect_object("clicked", self.get_stringtarget, eventbox)
59 eventbox.connect("selection_received", self.selection_received)
60 vbox.pack_start(eventbox)
61 eventbox.show()
62 button.show()
63
64 # Create a button the user can click to get targets
65 button = gtk.Button("Get Targets")
66 eventbox = gtk.EventBox()
67 eventbox.add(button)
68 button.connect_object("clicked", self.get_targets, eventbox)
69 eventbox.connect("selection_received", self.selection_received)
70 vbox.pack_start(eventbox)
71 eventbox.show()
72 button.show()
73
74 window.show()
75
76 def main():
77 gtk.main()
78 return 0
79
80 if __name__ == "__main__":
81 GetSelectionExample()
82 main()
Las lineas 28-36 se encargan de la obtencin de los datos de seleccin de "TARGETS" e imprime la lista de los
nombres de los objetivos. Los botones estn metidos en sus propias cajas de eventos porque una seleccin debe
estar asociada a una gtk.gdkWindow y los botones son controles sin ventana en GTK+2.0.
19.3. Proporcionar la Seleccin
Proporcionar la seleccin es un poco ms complicado. Tienes que registrar manejadores que se llamaran cuando
se solicite tu seleccin. Para cada par seleccin-objetivo que controles tienes que hacer una llamada a:
widget.selection_add_target(selection, target, info)
widget (control), selection (seleccin), y target (objetivo) identican las peticiones que este manejador
gestionar. Cuando llega una peticin para una seleccin, la seal "selection_get" ser llamada. info es un entero
que se puede usar como un identicador para el objetivo especco dentro de la retrollamada.
La retrollamada tiene la siguiente signatura:
209
Captulo 19. Tratamiento de
Selecciones
def selection_get(widget, selection_data, info, time):
El argumento gtk.SelectionData es el mismo que antes, pero esta vez, somos responsables de rellenar los
campos type, format y data. (El campo format es importante aqui ya que el servidor X lo usa para saber si el
campo data necesita que se le cambie el orden de los bytes o no. Normalemente ser 8 - un caracter - o 32 - un
entero.) Esto se hace llamando al mtodo:
selection_data.set(type, format, data)
Este mtodo PyGTK slo puede tratar datos de cadenas de caracteres por lo que data debe ser cargado en una
cadena Python pero format ser cualquier cosa que tenga el tamao apropiado (por ejemplo 32 para tomos y
enteros, 8 para cadenas). Los mdulos Python struct o StringIO pueden servir para convertir datos que no son
cadenas de caracteres a cadenas de caracteres. Por ejemplo, puedes convertir una lista de enteros en una cadena y
ponerlos en el campo selection_data de esta forma:
ilist = [1, 2, 3, 4, 5]
data = apply(struct.pack, [%di%len(ilist)] + ilist)
selection_data.set("INTEGER", 32, data)
El siguiente mtodo ja los datos de la seleccin a partir de esa cadena:
selection_data.set_text(str, len)
Cuando lo solicite el usuario, debes reclamar la posesin de la seleccin llamando a:
result = widget.selection_owner_set(selection, time=0L)
result ser TRUE si el programa reclama la selection con xito. Si otra aplicacin reclama la posesin de
selection, te llegar un eventoa "selection_clear_event".
Como ejemplo de proporcionar la seleccin, el programa setselection.py [examples/setselection.py] le aade
funcionalidad de seleccin a un botn biestado que est dentro de una gtk.EventBox. (Necesitamos la
gtk.Eventbox porque la seleccin debe asociarse a una gtk.gdk.Window y un gtk.Button es un control sin
ventana en GTK+ 2.0.). Cuando el botn biestado se pulsa, el programa reclama la seleccin primaria. El nico
objetivo soportado (aparte de los objetivos que proporciona la propia GTK), es el objetivo "STRING". Cuando se
solicita este objetivo, se devuelve una representacin en cadena de caracteres de la hora actual. La gura Figura
19.2. Ejemplo de Fijar la Seleccin ilustra la ventana del programa cuando el programa ha conseguido la posesin
de la seleccin primaria:
Figura 19.2. Ejemplo de Fijar la Seleccin
210
Captulo 19. Tratamiento de
Selecciones
El cdigo fuente de setselection.py [examples/setselection.py] es:
1 #!/usr/bin/env python
2
3 # example setselection.py
4
5 import gtk
6 import time
7
8 class SetSelectionExample:
9 # Callback when the user toggles the selection
10 def selection_toggled(self, widget, window):
11 if widget.get_active():
12 self.have_selection = window.selection_owner_set("PRIMARY")
13 # if claiming the selection failed, we return the button to
14 # the out state
15 if not self.have_selection:
16 widget.set_active(gtk.FALSE)
17 else:
18 if self.have_selection:
19 # Not possible to release the selection in PyGTK
20 # just mark that we dont have it
21 self.have_selection = gtk.FALSE
22 return
23
24 # Called when another application claims the selection
25 def selection_clear(self, widget, event):
26 self.have_selection = gtk.FALSE
27 widget.set_active(gtk.FALSE)
28 return gtk.TRUE
29
30 # Supplies the current time as the selection.
31 def selection_handle(self, widget, selection_data, info, time_stamp):
32 current_time = time.time()
33 timestr = time.asctime(time.localtime(current_time))
34
35 # When we return a single string, it should not be null terminated.
36 # That will be done for us
37 selection_data.set_text(timestr, len(timestr))
38 return
39
40 def __init__(self):
41 self.have_selection = gtk.FALSE
42 # Create the toplevel window
43 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
44 window.set_title("Set Selection")
45 window.set_border_width(10)
46 window.connect("destroy", gtk.mainquit)
47 self.window = window
48 # Create an eventbox to hold the button since it no longer has
49 # a GdkWindow
50 eventbox = gtk.EventBox()
51 eventbox.show()
52 window.add(eventbox)
53
54 # Create a toggle button to act as the selection
55 selection_button = gtk.ToggleButton("Claim Selection")
56 eventbox.add(selection_button)
211
Captulo 19. Tratamiento de
Selecciones
57
58 selection_button.connect("toggled", self.selection_toggled, eventbox)
59 eventbox.connect_object("selection_clear_event", self.selection_clear,
60 selection_button)
61
62 eventbox.selection_add_target("PRIMARY", "STRING", 1)
63 eventbox.selection_add_target("PRIMARY", "COMPOUND_TEXT", 1)
64 eventbox.connect("selection_get", self.selection_handle)
65 selection_button.show()
66 window.show()
67
68 def main():
69 gtk.main()
70 return 0
71
72 if __name__ == "__main__":
73 SetSelectionExample()
74 main()
212
Captulo 20. Arrastrar y Soltar
PyGTK tiene un conjunto de funciones de alto nivel para comunicacin entre procesos a travs del sistema
arrastrar-y-soltar. PyGTK puede realizar arrastrar-y-soltar sobre los protocoles de bajo nivel Xdnd y arrastrar-
y-soltar Motif.
20.1. Perspectiva General de Arrastrar y Soltar
Una aplicacin con la capacidad de arrastrar-y-soltar primero dene y congura el/los control/es para arrastrar-
y-soltar. Cada control puede ser una fuente y/o destino para arrastrar-y-soltar. Te en cuenta que estos controles
deben tener asociada una ventana X.
Los controles fuente pueden enviar datos de arrastrar, permitiendo as al usuario arrastrar cosas desde ellos,
mientras que controles destino pueden recibir datos de arrastrar. Destino de arrastrar-y-soltar pueden limitar
quines pueden enviarles datos, por ejemplo, la misma aplicacin o cualquier aplicacin (incluyndose a s
misma).
Para enviar y recibir datos se utilizan seales. Soltar un elemento en un control destino requiere una peticin de
datos (para el control fuente) y un manejador de datos (para el control destino). Se pueden conectar manejadores
de seal adicionales si quieres saber cundo empieza el usuario a arrastrar (en el mismo momento en el que
empieza), cundo se realiza el soltar, y cuando naliza el proceso completo de arrastrar-y-soltar (con xito o no).
Tu aplicacin tiene que proporcionar los datos a los controles orgen cuando se solicite, lo cual implica tener un
manejador de seal para la solicitud de datos. Para controles destino, tienen que tener un manejador de seales de
datos recibidos.
Por tanto un ciclo habitual de arrastrar-y-soltar sera as:
Se empieza a arrastrar.
Se solicita los datos de arrastrar (cuando se suelta el botn).
Se reciben los datos (puede ser en la misma o en otra aplicacin).
Se borran los datos de arrastrar (si el arrastre fue un movimiento).
El proceso arrastrar-y-soltar termina.
Hay algunos pasos intermedios adicionales pero los veremos en detalle un poco ms tarde.
20.2. Propiedades de Arrastrar y Soltar
Los datos de arrastrar tienen las siguientes propiedades:
Tipo de accin de arrastrar (por ejemplo ACTION_COPY (accin copiar), ACTION_MOVE (accin mover)).
Tipo de arrastrar-y-soltar especco del cliente (un par de nombre y nmero).
Tipo de formato de los datos enviados y recibidos.
213
Captulo 20. Arrastrar y Soltar
Las acciones de arrastrar son bastante obvias, especican si el control puede arrastrar con la/s accin/es especi-
cada, por ejemplo gtk.gdk.ACTION_COPY y/o gtk.gdk.ACTION_MOVE. Una accin gtk.gdk.ACTION_COPY
sera el tpico arrastrar y soltar sin que el origen se elimine mientras que una accin gtk.gdk.ACTION_MOVE
sera exactamente igual pero se sugiere que se borren los datos orgen despues de que la seal de recepcin se
llame. Hay ms acciones como gtk.gdk.ACTION_LINK que puedes investigar cuando adquieras un poco ms de
prctica con arrastrar-y-soltar.
El tipo de arrastrar-y-soltar especicado por el cliente es mucho ms exible, porque ser tu aplicacin la que lo
dena y compruebe. Tendrs que congurar tus controles destino para recibir ciertos tipos de arrastrar-y-soltar
especicando un nombre y/o un nmero. Es ms able usar un nombre ya que otra aplicacin puede estar usando
el mismo nmero con un signicado completamente diferente.
Los tipos de emisin y recepcin de datos (objetivo de seleccin) entran en juego slo en tus manejadores de
datos solicitados y recibidos. El trmino objetivo de seleccin es un poco confuso. Es un trmino adaptado de
la seleccin GTK (cortar/copiar y pegar). Lo que selection target realmente signica es el tipo de formato de
datos (por ejemplo GdkAtom, entero, o cadena de caracteres) que se est enviando o recibiendo. Tu manejador de
datos solicitados tiene que especicar el tipo (selection target) de datos que est enviando y tu manejador de datos
recibidos tiene que manejar el tipo de datos recibidos (selection target).
20.3. Mtodos de Arrastrar y Soltar
20.3.1. Conguracin del Control Orgen
El mtodo drag_source_set() especica un conjunto de tipos objetivo para una operacin de arrastrar en un
control.
widget.drag_source_set(start_button_mask, targets, actions)
Los parmetros signican lo siguiente:
widget especica el control orgen
start_button_mask especica una mscara de bits de los botones que pueden empezar a arrastrar (por
ejemplo BUTTON1_MASK)
targets especica una lista de los tipos de datos objetivos que se manejarn.
actions especica un mscara de bits de las acciones posibles para arrastrar desde esta ventana.
214
Captulo 20. Arrastrar y Soltar
El parmetro targets es una lista de tuplas similar a:
(target, flags, info)
target especica una cadena de caracteres que representa el tipo de arrastre.
flags restringen la aplicacin del arrastre. flags puede ser 0 o las siguientes constantes:
gtk.TARGET_SAME_APP # El objetivo slo se puede seleccionar para arrastres
dentro de una sola aplicacin.
gtk.TARGET_SAME_WIDGET # El objetivo slo se puede seleccionar para arrastres
dentro del mismo control.
info es un identicador entero asignado por la aplicacin.
Si no es necesario que un control siga siendo el orgen de operaciones arrastrar-y-soltar, el mtodo
drag_source_unset() se puede usar para eliminar un conjunto de tipos de objetivos arrastrar-y-soltar.
widget.drag_source_unset()
20.3.2. Seales en el Control Orgen
Las siguientes seales se le envian al control orgen durante una operacin de arrastrar-y-soltar.
Tabla 20.1. Seales del Control de Orgen
drag_begin (comienzo de arrastre) def drag_begin_cb(widget, drag_context, data):
drag_motion (movimiento de arras-
tre)
def drag_motion_cb(widget, drag_context, x, y, time, data):
drag_data_get (obtencin de datos
de arrastre)
def drag_data_get_cb(widget, drag_context, selection_data, info, time,
data):
drag_data_delete (eliminacin de
datos de arrastre)
def drag_data_delete_cb(widget, drag_context, data):
drag_drop (arrastre soltado) def drag_drop_cb(widget, drag_context, x, y, time, data):
drag_end (n de arrastre) def drag_end_cb(widget, drag_context, data):
20.3.3. Conguracin de un Control Destino
drag_dest_set() especica que este control puede ser destino de operaciones arrastrar-y-soltar y dice los tipos
que permite.
drag_dest_unset() especica que el control no puede recibir ms operaciones arrastrar-y-soltar.
widget.drag_dest_set(flags, targets, actions)
widget.drag_dest_unset()
215
Captulo 20. Arrastrar y Soltar
flags especican qu acciones GTK debe realizar de parte del control cuando se suelte algo en l. Los valores
posibles son:
gtk.DEST_DEFAULT_MOTION Si est activado para este control, GTK comprobar si el arrastre se corre-
sponde con algn objetivo y accin de este control cuando se arrastre por encima de
este control. Entonces GTK llamar a drag_status() segn corresponda.
gtk.DEST_DEFAULT_HIGHLIGHT Si est activado para este control, GTK resaltar el control siempre que
el arrastre est encima de este control y el formato y la accin sean aceptables.
gtk.DEST_DEFAULT_DROP Si est activado para este control, GTK comprobar si el arrastre se corresponde
con algn objetivo y accin del control. Si es as, GTK llamar a drag_data_get()
de parte del control. No importa si el soltar tiene xito o no, GTK llamar a
drag_finish(). Si la accin fue mover, entonces si el arrastre tuvo xito, se le
pasar TRUE como argumento delete (borrar) a drag_finish().
gtk.DEST_DEFAULT_ALL Si est activo, especica que todas las acciones anteriores deben ejecutarse.
actions es una mscara de bits de las posibles acciones a realizar cuando se arrastre sobre este control. Los
valores posibles se pueden componer con la operacin OR y son los siguientes:
gtk.gdk.ACTION_DEFAULT # accin predeterminada
gtk.gdk.ACTION_COPY # accin copiar
gtk.gdk.ACTION_MOVE # accin mover
gtk.gdk.ACTION_LINK # accin enlazar
gtk.gdk.ACTION_PRIVATE # accin privada
gtk.gdk.ACTION_ASK # accin preguntar
20.3.4. Seales en el Control Destino
Durante una operacin arrastrar-y-soltar se le envia la siguiente seal al control destino.
Tabla 20.2. Seales del Control Destino
drag_data_received (datos
recibidos)
def drag_data_received_cb(widget, drag_context, x, y, selection_data,
info, time, data):
El programa de ejemplo dragndrop.py [examples/dragndrop.py] demuestra el uso de arrastrar y soltar en una
aplicacin. Un botn con un icono xpm (en gtkxpm.py [examples/gtkxpm.py]) es el orgen para el arrastre;
proporciona tanto texto como datos xpm. Un control de disposicin es el destino para soltar el xpm mientras que
un botn es el destino para soltar el texto. La gura Figura 20.1. Ejemplo de Arrastrar y Soltar ilustra la ventana
del programa despus de soltar el xpm en el control de disposicin y el texto en el botn:
216
Captulo 20. Arrastrar y Soltar
Figura 20.1. Ejemplo de Arrastrar y Soltar
El cdigo fuente de dragndrop.py [examples/dragndrop.py] es:
1 #!/usr/bin/env python
2
3 # example dragndrop.py
4
5 import gtk
6 import string, time
7
8 import gtkxpm
9
10 class DragNDropExample:
11 HEIGHT = 600
12 WIDTH = 600
13 TARGET_TYPE_TEXT = 80
14 TARGET_TYPE_PIXMAP = 81
15 fromImage = [ ( "text/plain", 0, TARGET_TYPE_TEXT ),
16 ( "image/x-xpixmap", 0, TARGET_TYPE_PIXMAP ) ]
17 toButton = [ ( "text/plain", 0, TARGET_TYPE_TEXT ) ]
18 toCanvas = [ ( "image/x-xpixmap", 0, TARGET_TYPE_PIXMAP ) ]
19
20 def layout_resize(self, widget, event):
21 x, y, width, height = widget.get_allocation()
22 if width > self.lwidth or height > self.lheight:
23 self.lwidth = max(width, self.lwidth)
217
Captulo 20. Arrastrar y Soltar
24 self.lheight = max(height, self.lheight)
25 widget.set_size(self.lwidth, self.lheight)
26
27 def makeLayout(self):
28 self.lwidth = self.WIDTH
29 self.lheight = self.HEIGHT
30 box = gtk.VBox(gtk.FALSE,0)
31 box.show()
32 table = gtk.Table(2, 2, gtk.FALSE)
33 table.show()
34 box.pack_start(table, gtk.TRUE, gtk.TRUE, 0)
35 layout = gtk.Layout()
36 self.layout = layout
37 layout.set_size(self.lwidth, self.lheight)
38 layout.connect("size-allocate", self.layout_resize)
39 layout.show()
40 table.attach(layout, 0, 1, 0, 1, gtk.FILL|gtk.EXPAND,
41 gtk.FILL|gtk.EXPAND, 0, 0)
42 # create the scrollbars and pack into the table
43 vScrollbar = gtk.VScrollbar(None)
44 vScrollbar.show()
45 table.attach(vScrollbar, 1, 2, 0, 1, gtk.FILL|gtk.SHRINK,
46 gtk.FILL|gtk.SHRINK, 0, 0)
47 hScrollbar = gtk.HScrollbar(None)
48 hScrollbar.show()
49 table.attach(hScrollbar, 0, 1, 1, 2, gtk.FILL|gtk.SHRINK,
50 gtk.FILL|gtk.SHRINK,
51 0, 0)
52 # tell the scrollbars to use the layout widgets adjustments
53 vAdjust = layout.get_vadjustment()
54 vScrollbar.set_adjustment(vAdjust)
55 hAdjust = layout.get_hadjustment()
56 hScrollbar.set_adjustment(hAdjust)
57 layout.connect("drag_data_received", self.receiveCallback)
58 layout.drag_dest_set(gtk.DEST_DEFAULT_MOTION |
59 gtk.DEST_DEFAULT_HIGHLIGHT |
60 gtk.DEST_DEFAULT_DROP,
61 self.toCanvas, gtk.gdk.ACTION_COPY)
62 self.addImage(gtkxpm.gtk_xpm, 0, 0)
63 button = gtk.Button("Text Target")
64 button.show()
65 button.connect("drag_data_received", self.receiveCallback)
66 button.drag_dest_set(gtk.DEST_DEFAULT_MOTION |
67 gtk.DEST_DEFAULT_HIGHLIGHT |
68 gtk.DEST_DEFAULT_DROP,
69 self.toButton, gtk.gdk.ACTION_COPY)
70 box.pack_start(button, gtk.FALSE, gtk.FALSE, 0)
71 return box
72
73 def addImage(self, xpm, xd, yd):
74 hadj = self.layout.get_hadjustment()
75 vadj = self.layout.get_vadjustment()
76 style = self.window.get_style()
77 pixmap, mask = gtk.gdk.pixmap_create_from_xpm_d(
78 self.window.window, style.bg[gtk.STATE_NORMAL], xpm)
79 image = gtk.Image()
80 image.set_from_pixmap(pixmap, mask)
81 button = gtk.Button()
82 button.add(image)
218
Captulo 20. Arrastrar y Soltar
83 button.connect("drag_data_get", self.sendCallback)
84 button.drag_source_set(gtk.gdk.BUTTON1_MASK, self.fromImage,
85 gtk.gdk.ACTION_COPY)
86 button.show_all()
87 # have to adjust for the scrolling of the layout - event location
88 # is relative to the viewable not the layout size
89 self.layout.put(button, int(xd+hadj.value), int(yd+vadj.value))
90 return
91
92 def sendCallback(self, widget, context, selection, targetType, eventTime):
93 if targetType == self.TARGET_TYPE_TEXT:
94 now = time.time()
95 str = time.ctime(now)
96 selection.set(selection.target, 8, str)
97 elif targetType == self.TARGET_TYPE_PIXMAP:
98 selection.set(selection.target, 8,
99 string.join(gtkxpm.gtk_xpm, \n))
100
101 def receiveCallback(self, widget, context, x, y, selection, targetType,
102 time):
103 if targetType == self.TARGET_TYPE_TEXT:
104 label = widget.get_children()[0]
105 label.set_text(selection.data)
106 elif targetType == self.TARGET_TYPE_PIXMAP:
107 self.addImage(string.split(selection.data, \n), x, y)
108
109 def __init__(self):
110 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
111 self.window.set_default_size(300, 300)
112 self.window.connect("destroy", gtk.mainquit)
113 self.window.show()
114 layout = self.makeLayout()
115 self.window.add(layout)
116
117 def main():
118 gtk.main()
119
120 if __name__ == "__main__":
121 DragNDropExample()
122 main()
219
Captulo 21. Ficheros rc de GTK
GTK tiene su propia forma de tratar las opciones predeterminadas de las aplicaciones, usando cheros rc. Con
esto puedes cambiar los colores de cualquier control, y tambin se pueden usar para poner un dibujo de fondo en
algunos controles.
21.1. Funciones para Ficheros rc
Cuando comience tu aplicacin, debes incluir una llamada a:
rc_parse(filename)
Pasndole el nombre de tu chero rc en filename. Esto hace que GTK analice este chero, y use los valores de
estilo para los tipos de controles que denas alli.
Si quieres tener un conjunto especial de controles que puedan tener un estilo diferente a los dems, o cualquier
otra divisin lgica de controles, usa una llamada a:
widget.set_name(name)
El nombre que especiques se le asignar a tu control recin creado. Esto te permitir cambiar los atributos de
este control en el chero rc.
Si usamos una llamada parecida a:
button = gtk.Button("Special Button")
button.set_name("special button")
Entonces se le dar el nombre "special button" a este botn y se podr localizar en el chero rc como "special
button.GtkButton".
El ejemplo de chero rc que hay ms abajo, cambia las propiedades de la ventana principal, y deja a todos sus
hijos que hereden el estilo descrito para el "main button" (botn principal). El cdigo usado por la aplicacin es:
window = gtk.Window(gtk.WINDOW_TOPLEVEL)
window.set_name("main window")
Y el estilo se dene en el chero rc usando:
widget "main window.*GtkButton*" style "main_button"
Lo cual le pone a todos los controles Button en la "main window" el estilo "main_buttons" tal y como se dene
en el chero rc.
220
Captulo 21. Ficheros rc de GTK
Como puedes ver, este es un sistema bastante potente y exible. Usa tu imaginacin para sacarle el mejor
provecho.
21.2. Formato de los Ficheros rc de GTK
El formato del chero rc se muestra en el siguiente ejemplo . Este es el chero testgtkrc de la distribucin
GTK, pero le he aadido unos cuantos comentarios y cosas. Puedes incluir esta explicacin en tu programa para
permitirle al usuario anar su aplicacin.
Hay varias directivas para cambiar los atributos de un control.
fg - Cambia el color de frente de un control.
bg - Cambia el color de fondo de un control.
bg_pixmap - Cambia el fondo de un control para que sea un mosaico con el pixmap dado.
font - Cambia la fuente que usar el control.
Adems de esto, hay varios estados en los que un control puede estar, y puedes cambiar los diferentes colores,
pixmaps y fuentes para cada estado. Los estados son:
NORMAL (Normal) El estado normal de un control, sin que el ratn est encima de l, y sin que haya
sido pulsado, etc.
PRELIGHT (Preiluminado) Cuando el ratn est encima del control, los colores denidos en este estado
tendrn efecto.
ACTIVE (Activo) Cuando el control est presionado o se ha hecho clic en l estar activo y los
atributos asignados con este valor tendrn efecto.
INSENSITIVE (Insensitivo) Cuando un control est insensitivo, y no puede ser activado, tendr estos atribu-
tos.
SELECTED (Seleccionado) Cuando un objeto est seleccionado, se usan estos atributos.
221
Captulo 21. Ficheros rc de GTK
Cuando se usan las palabras "fg" y "bg" para cambiar los colores de los controles, el formato es:
fg[<STATE>] = { Rojo, Verde, Azul }
Donde STATE es uno de los estados anteriores (PRELIGHT, ACTIVE, etc), y el Rojo, Verde y Azul son valores
en el rango de 0 - 1.0, siendo { 1.0, 1.0, 1.0 } el blanco. Deben estar en formato oat, o se les asignar 0, por tanto
un simple "1" no funcionar, debe ser "1.0". Un simple "0" esta bien ya que da igual si no se reconoce porque los
valores no reconocidos se ponen a 0.
bg_pixmap es muy similar a lo anterior excepto que los colores se sustituyen por un nombre de chero.
pixmap_path es una lista de caminos separados por ":" . Cuando especiques un pixmap, se buscar en esta lista.
La directiva "font" es simple:
font = "<font name>"
Lo nico dicil es saber la cadena de la fuente. El programa xfontsel o una utilidad similar ayuda.
La directiva "widget_class" ja el estilo para una clase de controles. Estas clases se listan en la perspectiva general
de controles en la jerarqua de clases.
La directiva "widget" ja el estilo de un conjunto especico de controles con un nombre, reemplazando cualquier
estilo de la clase del control en cuestin. Estos controles se registran en la aplicacin usando el mtodo
set_name() . Esto te permite cambiar los atributos de un control de una forma mucho ms concreta, en vez
de especicar los atributos de toda su clase. Te recomiendo que documentes todos estos controles especiales para
que los usuarios puedan personalizarlos.
Cuando se usa la palabra parent (padre) en un atributo, el control usar los atributos de su padre en la aplicacin.
Al denir un estilo, puedes asiganr los atributos de un estilo denido previamente al estilo actual.
style "main_button" = "button"
{
font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
bg[PRELIGHT] = { 0.75, 0, 0 }
}
Este ejemplo usa el estilo "button", y crea un nuevo estilo "main_button" simplemente cambiando la fuente y el
color de fondo del estado preiluminado del estilo "button".
Por supuesto, muchos de estos atributos no funcionan con todos los controles. Solo es cuestin de sentido comn.
Todo lo que podra aplicarse, se debe aplicar.
21.3. Ejemplo de chero rc
# pixmap_path "<dir 1>:<dir 2>:<dir 3>:..."
#
pixmap_path "/usr/include/X11R6/pixmaps:/home/imain/pixmaps"
#
# style <name> [= <name>]
222
Captulo 21. Ficheros rc de GTK
# {
# <option>
# }
#
# widget <widget_set> style <style_name>
# widget_class <widget_class_set> style <style_name>
# Esto crea un estilo llamado "window". El nombre no es importante ya que
# se le asigna a los controles reales al final del fichero.
style "window"
{
#Esto le pone el pixmap especificado como margn alrededor de la ventana.
#bg_pixmap[<STATE>] = "<pixmap filename>"
bg_pixmap[NORMAL] = "warning.xpm"
}
style "scale"
{
#Pone el color de frente (el color de la fuente) a rojo en el estado
#"NORMAL".
fg[NORMAL] = { 1.0, 0, 0 }
#Pone el pixmap de fondo de este control al mismo de su padre.
bg_pixmap[NORMAL] = "<parent>"
}
style "button"
{
# Esto muestra los posibles estados de un botn. El nico que no tiene es
# el estado SELECTED .
fg[PRELIGHT] = { 0, 1.0, 1.0 }
bg[PRELIGHT] = { 0, 0, 1.0 }
bg[ACTIVE] = { 1.0, 0, 0 }
fg[ACTIVE] = { 0, 1.0, 0 }
bg[NORMAL] = { 1.0, 1.0, 0 }
fg[NORMAL] = { .99, 0, .99 }
bg[INSENSITIVE] = { 1.0, 1.0, 1.0 }
fg[INSENSITIVE] = { 1.0, 0, 1.0 }
}
# En este ejemplo, heredamos los atributos del estilo "button" y reemplazamos
# el color de fondo y la fuente del estado PRELIGHT para crear el estilo
# "main_button" .
style "main_button" = "button"
{
font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
bg[PRELIGHT] = { 0.75, 0, 0 }
}
style "toggle_button" = "button"
{
fg[NORMAL] = { 1.0, 0, 0 }
fg[ACTIVE] = { 1.0, 0, 0 }
# Esto le pone el pixmap de fondo al botn biestado al que est usando el
223
Captulo 21. Ficheros rc de GTK
# padre (tal y como se defina en la aplicacin)
bg_pixmap[NORMAL] = "<parent>"
}
style "text"
{
bg_pixmap[NORMAL] = "marble.xpm"
fg[NORMAL] = { 1.0, 1.0, 1.0 }
}
style "ruler"
{
font = "-adobe-helvetica-medium-r-normal--*-80-*-*-*-*-*-*"
}
# pixmap_path "~/.pixmaps"
# Le decimos que estos tipos de controles usen los estilos definidos arriba.
# Los tipos de controles se listan en la jerarqua de controles, pero
# probablemente se podran listar en este documento para referencia del usuario
widget_class "GtkWindow" style "window"
widget_class "GtkDialog" style "window"
widget_class "GtkFileSelection" style "window"
widget_class "*Gtk*Scale" style "scale"
widget_class "*GtkCheckButton*" style "toggle_button"
widget_class "*GtkRadioButton*" style "toggle_button"
widget_class "*GtkButton*" style "button"
widget_class "*Ruler" style "ruler"
widget_class "*GtkText" style "text"
# Le decimos que todos los botones que sean hijos de la ventana "main window"
# tengan el estilo "main_button". Esto debe ser documentado para que se le
# saque provecho.
widget "main window.*GtkButton*" style "main_button"
224
Captulo 22. Scribble, Un Ejemplo de
Programa de Dibujo Simple
22.1. Perspectiva General de Scribble
En esta seccin, construiremos un programa de dibujo simple. En el proceso, examinaremos como manejar eventos
de ratn, como dibujar en una ventana, y como dibujar mejor usando un pixmap de fondo.
Figura 22.1. Ejemplo de Programa de Dibujo Scribble
22.2. Manejo de Eventos
Las seales GTK que hemos explicado son para acciones de alto nivel, tal como seleccionar un elemento de
men. Sin embargo, a veces es til aprender sobre situaciones de ms bajo nivel, como cuando se mueve un
ratn o se pulsa una tecla. Tambin hay seales para estos eventos de bajo nivel. Los manejadores de estas
seales tienen un parmetro extra que es un objeto GdkEvent que contiene informacin sobre el evento. Por
ejemplo, a los manejadores de eventos de movimiento se les pasa un objeto GdkEvent que contiene informacin
de EventMotion, la cual tiene atributos como:
type # tipo
window # ventana
time # tiempo
x
y
...
state # estado
...
225
Captulo 22. Scribble, Un Ejemplo de
Programa de Dibujo Simple
window es la ventana en la que ha ocurrido el evento.
x w y dan las coordenadas del evento.
type es el tipo de evento, en este caso MOTION_NOTIFY. Estos tipos (en el mdulo gtk.gdk) son:
NOTHING cdigo especial para indica un evento nulo.
DELETE el manejador de ventanas ha pedido que se oculte o destruya la

ventana de ms alto nivel, normalemente cuando el usuario hace clic en un icono

especial de la barra de ttulo.


DESTROY la ventana ha sido destruida.
EXPOSE todo o parte de la ventana se ha hecho visible y necesita

redibujarse.
MOTION_NOTIFY el puntero (normalmente el ratn) se ha movido.
BUTTON_PRESS se ha presionado un botn del ratn
_2BUTTON_PRESS se ha hecho doble clic en un botn del ratn. Fjate que
cada clic tambin genera un evento BUTTON_PRESS.
_3BUTTON_PRESS se ha hecho clic 3 veces seguidas dentro de un corto perodo de

tiempo en un botn del ratn. Fjate que cada clic tambin genera un evento

BUTTON_PRESS.
BUTTON_RELEASE se ha soltado un botn del ratn.
KEY_PRESS se ha pulsado una tecla.
KEY_RELEASE se ha soltado una tecla.
ENTER_NOTIFY el puntero ha entrado en la ventana.
LEAVE_NOTIFY el puntero ha salido de la ventana.
FOCUS_CHANGE el foco del teclado ha entrado o dejado la ventana.
CONFIGURE el tamao, posicin u orden de apilamiento de la ventana ha

cambiado. Fjate que GTK no usa estos eventos para ventanas hijas (GDK_WINDOW_CHILD).
MAP se han reservado recursos para la ventana.
UNMAP se han liberado recursos para la ventana.
PROPERTY_NOTIFY se ha borrado o cambiado una propiedad de la ventana.
SELECTION_CLEAR la aplicacin ha perdido la propiedad de una seleccin.
SELECTION_REQUEST otra aplicacin ha solicitado la seleccin.
SELECTION_NOTIFY se ha recibido una seleccin.
PROXIMITY_IN se ha hecho contacto en una superficie sensible de un dispositivo

de entrada (por ejemplo, una tableta grfica o pantalla sensible al tacto).


226
Captulo 22. Scribble, Un Ejemplo de
Programa de Dibujo Simple
PROXIMITY_OUT se ha perdido el contacto de una superfice sensible.
DRAG_ENTER el ratn ha entrado en la ventana mientras se estaba arrastrando

algo.
DRAG_LEAVE el ratn ha salido de la ventana mientras se estaba arrastrando

algo.
DRAG_MOTION el ratn se ha movido por la ventana mientras se estaba

arrastrando algo.
DRAG_STATUS el estado de la operacin de arrastre iniciada por la ventana ha

cambiado.
DROP_START se ha iniciado una operacin de soltar en la ventana.
DROP_FINISHED la operacin de soltar iniciada por la ventana ha terminado.
CLIENT_EVENT a message has been received from another application.
VISIBILITY_NOTIFY la visibilidad de la ventana ha cambiado.
NO_EXPOSE indica que la regin orgen estaba completamente disponible

cuando partes de un dibujable fueron copiadas. No es muy til.


SCROLL ?
WINDOW_STATE ?
SETTING ?
state especica el modicador de estado cuando ocurre el evento (es decir, especica que teclas auxiliares y
botones del ratn estaban presionados). Es una combinacin con el operador OR de algunoas de las siguientes
constantes (en el mdulo gtk.gdk):
SHIFT_MASK # mscara de maysculas
LOCK_MASK # mscara de bloqueo
CONTROL_MASK # mscara de control
MOD1_MASK # mscara del modificador 1
MOD2_MASK # mscara del modificador 2
MOD3_MASK # mscara del modificador 3
MOD4_MASK # mscara del modificador 4
MOD5_MASK # mscara del modificador 5
BUTTON1_MASK # mscara del botn 1
BUTTON2_MASK # mscara del botn 2
BUTTON3_MASK # mscara del botn 3
BUTTON4_MASK # mscara del botn 4
BUTTON5_MASK # mscara del botn 5
Como con las dems seales, para determinar qu pasa cuando ocurre un evento, llamamos al mtodo connect()
. Pero tambin tenemos que hacerle saber a GTK qu eventos queremos tratar. Para eso, llamamos al mtodo:
widget.set_events(events)
227
Captulo 22. Scribble, Un Ejemplo de
Programa de Dibujo Simple
El argumento events especica los eventos en los que estamos interesados. Es una combinacin con el operador
OR de constantes que especican diferentes tipos de eventos. Los tipos de eventos (en el mdulo gtk.gdk) son:
EXPOSURE_MASK
POINTER_MOTION_MASK
POINTER_MOTION_HINT_MASK
BUTTON_MOTION_MASK
BUTTON1_MOTION_MASK
BUTTON2_MOTION_MASK
BUTTON3_MOTION_MASK
BUTTON_PRESS_MASK
BUTTON_RELEASE_MASK
KEY_PRESS_MASK
KEY_RELEASE_MASK
ENTER_NOTIFY_MASK
LEAVE_NOTIFY_MASK
FOCUS_CHANGE_MASK
STRUCTURE_MASK
PROPERTY_CHANGE_MASK
VISIBILITY_NOTIFY_MASK
PROXIMITY_IN_MASK
PROXIMITY_OUT_MASK
SUBSTRUCTURE_MASK
Hay unas cuantas cosas que hay que tener en cuenta al llamar al mtodo set_events() . Lo primero es que tiene
que llamarse antes de que se cree la ventana X para el control PyGTK. En la prctica, esto signica que tienes que
llamarlo inmediatamente despus de crear el control. Lo segundo es que el control tiene que tener una ventana X
asociada. Por eciencia, la mayoria de los controles no tienen su propia ventana si no que se dibujan en la ventana
padre. Estos controles incluyen a:
gtk.Alignment
gtk.Arrow
gtk.Bin
gtk.Box
gtk.Image
gtk.Item
gtk.Label
gtk.Layout
gtk.Pixmap
gtk.ScrolledWindow
gtk.Separator
gtk.Table
gtk.AspectFrame
gtk.Frame
gtk.VBox
gtk.HBox
gtk.VSeparator
gtk.HSeparator
Para capturar eventos en estos controles, tienes que usar un control EventBox . Mira la seccin del control
EventBox para ms detalles.
Los atributos de los eventos que PyGTK usa para cada tipo de evento son:
228
Captulo 22. Scribble, Un Ejemplo de
Programa de Dibujo Simple
todos los eventos type # tipo
window # ventana
send_event # evento enviado
NOTHING
DELETE
DESTROY # sin atributos adicionales
EXPOSE area # rea
count # cuenta
MOTION_NOTIFY time # tiempo
x # x
y # y
pressure # presin
xtilt
ytilt
state # estado
is_hint # es pista
source # fuente
deviceid # identificador de dispositivo
x_root # x raiz
y_root # y raiz
BUTTON_PRESS
_2BUTTON_PRESS
_3BUTTON_PRESS
BUTTON_RELEASE time # tiempo
x # x
y # y
pressure # presin
xtilt
ytilt
state # estado
button # botn
source # fuente
deviceid # identificador de dispositivo
x_root # x raiz
y_root # y raiz
KEY_PRESS
KEY_RELEASE time # tiempo
state # estado
keyval # valor de tecla
string # cadena de caracteres
ENTER_NOTIFY
LEAVE_NOTIFY subwindow # subventana
time # tiempo
x # x
y # y
x_root # x raiz
y_root # y raiz
mode # modo
detail # detalle
focus # foco
state # estado
229
Captulo 22. Scribble, Un Ejemplo de
Programa de Dibujo Simple
FOCUS_CHANGE _in # dentro
CONFIGURE x # x
y # y
width # ancho
height # alto
MAP
UNMAP # sin atributos adicionales
PROPERTY_NOTIFY atom # tomo
time # tiempo
state # estado
SELECTION_CLEAR
SELECTION_REQUEST
SELECTION_NOTIFY selection # seleccin
target # objetivo
property # propiedad
requestor # solicitante
time # tiempo
PROXIMITY_IN
PROXIMITY_OUT time # tiempo
source # orgen
deviceid # identificador de dispositivo
DRAG_ENTER
DRAG_LEAVE
DRAG_MOTION
DRAG_STATUS
DROP_START
DROP_FINISHED context # contexto
time # tiempo
x_root # x raiz
y_root # y raiz
CLIENT_EVENT message_type # tipo de mensaje
data_format # formato de los datos
data # datos
VISIBILTY_NOTIFY state # estado
NO_EXPOSE # sin atributos adicionales
22.2.1. Scribble - Manejo de Eventos
Para nuestro programa de dibujo, queremos saber cundo se pulsa el botn del ratn y cuando se mueve, por
tanto especicamos POINTER_MOTION_MASK y BUTTON_PRESS_MASK. Tambin queremos saber cundo
tenemos que redibujar la ventana, por tanto especicamos EXPOSURE_MASK. Aunque queremos que nos
avisen con un evento de conguracin cuando el tamao de la ventana cambie, no tenemos que especicar el
correspondiente STRUCTURE_MASK, porque eso se hace automticamente para todas las ventanas.
Sin embargo, hay un problema si slo se especica POINTER_MOTION_MASK. El problema es que esto hace
que el servidor aada un nuevo evento de moviento a la cola de eventos cada vez que el usuario mueve el ratn.
Imagina que tardamos 0.1 segundos en tratar un evento de movimiento, pero el servidor X encola un nuevo
evento de movimiento cada 0.05 segundos. Pronto nos encontraremos muy por detrs de lo que el usuario est
230
Captulo 22. Scribble, Un Ejemplo de
Programa de Dibujo Simple
dibujando. Si el usuario est dibujando durante 5 segundos, tardaremos otros 5 segundos en recuperarnos despus
de que suelte el botn del ratn! Lo que podemos hacer es tratar un evento de movimiento por cada evento que
procesemos. La forma de hacer esto es especicar POINTER_MOTION_HINT_MASK.
Cuando especicamos POINTER_MOTION_HINT_MASK, el servidor nos manda un evento de movimiento la
primera vez que el puntero se mueve despus de entrar en la ventana, o despus de que se pulse o suelte el botn.
Los movimientos posteriores se suprimiran hasta que los pidamos explcitamente usando el siguiente mtodo de
GdkWindow :
x, y, mask = window.get_pointer()
window es un objeto gtk.gdk.Window . x e y son las coordenadas del puntero y mask es la mscara de
modicacin para detectar qu teclas estn pulsadas. (Hay un mtodo de gtk.Widget , get_pointer() que
devuelve la misma informacin que el mtodo gtk.gdk.Window.get_pointer() pero sin la informacin de la
mscara).
El programa de ejemplo scribblesimple.py [examples/scribblesimple.py] demuestra el uso bsico de eventos y
manejadores de eventos. La gura Figura 22.2. Ejemplo simple de Scribble muestra el programa en accin:
Figura 22.2. Ejemplo simple de Scribble
Los manejadores de eventos se conectan a el drawing_area (rea de dibujo) en las siguientes lineas:
90 # Signals used to handle backing pixmap
91 drawing_area.connect("expose_event", expose_event)
92 drawing_area.connect("configure_event", configure_event)
93
94 # Event signals
95 drawing_area.connect("motion_notify_event", motion_notify_event)
96 drawing_area.connect("button_press_event", button_press_event)
97
231
Captulo 22. Scribble, Un Ejemplo de
Programa de Dibujo Simple
98 drawing_area.set_events(gtk.gdk.EXPOSURE_MASK
99 | gtk.gdk.LEAVE_NOTIFY_MASK
100 | gtk.gdk.BUTTON_PRESS_MASK
101 | gtk.gdk.POINTER_MOTION_MASK
102 | gtk.gdk.POINTER_MOTION_HINT_MASK)
Los manejadores de eventos button_press_event() y motion_notify_event() en scribblesimple.py [ex-
amples/scribblesimple.py] son:
55 def button_press_event(widget, event):
56 if event.button == 1 and pixmap != None:
57 draw_brush(widget, event.x, event.y)
58 return gtk.TRUE
59
60 def motion_notify_event(widget, event):
61 if event.is_hint:
62 x, y, state = event.window.get_pointer()
63 else:
64 x = event.x
65 y = event.y
66 state = event.state
67
68 if state & gtk.gdk.BUTTON1_MASK and pixmap != None:
69 draw_brush(widget, x, y)
70
71 return gtk.TRUE
Los manejadores expose_event() y configure_event() se describirn despus.
22.3. El Control del rea de Dibujo, y Dibujar
Ahora nos toca dibujar en la pantalla. El control que usamos para eso es la DrawingArea (rea de dibujo). Un
control de rea de dibujo es esencialmente una ventana X y nada ms. Es un lienzo en blanco en el que podemos
pintar lo que queramos. Un rea de dibujo se crea usando la llamada:
darea = gtk.DrawingArea()
Se puede especicar un tamao predeterminado par ael control usando:
darea.set_size_request(width, height)
Este tamao predeterminado se puede cambiar, como en todos los controles, llamando al mtodo
set_size_request() , y esto tambin se puede modicar si el usuario cambia el tamao de la ventana
que contiene el rea de dibujo manualmente.
Hay que decir que cuando creamos un control DrawingArea , tenemos toda la responsabilidad de dibujar su
contenido. Si nuestra ventana se tapa y luego se muestra, recibimos un evento de exposicin y debemos redibujar
lo que antes se oculto.
Tener que recordar lo que haba dibujado en la pantalla para que podamos redibujarlo es, cuanto menos, un latazo.
Adems, puede distraer visualmente el hecho de que partes de la ventana se limpien, y luego se dibujen paso
232
Captulo 22. Scribble, Un Ejemplo de
Programa de Dibujo Simple
a paso. La solucin a este problema es usar un pixmap oculto. En vez de dibujar directamente en la pantalla,
dibujamos en la imagen almacenada en la memoria del servidor que no se muestra, y luego copiamos las partes
relevantes a la pantalla.
Para crear un pixmap fuera de pantalla, usamos esta funcin:
pixmap = gtk.gdk.Pixmap(window, width, height, depth=-1)
El parmetro window especica una ventana GDK de la que este pixmap tomar algunas propiedades. width
(ancho) y height (alto) especican el tamao del pixmap. depth especica la profundidad del color, es decir el
nmero de bits por pxel, de la nueva ventana. Si depth es -1 o se omite, ser la profundidad de la ventana.
Creamos el pixmap en nuestro manejador del evento "congure_event". Este evento se genera cada vez que la
ventana cambia de tamao, incluyendo cuando se crea por primera vez.
30 # Create a new backing pixmap of the appropriate size
31 def configure_event(widget, event):
32 global pixmap
33
34 x, y, width, height = widget.get_allocation()
35 pixmap = gtk.gdk.Pixmap(widget.get_window(), width, height)
36 gtk.draw_rectangle(pixmap, widget.get_style().white_gc,
37 gtk.TRUE, 0, 0, width, height)
38
39 return gtk.TRUE
La llamada a draw_rectangle() limpia el pixmap con blanco inicialmente. Comentaremos esto un poco ms
dentro de un momento.
Nuestro manejador del evento de exposicin simplemente copia las partes correspondientes del pixmap en el rea
de dibujo usando el mtodo draw_pixmap() . (Sabemos el rea que tenemos que redibujar usando el atributo
event.area attribute del evento de exposicin):
41 # Redraw the screen from the backing pixmap
42 def expose_event(widget, event):
43 x , y, width, height = event.area
44 widget.window.draw_drawable(widget.get_style().fg_gc[gtk.STATE_NORMAL],
45 pixmap, x, y, x, y, width, height)
46 return gtk.FALSE
Ya hemos visto cmo manetener la pantalla sincronizada con nuestro pixmap, pero cmo pintamos cosas
interesantes en nuestro pixmap? Hay un gran nmero de llamadas en PyGTK para dibujar en objetos dibujables.
Un objeto dibujable es simplemente algo en lo que puedes dibujar. Puede ser una ventana, un pixmap, o un
bitmap (una imagen en blanco y negro). Ya hemos visto dos de esas llamadas antes, draw_rectangle() y
draw_pixmap(). La lista completa es:
# dibuja punto
drawable.draw_point(gc, x, y)
# dibuja linea
drawable.draw_line(gc, x1, y1, x2, y2)
233
Captulo 22. Scribble, Un Ejemplo de
Programa de Dibujo Simple
# dibuja rectngulo
drawable.draw_rectangle(gc, fill, x, y, width, height)
# dibuja arco
drawable.draw_arc(gc, fill, x, y, width, height, angle1, angle2)
# dibuja polgono
drawable.draw_polygon(gc, fill, points)
# dibuja dibujable
drawable.draw_drawable(gc, src, xsrc, ysrc, xdest, ydest, width, height)
# dibuja puntos
drawable.draw_points(gc, points)
# dibuja lineas
drawable.draw_lines(gc, points)
# dibuja segmentos
drawable.draw_segments(gc, segments)
# dibuja imagen rgb
drawable.draw_rgb_image(gc, x, y, width, height, dither, buffer, rowstride)
# dibuja imagen rgb 32
drawable.draw_rgb_32_image(gc, x, y, width, height, dither, buffer, rowstride)
# dibuja imagen gris
drawable.draw_gray_image(gc, x, y, width, height, dither, buffer, rowstride)
Los mtodos del rea de dibujo son los mismos que los mtodos de dibujos de los objetos dibujables por lo
que puedes consultar la seccin Mtodos de Dibujo para ms detalles de estas funciones. Todas estas funciones
comparten los primeros argumentos. El primer argumento es un contexto grco (gc).
Un contexto grco encapsula informacin sobre cosas como los colores de fondo y frente y el ancho de linea.
PyGTk tiene un conjunto completo de funciones para crear y modicar contextos grcos, pero para dejar las
cosas fciles simplemente usaremos contextos grcos predenidos. Mira la seccin Contexto Grco , para ms
informacin sobre contextos grcos. Cada control tiene un estilo asociado (que puede modicarse en un chero
gtkrc, mira la seccin Ficheros rc de GTK.) Esto, entre otras cosas, almacena unos cuantos contextos grcos.
Algunos ejemplos para acceder a estos contextos grcos son:
widget.get_style().white_gc
widget.get_style().black_gc
widget.get_style().fg_gc[STATE_NORMAL]
widget.get_style().bg_gc[STATE_PRELIGHT]
Los campos fg_gc, bg_gc, dark_gc, y light_gc se indexan con un parmetro que puede tomar los siguientes
valores:
STATE_NORMAL, # El estado durante la operacin normal
234
Captulo 22. Scribble, Un Ejemplo de
Programa de Dibujo Simple
STATE_ACTIVE, # El control est activado, como cuando se pulsa un botn
STATE_PRELIGHT, # El puntero del ratn est sobre el control
STATE_SELECTED, # El control est seleccionado
STATE_INSENSITIVE # El control est desactivado
Por ejemplo, para STATE_SELECTED el color de frente predeterminado es blanco y el el color de fondo
predeterminado es, azul oscuro.
Nuestra funcin draw_brush() (pinta trazo), que es la que realmente dibuja en el pixmap, es la siguiente:
48 # Draw a rectangle on the screen
49 def draw_brush(widget, x, y):
50 rect = (x - 5, y - 5, 10, 10)
51 pixmap.draw_rectangle(widget.get_style().black_gc, gtk.TRUE,
52 rect[0], rect[1], rect[2], rect[3])
53 apply(widget.queue_draw_area, rect)
Despus de dibujar el rectngulo que representa el trazo en el pixmap llamamos a la funcin:
widget.queue_draw_area(x, y, width, height)
que notica a X que ese rea tiene que sera actualizada. En algn momento X generar un evento de exposicin
(posiblemente combinando las reas que se le pasan en varias llamadas a draw()) lo que har qeu se llame a
nuestro manejador del evento de exposicin para copiar las partes relevantes en la pantalla.
Ya hemos tratado el programa de dibujo completamente excepto por algunos detalles mundanos como crear la
ventana principal.
235
Captulo 23. Trucos para Escribir
Aplicaciones PyGTK
Esta seccin es simplemente una recoleccin de conocimientos, guas de estilo generales y trucos para crear
buenas aplicaciones PyGTK. Actualmente esta seccin es muy corta, pero espero que se vaya haciendo ms larga
en futuras ediciones de este tutorial.
236
Captulo 24. Contribuir
Este documento, al igual que mucho software genial existente, fue creado gratuitamente por voluntarios. Si tienes
algn conocimiento sobre algn aspecto de PyGTK que este documento no trate, por favor considera el contribuir
a este documento.
Si decides contribuir, por favor envia tu texto por correo electrnico a John Finlay (nlay@moeraki.com
[mailto:nlay@moeraki.com]). Adems, ten en cuenta que este documento en su conjunto es libre, y cualquier
adicin que proporciones tambin debe ser libre. Esto es, la gente puede usar cualquier parte de tus ejemplos en
sus programas, y se pueden distribuir copias de este documento.
Gracias.
Nota del traductor: Para cualquier contribucin relacionada con la traduccin de este documento, por favor escribe
un correo a lgs@sicem.biz [mailto:lgs@sicem.biz].
237
Apndice A. Seales GTK
Como PyGTk es un conjunto de controles orientado a objetos, tiene una jerarqua de herencia. Este mecanismo de
herencia se aplica a las seales. Por tanto, debes utilizar la jerarqua de controles cuando uses las seales listadas
en esta seccin.
A.1. GtkObject
destroy(object, data)
A.2. GtkWidget
show(GtkWidget, data)
hide(widget, data)
map(widget, data)
unmap(widget, data)
realize(widget, data)
unrealize(widget, data)
draw(widget, area, data)
draw-focus(widget, data)
draw-default(widget, data)
size-request(widget, requisition, data)
size-allocate(widget, allocation, data)
state-changed(widget, state, data)
parent-set(widget, object, data)
style-set(widget, style, data)
add-accelerator(widget, accel_signal_id, accel_group, accel_key, accel_mods,
accel_flags, data)
remove-accelerator(widget, accel_group, accel_key, accel_mods, data)
bool = event(widget, event, data)
bool = button-press-event(widget, event, data)
bool = button-release-event(widget, event, data)
bool = motion-notify-event(widget, event, data)
bool = delete-event(widget, event, data)
238
Apndice A. Seales GTK
bool = destroy-event(widget, event, data)
bool = expose-event(widget, event, data)
bool = key-press-event(widget, event, data)
bool = key-release-event(widget, event, data)
bool = enter-notify-event(widget, event, data)
bool = leave-notify-event(widget, event, data)
bool = configure-event(widget, event, data)
bool = focus-in-event(widget, event, data)
bool = focus-out-event(widget, event, data)
bool = map-event(widget, event, data)
bool = unmap-event(widget, event, data)
bool = property-notify-event(widget, event, data)
bool = selection-clear-event(widget, event, data)
bool = selection-request-event(widget, event, data)
bool = selection-notify-event(widget, event, data)
selection-get(widget, selection_data, info, time, data)
selection-received(widget, selection_data, time, data)
bool = proximity-in-event(widget, event, data)
bool = proximity-out-event(widget, event, data)
drag-begin(widget, context, data)
drag-end(widget, context, data)
drag-data-delete(widget, context, data)
drag-leave(widget, context, time, data)
bool = drag-motion(widget, context, x, y, time, data)
bool = drag-drop(widget, context, x, y, time, data)
drag-data-get(widget, context, selection_data, info, time, data)
drag-data-received(widget, context, info, time, selection_data,
info, time, data)
bool = client-event(widget, event, data)
bool = no-expose-event(widget, event, data)
239
Apndice A. Seales GTK
bool = visibility-notify-event(widget, event, data)
debug-msg(widget, string, data)
A.3. GtkData
disconnect(data_obj, data)
A.4. GtkContainer
add(container, widget, data)
remove(container, widget, data)
check-resize(container, data)
direction = focus(container, direction, data)
set-focus-child(container, widget, data)
A.5. GtkCalendar
month-changed(calendar, data)
day-selected(calendar, data)
day-selected-double-click(calendar, data)
prev-month(calendar, data)
next-month(calendar, data)
prev-year(calendar, data)
next-year(calendar, data)
A.6. GtkEditable
changed(editable, data)
insert-text(editable, new_text, text_length, position, data)
delete-text(editable, start_pos, end_pos, data)
activate(editable, data)
set-editable(editable, is_editable, data)
240
Apndice A. Seales GTK
move-cursor(editable, x, y, data)
move-word(editable, num_words, data)
move-page(editable, x, y, data)
move-to-row(editable, row, data)
move-to-column(editable, column, data)
kill-char(editable, direction, data)
kill-word(editable, drirection, data)
kill-line(editable, direction, data)
cut-clipboard(editable, data)
copy-clipboard(editable, data)
paste-clipboard(editable, data)
A.7. GtkNotebook
switch-page(noteboook, page, page_num, data)
A.8. GtkList
selection-changed(list, data)
select-child(list, widget, data)
unselect-child(list, widget, data)
A.9. GtkMenuShell
deactivate(menu_shell, data)
selection-done(menu_shell, data)
move-current(menu_shell, direction, data)
activate-current(menu_shell, force_hide, data)
cancel(menu_shell, data)
A.10. GtkToolbar
orientation-changed(toolbar, orientation, data)
241
Apndice A. Seales GTK
style-changed(toolbar, toolbar_style, data)
A.11. GtkButton
pressed(button, data)
released(button, data)
clicked(button, data)
enter(button, data)
leave(button, data)
A.12. GtkItem
select(item, data)
deselect(item, data)
toggle(item, data)
A.13. GtkWindow
set-focus(window, widget, data)
A.14. GtkHandleBox
child-attached(handle_box, widget, data)
child-detached(handle_box, widget, data)
A.15. GtkToggleButton
toggled(toggle_button, data)
A.16. GtkMenuItem
activate(menu_item, data)
activate-item(menu_item, data)
242
Apndice A. Seales GTK
A.17. GtkCheckMenuItem
toggled(check_menu_item, data)
A.18. GtkInputDialog
enable-device(input_dialog, deviceid, data)
disable-device(input_dialog, deviceid, data)
A.19. GtkColorSelection
color-changed(color_selection, data)
A.20. GtkStatusBar
text-pushed(statusbar, context_id, text, data)
text-popped(statusbar, context_id, text, data)
A.21. GtkCurve
curve-type-changed(curve, data)
A.22. GtkAdjustment
changed(adjustment, data)
value-changed(adjustment, data)
243
Apndice B. Ejemplos de Cdigo
B.1. scribblesimple.py
1 #!/usr/bin/env python
2
3 # example scribblesimple.py
4
5 # GTK - The GIMP Toolkit
6 # Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
7 # Copyright (C) 2001-2002 John Finlay
8 #
9 # This library is free software; you can redistribute it and/or
10 # modify it under the terms of the GNU Library General Public
11 # License as published by the Free Software Foundation; either
12 # version 2 of the License, or (at your option) any later version.
13 #
14 # This library 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 GNU
17 # Library General Public License for more details.
18 #
19 # You should have received a copy of the GNU Library General Public
20 # License along with this library; if not, write to the
21 # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 # Boston, MA 02111-1307, USA.
23
24
25 import gtk
26
27 # Backing pixmap for drawing area
28 pixmap = None
29
30 # Create a new backing pixmap of the appropriate size
31 def configure_event(widget, event):
32 global pixmap
33
34 x, y, width, height = widget.get_allocation()
35 pixmap = gtk.gdk.Pixmap(widget.window, width, height)
36 pixmap.draw_rectangle(widget.get_style().white_gc,
37 gtk.TRUE, 0, 0, width, height)
38
39 return gtk.TRUE
40
41 # Redraw the screen from the backing pixmap
42 def expose_event(widget, event):
43 x , y, width, height = event.area
44 widget.window.draw_drawable(widget.get_style().fg_gc[gtk.STATE_NORMAL],
45 pixmap, x, y, x, y, width, height)
46 return gtk.FALSE
47
48 # Draw a rectangle on the screen
49 def draw_brush(widget, x, y):
50 rect = (x - 5, y - 5, 10, 10)
51 pixmap.draw_rectangle(widget.get_style().black_gc, gtk.TRUE,
52 rect[0], rect[1], rect[2], rect[3])
53 widget.queue_draw_area(rect[0], rect[1], rect[2], rect[3])
244
Apndice B. Ejemplos de Cdigo
54
55 def button_press_event(widget, event):
56 if event.button == 1 and pixmap != None:
57 draw_brush(widget, event.x, event.y)
58 return gtk.TRUE
59
60 def motion_notify_event(widget, event):
61 if event.is_hint:
62 x, y, state = event.window.get_pointer()
63 else:
64 x = event.x
65 y = event.y
66 state = event.state
67
68 if state & gtk.gdk.BUTTON1_MASK and pixmap != None:
69 draw_brush(widget, x, y)
70
71 return gtk.TRUE
72
73 def main():
74 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
75 window.set_name ("Test Input")
76
77 vbox = gtk.VBox(gtk.FALSE, 0)
78 window.add(vbox)
79 vbox.show()
80
81 window.connect("destroy", gtk.mainquit)
82
83 # Create the drawing area
84 drawing_area = gtk.DrawingArea()
85 drawing_area.set_size_request(200, 200)
86 vbox.pack_start(drawing_area, gtk.TRUE, gtk.TRUE, 0)
87
88 drawing_area.show()
89
90 # Signals used to handle backing pixmap
91 drawing_area.connect("expose_event", expose_event)
92 drawing_area.connect("configure_event", configure_event)
93
94 # Event signals
95 drawing_area.connect("motion_notify_event", motion_notify_event)
96 drawing_area.connect("button_press_event", button_press_event)
97
98 drawing_area.set_events(gtk.gdk.EXPOSURE_MASK
99 | gtk.gdk.LEAVE_NOTIFY_MASK
100 | gtk.gdk.BUTTON_PRESS_MASK
101 | gtk.gdk.POINTER_MOTION_MASK
102 | gtk.gdk.POINTER_MOTION_HINT_MASK)
103
104 # .. And a quit button
105 button = gtk.Button("Quit")
106 vbox.pack_start(button, gtk.FALSE, gtk.FALSE, 0)
107
108 button.connect_object("clicked", lambda w: w.destroy(), window)
109 button.show()
110
111 window.show()
112
245
Apndice B. Ejemplos de Cdigo
113 gtk.main()
114
115 return 0
116
117 if __name__ == "__main__":
118 main()
246

También podría gustarte