Tutorial de PyGTK 2.0 Versión 2.3
Tutorial de PyGTK 2.0 Versión 2.3
Introduccin
Tabla de contenidos 1.1. Exploracin de PyGTK PyGTK 2.0 es un conjunto de mdulos que componen una interfaz Python para GTK+ 2.0. En el resto de este documento cuando se menciona PyGTK se trata de la versin 2.0 o posterior de PyGTK, y en el caso de GTK+, tambin a su versin 2.0 y siguientes. El sitio web de referencia sobre PyGTK es [Link]. El autor principal de PyGTK es:
y
que es ayudado por los desarrolladores citados en el archivo AUTHORS de la distribucin PyGTK y por la comunidad PyGTK. Python es un lenguaje de programacin interpretado, ampliable y orientado a objetos que se distribuye con un amplio conjunto de mdulos que permiten el acceso a un gran nmero de servicios del sistema operativo, servicios de internet (como HTML, XML, FTP, etc.), grficos (incluidos OpenGL, TK, etc.), funciones de manejo de cadenas, servicios de correo (IMAP, SMTP, POP3, etc.), multimedia (audio, JPEG) y servicios de criptografa. Existen adems multitud de mdulos proporcionados por terceros que aaden otros servicios. Python se distribuye bajo trminos similares a los de la licencia GPL y est disponible para los sistemas operativos Linux, Unix, Windows y Macintosh. En [Link] hay ms informacion disponible sobre Python. Su autor principal es:
y
GTK+ (GIMP Toolkit) es una librera que permite crear interfaces grficas de usuario. Se distribuye bajo la licencia LGPL, por lo que posibilita el desarrollo de software abierto, software libre, e incluso software comercial no libre que use GTK sin necesidad de pagar licencias o derechos. Se le conoce como el toolkit de GIMP porque originalmente se escribi para desarrollar el Programa de Manipulacin de Imgenes de GNU GIMP, pero GTK+ se usa ya en numerosos proyectos de software, includo el proyecto de escritorio GNOME (Entorno de Modelo de Objetos orientados a Red). GTK+ est diseada sobre GDK (Kit de Dibujo de GIMP) que, bsicamente, es una
abstraccin de las funciones de bajo nivel que acceden al sistema de ventanas (Xlib en el caso del sistema de ventanas X). Los principales autores de GTK+ son:
y y y
GTK+ es fundamentalmente 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). Existe un tercer componente, llamado Glib, que contiene diversas 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 GTK+ ya que algunas de las funciones que implementa no estn disponibles o no son estndar en otros UNIX, tales como g_strerror(). Otras incluyen mejoras a las versiones de libc, tales como g_malloc, que posee capacidades de depuracin mejoradas. Desde su versin 2.0, GLib incluye el sistema de tipos que forma la base de la jerarqua de clases de GTK+, el sistema de seales usado en sta, una API de hebras que abstrae las diferentes APIs nativas para programacin multihilo en las diversas plataformas, y la capacidad de cargar mdulos. Como ltimo componente, GTK+ usa la librera Pango para la salida de texto internacionalizado. Este tutorial describe la interfaz de Python con GTK+ y est basado en el tutorial de GTK+ 2.0 escrito por Tony Gale e Ian Main. En l se intenta documentar en la medida posible todo PyGTK, pero en ningn caso es completo. Este tutorial presupone algn conocimiento previo de Python, as de cmo se crean y ejecutan programas escritos en Python. Si no se est familiarizado con
Python, es recomendable previamente la lectura del Tutorial de Python. Este tutorial no presupone ningn conocimiento previo sobre GTK+ y si se utiliza PyGTK para aprender GTK+ sera interesante recibir comentarios acerca de este tutorial, y qu aspectos resultan problemticos. Este tutorial no describe cmo compilar o instalar Python, GTK+ o PyGTK. Este tutorial est basado en:
y y y
GTK+ desde la versin 2.0 hasta la 2.4 Python 2.2 PyGTK desde la versin 2.0 hasta la 2.4
Los ejemplos se escribieron y probaron en una RedHat 9.0. Este documento est "en obras". Por favor, consltese [Link] para localizar las actualizaciones. Me gustara mucho escuchar los problemas que aparezcan al aprender PyGTK a partir de este documento, y se aprecian los comentarios sobre cmo mejorarlo. Por favor, mira la seccin Cmo Contribuir para ms informacin. Si encuentra fallos, por favor rellene un informe de fallo en [Link] en el proyecto pygtk. Para ello, la informacin que se encuentra en [Link] sobre Bugzilla puede resultar de gran utilidad. El manual de referencia de PyGTK 2.0 se encuentra disponible en [Link] Dicho manual describe detalladamente las clases de PyGTK y, por ahora, slo se encuentra disponible en ingls. La pgina web de PyGTK ([Link]) contiene otros recursos tiles para aprender PyGTK, incluido un enlace a la extensa FAQ (Lista de Preguntas Frecuentes, tambin en ingls nicamente), y otros artculos y cursos, as como una lista de correo activa y un canal IRC (consltese [Link] para los detalles).
mdulos PyGTK se cargan por defecto al arrancar el programa. Un ejemplo simple de sesin es:
moe: 96:1095$ [Link] Python 2.2.2, PyGTK 1.99.14 (Gtk+ 2.0.6) Interactive console to manipulate GTK+ widgets. >>> w=Window() >>> b=Button('Hola') >>> [Link](b) >>> def hola(b): ... print "Hola Mundo!" ... >>> [Link]('clicked', hola) 5 >>> w.show_all() >>> Hola Mundo! Hola Mundo! Hola Mundo! >>> b.set_label("Hola a todos") >>>
En este ejemplo se crea una ventana que contiene un botn que imprime un mensaje ('Hola Mundo!') cuando se hace clic en l. El programa permite probar as fcilmente los diversos controles de GTK+ y sus interfaces PyGTK. Tambin es til el programa desarrollado por Brian McErlean para la receta de Activestate 65109 junto con algunas modificaciones para que funcione con PyGTK 2.X. En este curso lo llamamos [Link] funciona de forma parecida al programa [Link]. Nota Estos dos programas no funcionan en Microsoft Windows porque necesitan funciones especficas de Unix.
2.4. Hola Mundo Paso a Paso Para empezar nuestra introduccin a PyGTK, comenzaremos con el programa ms simple posible. Este programa ([Link]) crear una ventana de 200x200 pxeles y no es posible salir de l excepto terminando el proceso desde la consola.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #!/usr/bin/env python # example [Link] import pygtk [Link]('2.0') import gtk class Base: def __init__(self): [Link] = [Link](gtk.WINDOW_TOPLEVEL) [Link]() def main(self): [Link]() print __name__ if __name__ == "__main__": base = Base() [Link]()
Si [Link] es hecho ejecutable y se puede encontrar en la variable PATH, es posible ejecutarlo usando:
[Link]
En este caso, la lnea 1 pedir al intrprete de Python que ejecute [Link]. Las lneas 5-6 ayudan a diferenciar entre las distintas versiones de PyGTK que puedan estar instaladas en el equipo. Estas lneas indican que se desea usar la versin 2.0 de PyGTK, que comprende todas las versiones de PyGTK con 2 como nmero principal. Ello impide que el programa utilice versiones anteriores de PyGTK, en caso de que se encuentren instaladas en el sistema. Las lneas 1820 comprueban si la variable __name__ es "__main__", lo cual indica que el programa est siendo ejecutado directamente por python y no est siendo importado en un intrprete Python. En el primer caso el programa crea una nueva
instancia de la clase Base y guarda una referencia a ella en la variable base. Despus llama la funcin main() para iniciar el bucle de procesamiento de eventos de GTK. Una ventana similar a Figura 2.1, Ventana Simple PyGTK debera aparecer en tu pantalla. Figura 2.1. Ventana Simple PyGTK
La primera lnea permite al programa [Link] ser invocado desde una consola Linux o Unix asumiendo que python se encuentre en el PATH. Esta lnea aparecer como primera lnea en todos los programas de ejemplo. Las lneas 5-7 importan el mdulo PyGTK 2 e inicializan el entorno GTK+. El mdulo PyGTK define las interfaces Python de las funciones GTK+ que se usarn en el programa. Para quienes estn familiarizados con GTK+ hay que advertir que la inicializacin incluye la llamada a la funcin gtk_init(). Tambin se configuran algunas cosas por nosotros, tales como el visual por defecto, el mapa de colores, manejadores de seales predeterminados. Asimismo comprueba los argumentos que se pasan al programa desde la lnea de comandos, en busca de alguno entre:
y y y y y y
y y y y
En este caso, los borra de la lista de argumentos y deja los no coincidentes que no reconoce para que el programa lo procese o ignore. El anterior conjunto de argumentos son los que aceptan de forma estndar todos los programas GTK+. Las lneas 9-15 definen una clase de Python llamada Base que define un mtodo de inicializacin de instancia __init__(). La funcin __init__() crea una ventana de nivel superior (lnea 11) y ordena a GTK+ que la muestre (lnea 12). La [Link] se crea en la lnea 11 con el argumento gtk.WINDOW_TOPLEVEL que indica que se desea una ventana sometida a las decoraciones y posicionamiento del manejador de ventanas. En vez de crear una ventana de tamao 0x0, una ventana sin hijos tiene un tamao predeterminado de 200x200 de forma que se pueda manipular. Las lneas 14-15 definen el mtodo main() que llama a la funcin PyGTK main(), que 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 18-20 permiten al programa comenzar 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 18-20 se ejecutar. Si el programa se carga en un intrprete de Python en ejecucin, las lneas 18-20 no sern ejecutadas. La lnea 19 crea una instancia de la clase Base llamada base. Crea una [Link] y la muestra como resultado. La lnea 20 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 a la espera de eventos de las X (como pulsaciones de teclas o botones), alarmas, o notificaciones de entrada/salida de ficheros. En el ejemplo, sin embargo, los eventos son ignorados.
Ahora seguimos con un programa con un control (un botn). Es la versin PyGTK del clsico programa hola mundo ([Link] ).
1 #!/usr/bin/env python 2 3 # ejemplo [Link] 4 5 import pygtk 6 [Link]('2.0') 7 import gtk 8 9 class HelloWorld: 10 11 # Esta es una funcin de retrollamada. Se ignoran los argumentos de datos 12 # en este ejemplo. Ms sobre retrollamadas ms abajo. 13 def hello(self, widget, data=None): 14 print "Hello World" 15 16 def delete_event(self, widget, event, data=None): 17 # Si se devuelve FALSE en el gestor de la seal "delete_event", 18 # GTK emitir la seal "destroy". La devolucin de TRUE significa 19 # que no se desea la destruccin de la ventana. 20 # Esto sirve para presentar dilogos como: 'Est seguro de que desea salir?' 21 # 22 print "delete event occurred" 23 24 # Si se cambia FALSE a TRUE la ventana principal no se 25 # destruir con "delete_event". 26 return [Link] 27 28 # Otra retrollamada 29 def destroy(self, widget, data=None): 30 gtk.main_quit() 31 32 def __init__(self): 33 # se crea una ventana nueva 34 [Link] = [Link](gtk.WINDOW_TOPLEVEL) 35 36 # Cuando se enva a una ventana la seal "delete_event" (esto lo hace 37 # generalmente el gestor de ventanas, usualmente con "cerrar", o con el icono 38 # de la ventana de ttulo), pedimos que llame la funcin delete_event () 39 # definida arriba. Los datos pasados a la retrollamada son 40 # NULL y se ignoran en la funcin de retrollamada. 41 [Link]("delete_event", self.delete_event) 42
43 # Conectamos el evento "destroy" a un manejador de seal. 44 # Este evento sucede cuando llamamos gtk_widget_destroy() para la ventana, 45 # o si devolvemos FALSE en la retrollamada "delete_event". 46 [Link]("destroy", [Link]) 47 48 # Establece el grosor del borde de la ventana. 49 [Link].set_border_width(10) 50 51 # Crea un nuevo botn con la etiqueta "Hello World". 52 [Link] = [Link]("Hello World") 53 54 # Cuando el botn recibe la seal "clicked", llamar la 55 # funcin hello() a la que pasa None como argumento. La funcin hello() 56 # se define ms arriba. 57 [Link]("clicked", [Link], None) 58 59 # Esto causar la destruccin de la ventana al llamar a 60 # gtk_widget_destroy(window) cuando se produzca "clicked". De nuevo, 61 # la seal podra venir de aqu o del gestor de ventanas. 62 [Link].connect_object("clicked", [Link], [Link]) 63 64 # Esto empaqueta el botn en la ventana (un contenedor de GTK+). 65 [Link]([Link]) 66 67 # El paso final es mostrar el control recin creado. 68 [Link]() 69 70 # y la ventana 71 [Link]() 72 73 def main(self): 74 # Todas las aplicaciones de PyGTK deben tener una llamada a [Link](). Aqu se deja 75 # el control y se espera que suceda un evento (como un evento de teclado o ratn). 76 [Link]() 77 78 # Si el programa se ejecuta directamente o se pasa como argumento al intrprete 79 # de Python, entonces se crea una instancia de HelloWorld y se muestra 80 if __name__ == "__main__": 81 hello = HelloWorld() 82 [Link]()
Figura 2.2, Programa de ejemplo: Hola Mundo muestra la ventana creada por [Link].
Las variables y funciones que se definen en el mdulo PyGTK se llaman de la forma gtk.*. Por ejemplo, el programa [Link] usa:
[Link] [Link]() [Link]() [Link]()
del mdulo PyGTK. En futuras secciones no se especificar el prefijo del mdulo gtk, pero se dar por asumido. Naturalmente, los programas de ejemplo usarn los prefijos del mdulo.
Para hacer que un botn realice una accin, debemos configurar un manejador de seales que capture estas seales y llame a la funcin apropiada. Esto se hace usando un mtodo de [Link] (heredado de la clase GObject) como por ejemplo:
handler_id = [Link](name, func, func_data)
donde object es la instancia de [Link] (un control) que estar emitiendo la seal, y el primer argumento name es una cadena que contiene el nombre de la seal que se desea capturar. El segundo argumento, func, es la funcin que se quiere llamar cuando se produce el evento. El tercer argumento, func_data, son los datos que se desean pasar a la funcin func. El mtodo devuelve un handler_idque se puede usar para desconectar o bloquear el uso del manejador. La funcin especificada en el tercer argumento se llama "funcin de retrollamada", y generalmente tiene la forma:
def callback_func(widget, callback_data):
donde el primer argumento ser una referencia al widget (control) que emiti la 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 [Link]. Nota La forma anterior de declaracin de una funcin de retrollamada a seales es slo una gua general, ya que las seales especficas de los distintos controles generan diferentes parmetros de llamada. Otra llamada que se usa en el ejemplo [Link] es:
handler_id = object.connect_object(name, func, slot_object)
connect_object()
es idntica a connect(), exceptuando 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 reflejan 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 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 de los 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):
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. Los valores posibles para los tipos son:
[Link] NOTHING DELETE DESTROY EXPOSE MOTION_NOTIFY BUTTON_PRESS _2BUTTON_PRESS _3BUTTON_PRESS BUTTON_RELEASE KEY_PRESS KEY_RELEASE ENTER_NOTIFY LEAVE_NOTIFY FOCUS_CHANGE CONFIGURE MAP UNMAP PROPERTY_NOTIFY SELECTION_CLEAR SELECTION_REQUEST SELECTION_NOTIFY PROXIMITY_IN PROXIMITY_OUT DRAG_ENTER DRAG_LEAVE DRAG_MOTION DRAG_STATUS DROP_START DROP_FINISHED CLIENT_EVENT VISIBILITY_NOTIFY NO_EXPOSE SCROLL WINDOW_STATE SETTING
Para acceder a estos valores se aade el prefijo [Link]. al tipo de evento. Por ejemplo, [Link].DRAG_ENTER.
Por tanto, para conectar una funcin de retrollamada a uno de estos eventos se usara algo como:
[Link]("button_press_event", button_press_callback)
Esto asume que button es un control [Link]. Entonces, cuando el ratn est sobre el botn y se pulse un botn del ratn, se llamar a la funcin button_press_callback. Esta funcin se puede definir 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 [Link] indicamos que el evento ha sido procesado, y que no debe ser propagado. Devolviendo [Link] se continua el procesamiento normal del evento. Es aconsejable consultar la seccin Procesamiento Avanzado de Eventos y Seales para obtener ms detalles sobre el sistema de propagacin. Las APIs de seleccin y arrastrar y soltar de GDK tambin emiten unos cuantos eventos que se reflejan en GTK+ por medio de seales. Consulta Seales en el Control de Orgen y Seales en el Control de Destino para obtener ms detalles sobre la sintaxis 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
Las lneas 13-14 definen el mtodo de retrollamada hello() que ser llamado al pulsar el botn. Cuando se llama a este mtodo, se imprime "Hello World" en la consola. En el 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 define con un valor predeterminado igual a None porque PyGTK no pasar ningn valor para los datos si no son incluidos en la llamada a connect(); esto producira un error ya que la retrollamada espera tres argumentos y nicamente recibe dos. La definicin de un valor por defectoNone 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 qu botn fue pulsado.
def hello(self, widget, data=None): print "Hello World"
La siguiente retrollamada (lneas 16-26) 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 se devuelva en esta retrollamada le permite a GTK+ saber qu accin realizar. Si devolvemos TRUE hacemos saber que no queremos que se emita la seal "destroy", y as nuestra aplicacin sigue ejecutndose. Si devolvemos 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 mayor claridad.
def delete_event(widget, event, data=None): print "delete event occurred" return [Link]
El mtodo de retrollamada destroy() (lneas 29-30) hace que el programa termine mediante la lllamada a gtk.main_quit(). Esta funcin indica a GTK que debe salir de la funcin [Link]() cuando el control le sea transferido.
def destroy(widget, data=None): gtk.main_quit()
Las lneas 32-71 definen 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 34 crea una nueva ventana, pero no se muestra directamente hasta que comunicamos a GTK+ que lo haga, casi al final del programa. La referencia a la ventana se guarda en un atributo de instancia ([Link]) para poder acceder a ella despus.
[Link] = [Link](gtk.WINDOW_TOPLEVEL)
Las lneas 41 y 46 ilustran dos ejemplos de cmo conectar un manejador de seal a un objeto, en este caso a window. Aqu se captura 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 [Link]. La segunda se emite cuando, en el manejador de "delete_event", devolvemos FALSE.
[Link]("delete_event", self.delete_event) [Link]("destroy", [Link])
La lnea 49 establece un atributo de un objeto contenedor (en este caso window) para que tenga un rea vaca de 10 pxeles de ancho a su alrededor en donde no se site ningn control. Hay otras funciones similares que se tratarn en la seccin Establecimiento de Atributos de Controles
[Link].set_border_width(10)
La lnea 52 crea un nuevo botn y guarda una referencia a l en [Link]. El botn tendr la etiqueta "Hello World" cuando se muestre.
[Link] = [Link]("Hello World")
En la lnea 57 conectamos un manejador de seal al botn, de forma que, cuando emita la seal "clicked", se llame a nuestro manejador de retrollamada hello(). No pasamos ningn dato a hello() as que simplemente se entrega None como dato. Obviamente, la seal "clicked" se emite al hacer clic en el botn con el cursor del ratn. El valor del parmetro de los datos None no es imprescindible y podra omitirse. La retrollamada se llamar con un parmetro menos.
[Link]("clicked", [Link], None)
Tambin vamos a usar este botn para salir del programa. La lnea 62 muestra cmo la seal "destroy" puede venir del manejador de ventanas, o de nuestro programa. Al hacer clic en el botn, al igual que antes, se llama primero a la retrollamada hello(), y despus a la siguiente en el orden en el que han sido configuradas. Se pueden tener todas las retrollamadas que sean necesarias, y se ejecutarn en el orden en el que se hayan conectado. Como queremos usar el mtodo destroy() de la clase [Link] 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 del botn. Cuando se llama el mtodo destroy() de la clase [Link] se emite la seal "destroy" desde la ventana, lo que a su vez provocar la llamada al mtodo destroy() de la clase HelloWorld que termina el programa.
[Link].connect_object("clicked", [Link], [Link])
La lnea 65 es una llamada de colocacin, que se explicar en profundidad ms tarde, en Colocacin de Controles , aunque es bastante fcil de entender. Simplemente indica a GTK+ que el botn debe situarse en la ventana en donde se va a mostrar. Ha de tenerse en cuenta que un contenedor GTK+ nicamente puede contener un control. Otros controles, descritos ms adelante, estn diseados para posicionar varios controles de otras maneras.
[Link]([Link])
Ahora lo tenemos todo configurado como queremos. Con todos los manejadores de seales, y el botn situado en la ventana donde debera estar, pedimos a GTK (lneas 66 y 69) que muestre los controles en pantalla. El control de ventana se muestra en ltimo lugar, para que la ventana entera aparezca de una vez y no primero la ventana y luego el botn dentro de ella dibujndose. Sin embargo, con un ejemplo tan simple, sera difcil apreciar la diferencia.
[Link]() [Link]()
Las lneas 73-75 definen el mtodo main() que llama a la funcin [Link]()
Las lneas 80-82 permiten al programa ejecutarse automticamente si es llamado directamente o como argumento del intrprete de python. La lnea 81 crea una instancia de la clase HelloWorld y guarda una referencia a ella en la variable hello. La lnea 82 llama al mtodo main() de la clase HelloWorld para empezar el bucle de procesamiento de eventos GTK.
if __name__ == "__main__": hello = HelloWorld() [Link]()
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 configura un manejador de seal que capture esta seal, la cual llama a la funcin que decidamos. En nuestro ejemplo, cuando se pulsa el botn que hemos creado, 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 que la ventana emita la seal "destroy", que es capturada y llama al mtodo destroy() de la clase HelloWorld Otra funcin de los eventos es usar el manejador de ventanas para eliminar la ventana, lo que causar que se emita "delete_event". Esto llamar a nuestro manejador de "delete_event". Si devolvemos TRUEaqu, 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+.
Captulo 3. Avanzando
Tabla de contenidos 3.1. Ms sobre manejadores de seales 3.2. Un Hola Mundo Mejorado
El valor de retorno de connect() es un nmero entero que identifica la retrollamada. Como ya se ha mencionado, es posible disponer de tantas retrollamadas por seal como sea necesario, y cada una de ellas se ejecutar por turnos, en el mismo orden de conexin. Este identificador permite eliminar la retrollamada de la lista de retrollamadas activas mediante el mtodo:
[Link](id)
As, pasando el identificador devuelto por los mtodos de conexin, es posible desconectar un manejador de seal. Tambin es posible deshabilitar temporalmente un manejador de seal mediante los mtodos signal_handler_block() y signal_handler_unblock().
object.signal_handler_block(handler_id) object.signal_handler_unblock(handler_id)
21 def __init__(self): 22 # Creamos una ventana 23 [Link] = [Link](gtk.WINDOW_TOPLEVEL) 24 25 # Esta llamada establece el ttulo de la 26 # ventana como "Hello Buttons!" 27 [Link].set_title("Hello Buttons!") 28 29 # Aqu establecemos un manejador para delete_event que 30 # sale inmediatamente de GTK+. 31 [Link]("delete_event", self.delete_event) 32 33 # Establece el grosor del borde de la ventana 34 [Link].set_border_width(10) 35 36 # Creamos una caja en la que empaquetar los controles. Esto se describe detalladamente 37 # en la seccin de "empaquetado". La caja no es visible en realidad sino que simplemente 38 # facilita la organizacin de los controles. 39 self.box1 = [Link]([Link], 0) 40 41 # Introducimos la caja en la ventana principal 42 [Link](self.box1) 43 44 # Crea un nuevo botn con la etiqueta "Button 1". 45 self.button1 = [Link]("Button 1") 46 47 # Ahora, cuando se pulsa el botn, llamamos al mtodo "callback" 48 # con un puntero a "button 1" como argumento 49 [Link]("clicked", [Link], "button 1") 50 51 # En vez de usar add(), empaquetamos este botn en la caja visible 52 # que ha sido introducida en la ventana. 53 self.box1.pack_start(self.button1, [Link], [Link], 0) 54 55 # Hay que recordar siempre este paso, que indica a GTK+ que la preparacin del 56 # botn ha terminado y que ya es posible mostrarlo. 57 [Link]() 58 59 # Seguimos los mismos pasos para crear el segundo botn 60 self.button2 = [Link]("Button 2") 61 62 # Llamamos la misma retrollamada pero con un argumento diferente, 63 # haciendo referencia a "button 2" esta vez. 64 [Link]("clicked", [Link], "button 2") 65 66 self.box1.pack_start(self.button2, [Link], [Link], 0)
67 68 # El orden en que mostramos los botones no es muy importante, pero es recomendable 69 # mostrar la ventana en ltimo lugar, puesto que as aparece todo de una vez. 70 [Link]() 71 [Link]() 72 [Link]() 73 74 def main(): 75 [Link]() 76 77 if __name__ == "__main__": 78 hello = HelloWorld2() 79 main()
Al ejecutar [Link] se genera la ventana de la Figura 3.1, Ejemplo mejorado de Hola Mundo. Figura 3.1. Ejemplo mejorado de Hola Mundo
Esta vez se puede ver que no hay forma fcil de salir del programa, y resulta necesario usar el gestor de ventanas o la lnea de comandos para eliminarlo. Un buen ejercicio para el lector sera insertar un tercer botn "Salir" que cerrara el programa. Sera interesante jugar con las opciones de pack_start() al tiempo que se lee la siguiente seccin, as como probar a cambiar de tamao la ventana y observar qu sucede. Como nota, hay que mencionar otra constante til para [Link]() WINDOW_DIALOG. Este tipo de ventana interacta de forma distinta con el gestor de ventanas y debe usarse en ventanas de uso transitorio. A continuacin se describen en orden las pequeas diferencias del cdigo respecto a la versin inicial del programa "Hola Mundo": Como ya se ha dicho, no existe manejador del evento "destroy" en esta versin mejorada de "Hola Mundo".
Las lneas 13-14 definen un mtodo de retrollamada similar a la retrollamada hello() del ejemplo inicial. La diferencia reside en que ahora la retrollamada imprime un mensaje que incluye los datos que se le suministran. La lnea 27 pone ttulo a la barra de ttulo de la ventana (vase la Figura 3.1, Ejemplo mejorado de Hola Mundo). La lnea 39 crea una caja horizontal ([Link]) que almacena los dos botones que se crean en las lneas 45 y 60. La lnea 42 aade la caja horizontal al contenedor de la ventana. Las lneas 49 y 64 conectan el mtodo callback() a la seal "clicked" de los botones. Y cada botn establece una cadena diferente que se pasa al mtodo callback() al ser invocado. Las lneas 53 y 66 empaquetan los botones en la caja horizontal. Y, finalmente, las lneas 57 y 70 indican a GTK+ que muestre los botones. Las lneas 71-72 piden finalmente a GTK+ que muestre la caja y la ventana.
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 se empaqueta en la hbox de la misma manera (con los mismos argumentos al mtodo pack_start() ). Este es un ejemplo del mtodo pack_start():
box.pack_start(child, expand, fill, padding)
es la caja donde se empaqueta el objeto. El primer argumento, child, es el objeto que se va a empaquetar. Por ahora los objetos sern botones, con lo que estaramos empaquetando botones dentro de cajas.
box
El argumento expand de pack_start() y pack_end() controla si los controles se disponen de forma que ocupen todo el espacio extra de la caja y, de esta manera, sta se expande hasta ocupar todo el rea reservada para ella (TRUE); o si se encoge para ocupar el espacio justo de los controles (FALSE). Poner expand a FALSE permite justificar a la derecha y a la izquierda los controles. Si no, se expandirn para llenar la caja, y el mismo efecto podra obtenerse usando slo o pack_start() o pack_end(). El argumento fill controla si el espacio extra se utiliza en los propios objetos (TRUE) o como espacio extra en la caja alrededor de los objetos (FALSE). Slo tiene efecto si el argumento expand tambin esTRUE. Python permite definir un mtodo o funcin con valores de argumento predeterminados y argumentos con nombre. A lo largo de este tutorial se ver la definicin de las funciones y mtodos con valores predeterminados y argumentos
con nombre cuando sean de aplicacin. Por ejemplo, el mtodo pack_start se define as:
box.pack_start(child, expand=[Link], fill=[Link], padding=0) box.pack_end(child, expand=[Link], fill=[Link], padding=0) child, expand, fill
y padding son palabras clave (argumentos con nombre). Los argumentos expand, fill y padding tienen los valores predeterminados (o "por defecto") mostrados arriba. El argumento child debe especificarse obligatoriamente al no tener un valor predeterminado. Las funciones que nos permiten crear una caja nueva son:
hbox = [Link](homogeneous=[Link], spacing=0) vbox = [Link](homogeneous=[Link], spacing=0)
El argumento homogeneous de [Link]() y [Link]() controla si cada objeto de la caja tiene el mismo tamao (por ejemplo, el mismo ancho en una hbox, o la misma altura en una vbox). Si se usa, las rutinas de empaquetado funcionan basicamente como si el argumento expand estuviera siempre activado. Qu diferencia existe entre spacing (se fija al crear la caja) y padding (se determina al empaquetar los elementos)? El spacing se aade entre objetos, y el padding se aade a cada lado de un objeto. La Figura 4.2, Empaquetado con Spacing y Padding ilustra la diferencia, pasando un argumento de 2 a [Link] : Figura 4.2. Empaquetado con Spacing y Padding
La Figura 4.3, Empaquetado con pack_end() ilustra el uso del mtodo pack_end() (pasa un argumento de 3 a [Link]). La etiqueta "end" se empaqueta con el mtodo pack_end(). Se mantendr en el borde derecho de la ventana cuando sta se redimensione. Figura 4.3. Empaquetado con pack_end()
27 [Link]() 28 29 # Creamos un botn con una etiqueta que depende del valor de 30 # expand. 31 if expand == [Link]: 32 button = [Link]("TRUE,") 33 else: 34 button = [Link]("FALSE,") 35 36 box.pack_start(button, expand, fill, padding) 37 [Link]() 38 39 # Aqu hacemos lo mismo que en la creacin del botn de "expand" 40 # anterior, pero usa la forma abreviada. 41 button = [Link](("FALSE,", "TRUE,")[fill==[Link]]) 42 box.pack_start(button, expand, fill, padding) 43 [Link]() 44 45 padstr = "%d)" % padding 46 47 button = [Link](padstr) 48 box.pack_start(button, expand, fill, padding) 49 [Link]() 50 return box 51 52 class PackBox1: 53 def delete_event(self, widget, event, data=None): 54 gtk.main_quit() 55 return [Link] 56 57 def __init__(self, which): 58 59 # Creamos nuestra ventana 60 [Link] = [Link](gtk.WINDOW_TOPLEVEL) 61 62 # Siempre debemos recordar la conexin de la seal delete_event 63 # a la ventana principal. Esto es muy importante de cara a un comportamiento 64 # intuitivo adecuado 65 [Link]("delete_event", self.delete_event) 66 [Link].set_border_width(10) 67 68 # Creamos una caja vertical (vbox) en la que empaquetar las cajas horizontales. 69 # Esto nos permite apilar las cajas horizontales llenas de botones 70 # una encima de otra en esta vbox. 71 box1 = [Link]([Link], 0) 72 73 # qu ejemplo mostramos. stos se corresponden a las imgenes anteriores. 74 if which == 1:
75 # creamos una etiqueta nueva. 76 label = [Link]("HBox(FALSE, 0)") 77 78 # Alineamos la etiqueta al lado izquierdo. Comentaremos este y otros 79 # mtodos en la seccin sobre Atributos de los Controles. 80 label.set_alignment(0, 0) 81 82 # Empaquetamos la etiqueta en la caja vertical (vbox box1). Recurdese que 83 # los controles que se aaden a una caja vertical se apilan uno encima del otro 84 # en orden. 85 box1.pack_start(label, [Link], [Link], 0) 86 87 # Mostramos la etiqueta 88 [Link]() 89 90 # Llamamos a nuestra funcin de crear caja homogeneous = FALSE, spacing = 0, 91 # expand = FALSE, fill = FALSE, padding = 0 92 box2 = make_box([Link], 0, [Link], [Link], 0) 93 box1.pack_start(box2, [Link], [Link], 0) 94 [Link]() 95 96 # Llamamos a nuestra funcin de crear caja homogeneous = FALSE, spacing = 0, 97 # expand = TRUE, fill = FALSE, padding = 0 98 box2 = make_box([Link], 0, [Link], [Link], 0) 99 box1.pack_start(box2, [Link], [Link], 0) 100 [Link]() 101 102 # Los argumentos son: homogeneous, spacing, expand, fill, padding 103 box2 = make_box([Link], 0, [Link], [Link], 0) 104 box1.pack_start(box2, [Link], [Link], 0) 105 [Link]() 106 107 # Crea un separador, que veremos qu hacen ms adelante, 108 # aunque son muy simples. 109 separator = [Link]() 110 111 # Empaquetamos el separador en la vbox. Recurdese que empaquetamos todos estos 112 # controles en una vbox, por lo que se apilarn 113 # verticalmente. 114 box1.pack_start(separator, [Link], [Link], 5) 115 [Link]() 116 117 # Creamos otra etiqueta y la mostramos. 118 label = [Link]("HBox(TRUE, 0)") 119 label.set_alignment(0, 0)
120 box1.pack_start(label, [Link], [Link], 0) 121 [Link]() 122 123 # Los argumentos son: homogeneous, spacing, expand, fill, padding 124 box2 = make_box([Link], 0, [Link], [Link], 0) 125 box1.pack_start(box2, [Link], [Link], 0) 126 [Link]() 127 128 # Los argumentos son: homogeneous, spacing, expand, fill, padding 129 box2 = make_box([Link], 0, [Link], [Link], 0) 130 box1.pack_start(box2, [Link], [Link], 0) 131 [Link]() 132 133 # Otro separador. 134 separator = [Link]() 135 # Los ltimos 3 argumentos de pack_start son: 136 # expand, fill, padding. 137 box1.pack_start(separator, [Link], [Link], 5) 138 [Link]() 139 elif which == 2: 140 # Creamos una etiqueta nueva, recordando que box1 es una vbox creada 141 # cerca del comienzo de __init__() 142 label = [Link]("HBox(FALSE, 10)") 143 label.set_alignment( 0, 0) 144 box1.pack_start(label, [Link], [Link], 0) 145 [Link]() 146 147 # Los argumentos son: homogeneous, spacing, expand, fill, padding 148 box2 = make_box([Link], 10, [Link], [Link], 0) 149 box1.pack_start(box2, [Link], [Link], 0) 150 [Link]() 151 152 # Los argumentos son: homogeneous, spacing, expand, fill, padding 153 box2 = make_box([Link], 10, [Link], [Link], 0) 154 box1.pack_start(box2, [Link], [Link], 0) 155 [Link]() 156 157 separator = [Link]() 158 # Los ltimos 3 argumentos de pack_start son: 159 # expand, fill, padding. 160 box1.pack_start(separator, [Link], [Link], 5) 161 [Link]() 162 163 label = [Link]("HBox(FALSE, 0)") 164 label.set_alignment(0, 0) 165 box1.pack_start(label, [Link], [Link], 0) 166 [Link]() 167 168 # Los argumentos son: homogeneous, spacing, expand,
fill, padding 169 box2 = make_box([Link], 0, [Link], [Link], 10) 170 box1.pack_start(box2, [Link], [Link], 0) 171 [Link]() 172 173 # Los argumentos son: homogeneous, spacing, expand, fill, padding 174 box2 = make_box([Link], 0, [Link], [Link], 10) 175 box1.pack_start(box2, [Link], [Link], 0) 176 [Link]() 177 178 separator = [Link]() 179 # Los ltimos 3 argumentos de pack_start son: 180 # expand, fill, padding. 181 box1.pack_start(separator, [Link], [Link], 5) 182 [Link]() 183 184 elif which == 3: 185 186 # Esto ilustra la posibilidad de usar pack_end() para 187 # alinear los controles a la derecha. Primero creamos una caja nueva, como antes. 188 box2 = make_box([Link], 0, [Link], [Link], 0) 189 190 # Creamos la etiqueta que pondremos al final. 191 label = [Link]("end") 192 # La empaquetamos con pack_end(), por lo que se pone en el extremo derecho 193 # de la hbox creada en la llamada a make_box(). 194 box2.pack_end(label, [Link], [Link], 0) 195 # Mostramos la etiqueta. 196 [Link]() 197 198 # Empaquetamos la box2 en box1 199 box1.pack_start(box2, [Link], [Link], 0) 200 [Link]() 201 202 # Un separador para la parte de abajo. 203 separator = [Link]() 204 205 # Esto establece explcitamente el ancho del separador a 400 pxeles y 5 206 # pxeles de alto. As la hbox que creamos tambin tendra 400 207 # pxeles de ancho, y la etiqueta "end" estar separada de las otras 208 # de la hbox. En otro caso, todos los controles de la 209 # hbox estaran empaquetados lo ms juntos posible. 210 separator.set_size_request(400, 5) 211 # empaquetamos el separador en la vbox (box1) creada cerca del principio 212 # de __init__() 213 box1.pack_start(separator, [Link], [Link], 5) 214 [Link]()
215 216 # Creamos otra hbox nueva. Recordemos que podramos usar cuantas queramos! 217 quitbox = [Link]([Link], 0) 218 219 # Nuestro botn de salida. 220 button = [Link]("Quit") 221 222 # Configuramos la seal que finalice el programa al pulsar el botn 223 [Link]("clicked", lambda w: gtk.main_quit()) 224 # Empaquetamos el botn en la quitbox. 225 # Los 3 ltimos argumentos de pack_start son: 226 # expand, fill, padding. 227 quitbox.pack_start(button, [Link], [Link], 0) 228 # empaquetamos la quitbox en la vbox (box1) 229 box1.pack_start(quitbox, [Link], [Link], 0) 230 231 # Empaquetamos la vbox (box1), que ahora contiene todos los controles, 232 # en la ventana principal. 233 [Link](box1) 234 235 # Y mostramos todo lo que queda 236 [Link]() 237 [Link]() 238 239 [Link]() 240 # Mostrando la ventana al final de forma que todo aparezca de una vez. 241 [Link]() 242 243 def main(): 244 # y, naturalmente, el bucle de eventos principal. 245 [Link]() 246 # El control se devuelve a este punto cuando se llama a main_quit(). 247 return 0 248 249 if __name__ =="__main__": 250 if len([Link]) != 2: 251 [Link]("usage: [Link] num, where num is 1, 2, or 3.\n") 252 [Link](1) 253 PackBox1([Link]([Link][1])) 254 main()
El pequeo tour por el cdigo [Link] empieza por las lineas 14-50 que definen una funcin auxiliar make_box que crea una caja horizontal y la rellena con botones segn los parmetros especficados. Devuelve una referencia a la caja horizontal.
Las lineas 52-241 definen el mtodo de inicializacin __init__() de la clase PackBox1 que crea una ventana y una caja vertical en ella que se rellena con una configuracin de controles que depende del argumento que recibe. Si se le pasa un 1, las lineas 75-138 crean una ventana que muestra las cinco nicas posibilidades que resultan de variar los parmetros homogeneous, expand y fill. Si se le pasa un 2, las lineas 140-182 crean una ventana que muesstra las diferentes combinaciones de fill con spacing y padding. Finalmente, si se le pasa un 3, las lineas 188-214 crean una ventana que muestra el uso del mtodo pack_start() para justificar los botones a la izquierda y el mtodo pack_end() para justificar 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 gtk.main_quit() para terminar el programa. Las lineas 250-252 comprueban los argumentos de la lnea de comandos y terminan el programa usando la funcin [Link]() si no hay exactamente un argumento. La lnea 251 crea una instancia de PackBox1. La lnea 253 llama a la funcin [Link]() para empezar el bucle de procesamiento de eventos GTK+. En este programa de ejemplo, las referencias a los controles (excepto a la ventana) no se guardan en los atributos de instancia del objeto porque no se necesitan ms tarde.
El primer argumento es el nmero de filas de la tabla, mientras que el segundo, obviamente, es el nmero de columnas. El argumento homogeneous tiene que ver con el tamao de las celdas de la tabla. Si homogeneous es TRUE, las celdas de la tabla tienen el tamao del mayor control
en ella. Si homogeneous es FALSE, el tamao de las celdas viene dado por el control ms alto de su misma fila, y el control ms ancho de su columna. Las filas y las columnas se disponen de 0 a n, donde n es el nmero que se especific en la llamada a [Link](). Por tanto, si se especifica rows (filas) = 2 y columns (columnas) = 2, la dispoisicin quedara as:
0 1 2 0+----------+----------+ | | | 1+----------+----------+ | | | 2+----------+----------+
Obsrvese que el sistema de coordenadas tiene su orgien en la esquina superior izquierda. Para introducir un control en una caja, se usa el siguiente mtodo:
[Link](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 se cre con [Link](). El primer parmetro ("child") es el control que se desea introducir en la tabla. Los argumentos left_attach, right_attach, top_attach y bottom_attach especifican dnde situar el control, y cuntas cajas usar. Si se quiere poner un botn en la esquina inferior derecha de una tabla 2x2, y se quiere que ocupe SLO ese espacio, left_attach sera = 1, right_attach = 2, top_attach = 1, bottom_attach = 2. Ahora, si se desea que un control ocupe la fila entera de la tabla 2x2, se pondra left_attach = 0, right_attach = 2, top_attach = 0, bottom_attach = 1. Los argumentos xoptions e yoptions se usan para especificar opciones de colocacin y pueden unirse mediante la operacin OR, permitiendo as mltiples opciones. Estas opciones son:
FILL
expandir hasta usar todo el espacio disponible. Si se le asigna menos espacio a la tabla del que solicit (normalmente porque el usuario ha redimensionado la ventana), entonces los controles normalmente sera SHRINK empujados a la parte inferior de la ventana y desapareceran. Si se especifica SHRINK, los controles se encojern 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 especificado en pxeles alrededor del control. Tambin tenemos los mtodos set_row_spacing() y set_col_spacing(), que aaden espacio entre las filas en la columna o fila especificada.
table.set_row_spacing(row, spacing)
y
table.set_col_spacing(column, spacing)
Obsrvese que, para las columnas, el espacio va a la derecha de la columna, y, para las filas, el espacio va debajo de la fila. Tambin se puede poner un espacio igual en todas las filas y/o columnas con:
table.set_row_spacings(spacing)
y,
table.set_col_spacings(spacing)
Obsrvese que con stas funciones, la ltima fila y la ltima columna no obtienen ningn espacio.
40 # Creamos el primer botn 41 button = [Link]("button 1") 42 43 # Cuando se pulsa el botn llamamos al mtodo "callback" 44 # con una indicacin a "button 1" como argumento. 45 [Link]("clicked", [Link], "button 1") 46 47 48 # Insertamos el botn 1 en el cuadrante superior izquierdo de la tabla. 49 [Link](button, 0, 1, 0, 1) 50 51 [Link]() 52 53 # Creamos el segundo botn. 54 55 button = [Link]("button 2") 56 57 # Cuando se pulsa el botn llamamos al mtodo "callback" 58 # con una indicacin a "button 2" como argumento. 59 [Link]("clicked", [Link], "button 2") 60 # Insertamos el botn 2 en el cuadrante superior derecho de la tabla. 61 [Link](button, 1, 2, 0, 1) 62 63 [Link]() 64 65 # Creamos el botn de salida "Quit" 66 button = [Link]("Quit") 67 68 # Cuando se pulsa el botn llamamos a la funcin main_quit y 69 # el programa se termina 70 [Link]("clicked", lambda w: gtk.main_quit()) 71 72 # Insertamos el botn de salida en los dos cuadrantes inferiores de la tabla 73 [Link](button, 0, 2, 1, 2) 74 75 [Link]() 76 77 [Link]() 78 [Link]() 79 80 def main(): 81 [Link]() 82 return 0 83 84 if __name__ == "__main__": 85 Table() 86 main()
La clase Table se define en las lneas 9-78. Las lneas 12-13 definen el mtodo callback() que se llama al hacer "click" en dos de los botones. La retrollamada slo imprime un mensaje en la consola indicando qu botn se puls usando los datos que se le pasan. Las lineas 16-18 definen el mtodo delete_event() que se llama cuando el manejador de ventanas le pide a la ventana que se elimine. Las lneas 20-78 definen el constructor de la clase Table __init__(). Crea una ventana (lnea 22), le pone el ttulo (lnea 25), conecta la retrollamada delete_event() a la seal "delete_event" (lnea 29), y le pone el ancho al borde (lnea 32). Se crea una [Link] en la lnea 35 y se aade a la ventana en la lnea 38. Los dos botones superiores se crean en las lneas 41 y 55, sus seales "clicked" se conectan al mtodo callback() en las lneas 45 y 59; y se aaden a la tabla en la primera fila en las lneas 49 y 61. Las lneas 66-72 crean el botn "Quit", conectan su seal "clicked" a la funcin mainquit() y lo aaden a la tabla ocupando la fila inferior completa.
Se llama a gtk.* (una de las mltiples funciones para crear un nuevo control, y que se detallan en esta seccin. Se conectan todas la seales y eventos que queramos usar a los manejadores apropiados. Se establecen los atributos del control. Se empaqueta el control dentro de un contenedor usando una llamada como [Link]() o [Link].pack_start(). Se llama a [Link]() en el control.
show()
le permite saber a GTK que hemos terminado de configurar los atributos del control, y est listo para ser mostrado. Tambin se puede usar [Link]() para que desaparezca otra vez. El orden en el que se muestran los controles no es importante, pero es conveniente que se muestre la ventana al final de modo que la toda la ventana aparezca de una vez y no se vea como van apareciendo los controles individuales en la ventana a medida que se van formando. Los hijos de un control (una ventana tambin es un control) no se mostrarn hasta que la propia ventana se muestre usando el mtodoshow() .
| | | | | | +[Link] (Dilogo de Entrada de Datos) | | | | | | `[Link] (Dilogo de Mensaje) | | | | | `[Link] (Conectable) | | | | +[Link] (Caja con Lista Desplegable) | | | | | `[Link] (Entrada de Caja de Lista Desplegable) | | | | +[Link] (Caja de Eventos) | | | | +[Link] (Expansin) | | | | +[Link] (Manejador de Caja) | | | | +[Link] (Elemento de Barra de Herramientas) | | | | | +[Link] (Botn de Barra de Herramientas) | | | | | | +[Link] (Botn Biestado de Barra de Herramientas) | | | | | | | `[Link] (Botn de Exclusin Mtua de Barra de Herramientas) | | | | | `[Link] (Separador de Elementos de Barra de Herramientas) | | | | +[Link] (Ventana de Desplazamiento) | | | | `[Link] (Vista) | | | +[Link] (Caja) | | | | +[Link] (Caja de Botones) | | | | | +[Link] (Caja de Botones Horizontal) | | | | | `[Link] (Caja de Botones Vertical) | | | | +[Link] (Caja Vertical) | | | | | +[Link] (Selector de Colores) | | | | | +[Link] (Selector de Tipos de Letra) | | | | | `[Link] (Curva Gamma) | | | | `[Link] (Caja Horizontal) | | | | +[Link] (Lista Desplegable) | | | | `[Link] (Barra de Estado) | | | +[Link] (Fijo) | | | +[Link] (Panel) | | | | +[Link] (Panel Horizontal) | | | | `[Link] (Panel Vertical) | | | +[Link] (Disposicin) | | | +[Link] (Consola de Men) | | | | +[Link] (Barra de Men) | | | | `[Link] (Men) | | | +[Link] (Cuaderno de Fichas) | | | +[Link] (Socket) | | | +[Link] (Tabla) | | | +[Link] (Vista de Texto) | | | +[Link] (Barra de Herramientas) | | | `[Link] (Vista de rbol) | | +[Link] (Calendario) | | +[Link] (rea de Dibujo) | | | `[Link] (Curva) | | +[Link] (Entrada de Texto) | | | `[Link] (Botn Aumentar/Disminuir) | | +[Link] (Regla) | | | +[Link] (Regla Horizontal) | | | `[Link] (Regla Vertical) | | +[Link] (Rango) | | | +[Link] (Escala) | | | | +[Link] (Escala Horizontal)
| | | | `[Link] (Escala Vertical) | | | `[Link] (Barra de Desplazamiento) | | | +[Link] (Barra de Desplazamiento Horizontal) | | | `[Link] (Barra de Desplazamiento Vertical) | | +[Link] (Separador) | | | +[Link] (Separador Horizontal) | | | `[Link] (Separador Vertical) | | +[Link] (Invisible) | | +[Link] (Elemento de Progreso) | | | `[Link] (Barra de Progreso) | +[Link] (Ajuste) | +[Link] (Visualizador de Celda) | | +[Link] (Visualizador de Imgen de Celda) | | +[Link] (Visualizador de Texto de Celda) | | +[Link] (Visualizador de Activacin de Celda) | +[Link] (Filtro de Seleccin de Archivos) | +[Link] (Factora de Elementos) | +[Link] (Pistas) | `[Link] (Columna de Vista de rbol) +[Link] (Accin) | +[Link] (Accin Biestado) | | `[Link] (Accin de Exclusin Mtua) +[Link] (Grupo de Acciones) +[Link] (Completado de Entrada) +[Link] (Factora de Iconos) +[Link] (Tema de Iconos) +[Link] (Contexto de Mtodo de Entrada) | +[Link] (Contexto Simple de Mtodo de Entrada) | `[Link] (Contexto Mltiple de Mtodo de Entrada) +[Link] (Almacn en Lista) +[Link] (Recurso de Estilos) +[Link] (Opciones) +[Link] (Grupo de Tamao) +[Link] (Estilo) +[Link] (Buffer de texto) +[Link] (Anclaje Hijo de Texto) +[Link] (Marca en Texto) +[Link] (Etiqueta de Texto) +[Link] (Tabla de Etiquetas de Texto) +[Link] (Modelo en rbol Filtrado) +[Link] (Modelo en rbol Ordenado) +[Link] (Seleccin de rbol) +[Link] (Almacn en rbol) +[Link] (Gestor de Interfaces de Usuario) +[Link] (Grupo de Ventanas) +[Link] (Contexto de Arrastre) +[Link] (Pantalla) +[Link] (Buffer de pxeles) +[Link] (Dibujable) | +[Link] (Mapa de Bits) +[Link] (Imagen) +[Link] (Animacin) +[Link] (Dispositivo de Entrada)
[Link] | +[Link] (Disposicin de Celdas) +[Link] (Editable) +[Link] (Editor de Celda) +[Link] (Seleccin de Ficheros) +[Link] (Modelo en rbol) +[Link] (Fuente de Arrastre en rbol) +[Link] (Destino de Arrastre en rbol) +[Link] (rbol Ordenable)
Seguiremos nuestra exploracin de PyGTK examinando cada control, creando programas de ejemplo simples que los muestren.
6.1. Botones Normales 6.2. Botones Biestado (Toggle Buttons) 6.3. Botones de Activacin (Check Buttons) 6.4. Botones de Exclusin Mtua (Radio Buttons)
si se especifica una etiqueta sta se usa como texto del [Link] se especifica stock ste se usa para elegir un icono de serie y una etiqueta para el botn. Los elementos de serie son:
STOCK_DIALOG_INFO STOCK_DIALOG_WARNING STOCK_DIALOG_ERROR STOCK_DIALOG_QUESTION STOCK_DND STOCK_DND_MULTIPLE STOCK_ADD STOCK_APPLY STOCK_BOLD STOCK_CANCEL STOCK_CDROM STOCK_CLEAR STOCK_CLOSE STOCK_CONVERT STOCK_COPY STOCK_CUT STOCK_DELETE STOCK_EXECUTE STOCK_FIND STOCK_FIND_AND_REPLACE
STOCK_FLOPPY STOCK_GOTO_BOTTOM STOCK_GOTO_FIRST STOCK_GOTO_LAST STOCK_GOTO_TOP STOCK_GO_BACK STOCK_GO_DOWN STOCK_GO_FORWARD STOCK_GO_UP STOCK_HELP STOCK_HOME STOCK_INDEX STOCK_ITALIC STOCK_JUMP_TO STOCK_JUSTIFY_CENTER STOCK_JUSTIFY_FILL STOCK_JUSTIFY_LEFT STOCK_JUSTIFY_RIGHT STOCK_MISSING_IMAGE STOCK_NEW STOCK_NO STOCK_OK STOCK_OPEN STOCK_PASTE STOCK_PREFERENCES STOCK_PRINT STOCK_PRINT_PREVIEW STOCK_PROPERTIES STOCK_QUIT STOCK_REDO STOCK_REFRESH STOCK_REMOVE STOCK_REVERT_TO_SAVED STOCK_SAVE STOCK_SAVE_AS STOCK_SELECT_COLOR STOCK_SELECT_FONT STOCK_SORT_ASCENDING STOCK_SORT_DESCENDING STOCK_SPELL_CHECK STOCK_STOP STOCK_STRIKETHROUGH STOCK_UNDELETE STOCK_UNDERLINE STOCK_UNDO STOCK_YES STOCK_ZOOM_100 STOCK_ZOOM_FIT STOCK_ZOOM_IN STOCK_ZOOM_OUT
El programa de ejemplo [Link] proporciona un ejemplo del uso de [Link]() para crear un botn con una imagen y una etiqueta en l. Se ha
separado el cdigo para crear una caja del resto para que se pueda usar en ms programas. Hay ms ejemplos del uso de imgenes ms adelante en el tutorial. La figura Figura 6.1, Botn con Pixmap y Etiqueta muestra la ventana con un botn que incluye una imagen y una etiqueta: Figura 6.1. Botn con Pixmap y Etiqueta
35 print "Hello again - %s was pressed" % data 36 37 def __init__(self): 38 # Creamos una ventana nueva 39 [Link] = [Link](gtk.WINDOW_TOPLEVEL) 40 41 [Link].set_title("Image'd Buttons!") 42 43 # Es buena idea hacer esto para todas las ventanas 44 [Link]("destroy", lambda wid: gtk.main_quit()) 45 [Link]("delete_event", lambda a1,a2:gtk.main_quit()) 46 47 # Fijamos el ancho de borde de la ventana 48 [Link].set_border_width(10) 49 50 # Creamos un nuevo botn 51 button = [Link]() 52 53 # Conectamos la seal "clicked" a nuestra retrollamada 54 [Link]("clicked", [Link], "cool button") 55 56 # Esto llama a nuestra funcin de creacin de caja 57 box1 = xpm_label_box([Link], "[Link]", "cool button") 58 59 # Empaquetamos y mostramos todos los controles 60 [Link](box1) 61 62 [Link]() 63 [Link]() 64 65 [Link](button) 66 [Link]() 67 68 def main(): 69 [Link]() 70 return 0 71 72 if __name__ == "__main__": 73 Buttons() 74 main()
Las lneas 12-34 definen la funcin auxiliar xpm_label_box() que crea una caja horizontal con un borde de ancho 2 (lineas 14-15) y le pone una imagen (lineas 22-23) y una etiqueta (linea 26). Las lneas 36-70 definen la clase Buttons. Las lneas 41-70 definen el mtodo de inicializacin de instancia que crea una ventana (linea 43), le pone el ttulo (linea 45), le conecta las seales "delete_event" y "destroy" (lineas 48-49). La linea 55
crea el botn sin etiqueta. Su seal "clicked" se conecta al mtodo callback() en la linea 58. La funcin xpm_label_box() se llama en la linea 61 para crear la imagen y la etiqueta que se pondrn en el botn en la linea 64. La funcin xpm_label_box() podra usarse para empaquetar 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
Como se puede imaginar, estas llamadas funcionan igual que las llamadas al control de botn normal. Si no se especifica etiqueta el botn estar vacio. El
texto de la etiqueta se analiza para comprobar si contiene caracteres mnemotcnicos con el prefijo '_' Para obtener el estado de un botn biestado, incluyendo los botones de exclusin mtua y los botones de activacin, se utiliza el mecanismo del ejemplo anterior. As se comprueba 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, se configura un manejador de seales para capturar la seal toggled, y se accede a los atributos del objeto para determinar su estado. La retrollamada ser parecida a:
def toggle_button_callback(widget, data): if widget.get_active(): # Si estamos aqui, el botn biestado est pulsado else: # Si estamos aqui, el botn biestado est levantado
Para forzar el estado de un botn biestado, y de sus hijos, el botn de exclusin mtua y el botn de activacin, se 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. Especificando un argumento TRUE o FALSE para el parmetrois_active indicamos si el botn debera estar pulsado o levantado. Cuando el botn biestado se crea, su valor predeterminado es levantado o FALSE. Hay que fijarse en que, cuando se usa el mtodo set_active(), y cambia realmente el estado del botn, se produce la emisin de las seales "clicked" y "toggled" por ste.
toggle_button.get_active()
Este mtodo devuelve el estado actual del botn biestado como un valor booleano TRUE o FALSE. El programa [Link] proporciona un ejemplo simple del uso de botones biestado. La figura Figura 6.2, Ejemplo de Botn Biestado ilustra la ventana resultante con el segundo botn biestado activo:
37 38 39 40 41 42 43 44 45 1") 46 47 48 49 50 51 52 53 54 55 56 57 58 59 2") 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
# Inserta vbox en la ventana principal [Link](vbox) # Crea el primer botn button = [Link]("toggle button 1") # cuando se conmuta el botn llamamos el mtodo "callback" # con un puntero a "button" como argumento [Link]("toggled", [Link], "toggle button
# Insertar el botn 1 vbox.pack_start(button, [Link], [Link], 2) [Link]() # Crear el segundo botn button = [Link]("toggle button 2") # Cuando se conmuta el botn llamamos el mtodo "callback" # con un puntero a "button 2" como argumento [Link]("toggled", [Link], "toggle button # Insertamos el botn 2 vbox.pack_start(button, [Link], [Link], 2) [Link]() # Crear el botn "Quit" button = [Link]("Quit") # Cuando se pulsa el botn llamamos la funcin main_quit # y el programa finaliza [Link]("clicked", lambda wid: gtk.main_quit()) # Insertar el botn de salida vbox.pack_start(button, [Link], [Link], 2) [Link]() [Link]() [Link]() def main(): [Link]() return 0 if __name__ == "__main__": ToggleButton() main()
Las lineas interesantes son la 12-13, que definen el mtodo callback() que imprime la etiqueta del botn biestado y su estado cuando es activado. Las lineas 45 y 59 conectan la seal "toggled" de los botones biestado al mtodo callback().
Si el argumento label se especifica, el mtodo crea un botn de activacin con una etiqueta a su lado. El texto label de la etiqueta se analiza en busca de caracteres mnemotcnicos con prefijo '_' Ver y modificar el estado de un botn de activacin es igual que en un botn biestado. El programa [Link] proporciona un ejemplo del uso de los botones de activacin. La figura Figura 6.3, Ejemplo de Botn de Activacin ilustra la ventana resultante: Figura 6.3. Ejemplo de Botn de Activacin
2 3 # ejemplo [Link] 4 5 import pygtk 6 [Link]('2.0') 7 import gtk 8 9 class CheckButton: 10 # Nuestra retrollamada 11 # Los datos pasados a este mtodo se imprimen en la salida estndar 12 def callback(self, widget, data=None): 13 print "%s was toggled %s" % (data, ("OFF", "ON")[widget.get_active()]) 14 15 # Esta retrollamada termina el programa 16 def delete_event(self, widget, event, data=None): 17 gtk.main_quit() 18 return [Link] 19 20 def __init__(self): 21 # Crear una nueva ventana 22 [Link] = [Link](gtk.WINDOW_TOPLEVEL) 23 24 # Establecer el ttulo de la ventana 25 [Link].set_title("Check Button") 26 27 # Fijar un manejador para delete_event que 28 # salga inmediatamente de GTK. 29 [Link]("delete_event", self.delete_event) 30 31 # Fijamos el borde de la ventana 32 [Link].set_border_width(20) 33 34 # Creamos una caja vertical vbox 35 vbox = [Link]([Link], 2) 36 37 # Insertamos vbox en la ventana principal 38 [Link](vbox) 39 40 # Creamos el primer botn 41 button = [Link]("check button 1") 42 43 # Cuando se conmuta el botn llamamos el mtodo "callback" 44 # con un puntero a "button" como argumento 45 [Link]("toggled", [Link], "check button 1") 46 47 48 # Insertamos el botn 1 49 vbox.pack_start(button, [Link], [Link], 2) 50 51 [Link]() 52 53 # Creamos un segundo botn
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
button = [Link]("check button 2") # Cuando se conmuta el botn llamamos el mtodo "callback" # con un puntero a "button 2" como argumento [Link]("toggled", [Link], "check button 2") # Insertamos el botn 2 vbox.pack_start(button, [Link], [Link], 2) [Link]() # Creamos el botn "Quit" button = [Link]("Quit") # Cuando se pulsa el botn llamamos la funcin mainquit # y el programa termina [Link]("clicked", lambda wid: gtk.main_quit()) # Insertamos el botn de salida vbox.pack_start(button, [Link], [Link], 2) [Link]() [Link]() [Link]() def main(): [Link]() return 0 if __name__ == "__main__": CheckButton() main()
Es necesario fijarse en el argumento adicional de esta llamada. Los botones de exclusin mtua requieren un grupo group para funcionar [Link] primera llamada a [Link]() 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 se pasa una referencia a un botn de exclusin mtua en group en las llamadas posteriores a [Link](). Si se especifica un argumento label dicho texto se analizar para comprobar la presencia de caracteres mnemotcnicos con prefijo '_'. Tambin es buena idea especificar explcitamente qu 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 manera. Una vez que los botones de exclusin mtua se agrupan, slo uno de los pertenecientes al 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 inactivo), y luego el segundo botn emitir su seal "toggled" (para informar de que va a estar activo). El programa de ejemplo [Link] crea un grupo de botones de exclusin mtua con tres botones. La figura Figura 6.4, Ejemplo de Botones de Exclusin Mtua ilustra la ventana resultante: Figura 6.4. Ejemplo de Botones de Exclusin Mtua
50 separator = [Link]() 51 box1.pack_start(separator, [Link], [Link], 0) 52 [Link]() 53 54 box2 = [Link]([Link], 10) 55 box2.set_border_width(10) 56 box1.pack_start(box2, [Link], [Link], 0) 57 [Link]() 58 59 button = [Link]("close") 60 button.connect_object("clicked", self.close_application, [Link], 61 None) 62 box2.pack_start(button, [Link], [Link], 0) 63 button.set_flags(gtk.CAN_DEFAULT) 64 button.grab_default() 65 [Link]() 66 [Link]() 67 68 def main(): 69 [Link]() 70 return 0 71 72 if __name__ == "__main__": 73 RadioButtons() 74 main()
El cdigo es bastante simple de seguir. Las lineas 63-64 hacen que el botn "close" sea el control por defecto, de manera que, al pulsar la tecla "Enter" cuando la ventana est activa, el botn "close" emitir la seal "clicked".
Captulo 7. Ajustes
Tabla de contenidos 7.1. Creacin de un Ajuste 7.2. Utilizacin de Ajustes de la Forma Fcil 7.3. Interioridades de un Ajuste 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 vista.
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 pasar el nuevo valor al manejador de seal, o requerir que se mire dentro de la estructura de datos del control para ver el nuevo valor. Pero puede que tambin se quiera 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 una vista o a un rea de texto desplazable. Si cada control tuviera su propia manera de manipular el valor del ajuste, entonces el programador 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 soluciona este problema mediante 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 flexible. El uso ms obvio de Adjustment es almacenar los parmetros de configuracin y los valores de los controles de rango, tales como las barras de desplazamiento y los controles de escala. Sin embargo, como la clase Adjustments deriva de Object, 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. Se ver como encajan los ajustes en todo el sistema cuando se vean los controles que los incorporan: Barras de Progreso, Vistas, Ventanas de Desplazamiento, y otros.
El argumento value es el valor inicial que se quiere dar al ajuste, y normalmente corresponde a la posicin superior o la posicin ms a la izquierda de un control
ajustable. El argumento lower especifica el valor ms bajo que puede tomar el ajuste adjustment. El argumento step_incr especifica 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 de un control incluido en otro 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.
# crea sus propios ajustes viewport = [Link]() # usa los ajustes recin creados para la barra de desplazamiento tambin vscrollbar = [Link](viewport.get_vadjustment())
Dada una instancia adj de la clase [Link], cada uno de los atributos se obtienen o modifican usando [Link], [Link], etc. Ya que, cuando se determina el valor de un ajuste, generalmente tambin se quiere que el cambio afecte a todos los controles que usan este ajuste, PyGTK proporciona un mtodo para hacer esto mismo:
adjustment.set_value(value)
Como se mencion anteriormente, Adjustment es una subclase de Object, al 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 se comparte 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 cualquier programa. Esta es la definicin de la retrollamada de esta seal:
def value_changed(adjustment):
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 se tiene un control de escala, y se quiere que cambie la rotacin de una imagen siempre que su valor cambie, se podra crear una retrollamada como esta:
def cb_rotate_picture(adj, picture): set_picture_rotation (picture, [Link]) ...
Y qu pasa cuando un control reconfigura los campos upper (superior) o lower (inferior) de su ajuste, tal y como sucede 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 reflejar el cambio - por ejemplo, el tamao del deslizador de una barra de desplazamiento aumentar o se reducir en proporcin inversa a la diferencia entre el valor superior e inferior de su ajuste. Probablemente nunca ser necesario que se haga la conexin de un manejador a esta seal, salvo que se est escribiendo un nuevo tipo de control de rango. En cualquier caso, si se cambia directamente alguno de los valores de un Adjustment, se debe emitir esta seal para reconfigurar los controles que lo usan. Tal que as:
[Link]("changed")
8.2.2. Mtodos y Seales (bueno, al menos mtodos) 8.3. Mtodos Comunes de los Rangos 8.3.1. Establecimiento de la Poltica de Actualizacin 8.3.2. Obtencin y Cambio de Ajustes 8.4. Atajos de Teclas y Ratn 8.5. Ejemplo de Control de Rango La categora de los controles de rango incluye el ubcuo 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 grficos, cada uno de los cuales tiene su propia ventana X y recibe eventos. Todos ellos contienen una gua o canal y un deslizador. Arrastrar el deslizador con el puntero del ratn hace que se mueva hacia adelante y hacia atrs en el 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.
vscrollbar = [Link](adjustment=None)
y eso es todo. El argumento adjustment puede ser, o bien una referencia a un Adjustment existente, o bien nada, en cuyo caso se crear uno. Especificar nada puede ser til en el caso en el que se quiera pasar el ajuste recin creado al constructor de otro control que lo configurar por uno, tal como podra ocurrir con una caja de texto.
El argumento adjustment puede ser bien un ajuste que ya haya sido creado con [Link](), o bien nada, en cuyo caso se crea un Adjustment annimo con todos sus valores puestos a 0.0 (lo cual no es demasiado til). Para evitar confusiones, probablemente sea mejor crear un ajuste con un valor page_size de 0.0 para que su valor upper realmente corresponda con el valor ms alto que el usuario puede seleccionar. (Si esto resulta confuso, la seccin sobre Ajustes da una explicacin detallada sobre qu hacen exactamente los ajustes y cmo 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 esto se puede cambiar con el mtodo:
scale.set_draw_value(draw_value)
Como habrs imaginado, draw_value (representar valor) 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). Se puede cambiar esto con:
scale.set_digits(digits)
donde digits (dgitos) es el nmero de posiciones decimales que se representarn. Se puede poner el nmero que se desee, pero no se representarn en pantalla ms de 13 dgitos decimales. Finalmente, el valor se puede mostrar en diferentes posiciones relativas al canal:
scale.set_value_pos(pos)
Si pones el valor en un "lado" del canal (por ejemplo, en la parte de arriba o de abajo de un control de escala horizontal), entonces seguir al deslizador en su desplazamiento hacia arriba y hacia abajo del canal.
8.3.1. Establecimiento de la Poltica de Actualizacin La "poltica de actualizacin" de un control de rango define 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 esteAdjustment. Las polticas de actualizacin son:
Es es el valor predeterminado. La seal "value_changed" se emite contnuamente, por ejemplo, cada vez que el UPDATE_CONTINUOUS deslizador se mueve, incluso en las cantidades mas minsculas. La seal "value_changed" slo se mite una vez que el UPDATE_DISCONTINUOUS deslizador ha parado de moverse y el usuario ha soltado el botn del ratn. La seal "value_changed" se emite cuando el usuario suelta UPDATE_DELAYED el botn del ratn, o si el deslizador deja de moverse durante un corto perodo de tiempo.
8.3.2. Obtencin y Cambio de Ajustes La obtencin y cambio del ajuste de un control de rango se puede hacer sobre la marcha, como era predecible, 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 se le pasa el adjustment que el range ya est utilizando, independientemente de que se le hayan cambiado alguno de sus campos o no. Si se le pasa 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 mencion en la
seccin de ajustes, si se desea reutilizar el mismo Adjustment, cuando se modifiquen sus valores directamente se debe emitir la seal "changed" desde l, como por ejemplo:
[Link]("changed")
23 class RangeWidgets: 24 def cb_pos_menu_select(self, item, pos): 25 # Fijar la posicin del valor para ambos ajustes 26 [Link].set_value_pos(pos) 27 [Link].set_value_pos(pos) 28 29 def cb_update_menu_select(self, item, policy): 30 # Establecer la poltica de actualizacin para ambos controles 31 [Link].set_update_policy(policy) 32 [Link].set_update_policy(policy) 33 34 def cb_digits_scale(self, adj): 35 # Fijar el nmero de posiciones decimales a las que se ajusta el valor 36 [Link].set_digits([Link]) 37 [Link].set_digits([Link]) 38 39 def cb_page_size(self, get, set): 40 # Fijar el valor del tamao de pgina y de su incremento 41 # para el ajuste al valor especificado por la escala "Page Size" 42 set.page_size = [Link] 43 set.page_incr = [Link] 44 # Ahora emitir la seal "changed" para reconfigurar todos los controles 45 # que estn ligados a este ajuste 46 [Link]("changed") 47 48 def cb_draw_value(self, button): 49 # Activar o desactivar la representacin del valor en funcin del 50 # estado del botn de activacin 51 [Link].set_draw_value(button.get_active()) 52 [Link].set_draw_value(button.get_active()) 53 54 # crea la ventana de ejemplo 55 56 def __init__(self): 57 # Creacin de la ventana principal 58 [Link] = [Link] (gtk.WINDOW_TOPLEVEL) 59 [Link]("destroy", lambda w: gtk.main_quit()) 60 [Link].set_title("range controls") 61 62 box1 = [Link]([Link], 0) 63 [Link](box1) 64 [Link]() 65 66 box2 = [Link]([Link], 10) 67 box2.set_border_width(10) 68 box1.pack_start(box2, [Link], [Link], 0) 69 [Link]() 70 71 # value, lower, upper, step_increment, page_increment,
page_size 72 # Obsrvese que el valor page_size solamente es significativo 73 # para controles de barra de desplazamiento y que el valor ms alto posible es 74 # (upper - page_size). 75 adj1 = [Link](0.0, 0.0, 101.0, 0.1, 1.0, 1.0) 76 77 [Link] = [Link](adj1) 78 scale_set_default_values([Link]) 79 box2.pack_start([Link], [Link], [Link], 0) 80 [Link]() 81 82 box3 = [Link]([Link], 10) 83 box2.pack_start(box3, [Link], [Link], 0) 84 [Link]() 85 86 # Reutilizamos el mismo ajuste 87 [Link] = [Link](adj1) 88 [Link].set_size_request(200, 30) 89 scale_set_default_values([Link]) 90 box3.pack_start([Link], [Link], [Link], 0) 91 [Link]() 92 93 # Reutilizamos el mismo ajuste otra vez 94 scrollbar = [Link](adj1) 95 # Obsrvese como esto hace que las escalas se actualicen 96 # continuamente cuando se mueve la barra de desplazamiento 97 scrollbar.set_update_policy(gtk.UPDATE_CONTINUOUS) 98 box3.pack_start(scrollbar, [Link], [Link], 0) 99 [Link]() 100 101 box2 = [Link]([Link], 10) 102 box2.set_border_width(10) 103 box1.pack_start(box2, [Link], [Link], 0) 104 [Link]() 105 106 # Un botn de activacin para definir se se muestra el valor o no 107 button = [Link]("Display value on scale widgets") 108 button.set_active([Link]) 109 [Link]("toggled", self.cb_draw_value) 110 box2.pack_start(button, [Link], [Link], 0) 111 [Link]() 112 113 box2 = [Link]([Link], 10) 114 box2.set_border_width(10) 115 116 # Un men de opciones para cambiar la posicin del valor 117 label = [Link]("Scale Value Position:") 118 box2.pack_start(label, [Link], [Link], 0) 119 [Link]() 120 121 opt = [Link]()
122 menu = [Link]() 123 124 item = make_menu_item ("Top", self.cb_pos_menu_select, gtk.POS_TOP) 125 [Link](item) 126 127 item = make_menu_item ("Bottom", self.cb_pos_menu_select, 128 gtk.POS_BOTTOM) 129 [Link](item) 130 131 item = make_menu_item ("Left", self.cb_pos_menu_select, gtk.POS_LEFT) 132 [Link](item) 133 134 item = make_menu_item ("Right", self.cb_pos_menu_select, gtk.POS_RIGHT) 135 [Link](item) 136 137 opt.set_menu(menu) 138 box2.pack_start(opt, [Link], [Link], 0) 139 [Link]() 140 141 box1.pack_start(box2, [Link], [Link], 0) 142 [Link]() 143 144 box2 = [Link]([Link], 10) 145 box2.set_border_width(10) 146 147 # Otro men de opciones ms, esta vez para la poltica de actualizacin 148 # de los controles de escala 149 label = [Link]("Scale Update Policy:") 150 box2.pack_start(label, [Link], [Link], 0) 151 [Link]() 152 153 opt = [Link]() 154 menu = [Link]() 155 156 item = make_menu_item("Continuous", self.cb_update_menu_select, 157 gtk.UPDATE_CONTINUOUS) 158 [Link](item) 159 160 item = make_menu_item ("Discontinuous", self.cb_update_menu_select, 161 gtk.UPDATE_DISCONTINUOUS) 162 [Link](item) 163 164 item = make_menu_item ("Delayed", self.cb_update_menu_select, 165 gtk.UPDATE_DELAYED) 166 [Link](item) 167 168 opt.set_menu(menu)
169 170 171 172 173 174 175 176 177 178 las escalas 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 pgina 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
box2.pack_start(opt, [Link], [Link], 0) [Link]() box1.pack_start(box2, [Link], [Link], 0) [Link]() box2 = [Link]([Link], 10) box2.set_border_width(10) # Un control HScale para ajustar el nmero de dgitos en # de ejemplo label = [Link]("Scale Digits:") box2.pack_start(label, [Link], [Link], 0) [Link]() adj2 = [Link](1.0, 0.0, 5.0, 1.0, 1.0, 0.0) [Link]("value_changed", self.cb_digits_scale) scale = [Link](adj2) scale.set_digits(0) box2.pack_start(scale, [Link], [Link], 0) [Link]() box1.pack_start(box2, [Link], [Link], 0) [Link]() box2 = [Link]([Link], 10) box2.set_border_width(10) # Y un ltimo control HScale para ajustar el tamao de # de la barra de desplazamiento. label = [Link]("Scrollbar Page Size:") box2.pack_start(label, [Link], [Link], 0) [Link]() adj2 = [Link](1.0, 1.0, 101.0, 1.0, 1.0, 0.0) [Link]("value_changed", self.cb_page_size, adj1) scale = [Link](adj2) scale.set_digits(0) box2.pack_start(scale, [Link], [Link], 0) [Link]() box1.pack_start(box2, [Link], [Link], 0) [Link]() separator = [Link]() box1.pack_start(separator, [Link], [Link], 0) [Link]() box2 = [Link]([Link], 10) box2.set_border_width(10) box1.pack_start(box2, [Link], [Link], 0) [Link]()
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
button = [Link]("Quit") [Link]("clicked", lambda w: gtk.main_quit()) box2.pack_start(button, [Link], [Link], 0) button.set_flags(gtk.CAN_DEFAULT) button.grab_default() [Link]() [Link]() def main(): [Link]() return 0 if __name__ == "__main__": RangeWidgets() main()
Se debe advertir que el programa no llama al mtodo connect() para el evento "delete_event", sino solamente a la seal "destroy". Esto seguir realizando la accin deseada, puesto que un evento "delete_event" sin tratar resultar en una seal "destroy" enviada a la ventana.
9.11. Lista Desplegable (Combo) 9.12. Calendario 9.13. Seleccin de Color 9.14. Selectores de Fichero 9.15. Dilogo de Seleccin de Fuentes
9.1. Etiquetas
Las etiquetas son objetos de la clase Label y se usan mucho en GTK, siendo adems relativamente simples. Los objetos Label no emiten seales ya que no tienen una ventana X asociada. Si se necesita capturar seales, o hacer recorte, se deben colocar dentro de un control EventBox (Caja de Eventos) o de un control Button (Botn). Para crear una nueva etiqueta se usa:
label = [Link](str)
El nico argumento es la cadena de texto que se quiere que visualice la etiqueta. Para cambiar el texto de la etiqueta despus de la creacin se usa el mtodo:
label.set_text(str)
es la etiqueta que se cre previamente, y str es la nueva cadena. El espacio que necesite la nueva cadena se ajustar automticamente si es necesario. Se pueden hacer etiquetas multilinea poniendo saltos de linea en la cadena de la etiqueta.
label
es la etiqueta que se ha creado, y str es la cadena que devuelve. El texto de una etiqueta en label se puede justificar usando:
label label.set_justify(jtype)
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 puede tomar un valor TRUE o FALSE. Si se quiere subrayado en la etiqueta, entonces se puede establecer un patrn para la etiqueta:
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 cuarto y quinto. Si slo se quiere un atajo subrayado ("mnemnico") en la etiqueta, se debera usar set_text_with_mnemonic (str), no set_pattern(). El programa de ejemplo [Link] es un ejemplo corto para ilustrar estos mtodos. Este ejemplo hace uso del control Frame (Marco) para demostrar mejor los estilos de etiqueta. Se puede 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 figura Figura 9.1, Ejemplos de Etiquetas ilustra el resultado de ejecutar el programa de ejemplo: Figura 9.1. Ejemplos de Etiquetas
27 label = [Link]("This is a Multi-line label.\nSecond line\n" 28 "Third line") 29 [Link](label) 30 vbox.pack_start(frame, [Link], [Link], 0) 31 32 frame = [Link]("Left Justified Label") 33 label = [Link]("This is a Left-Justified\n" 34 "Multi-line label.\nThird line") 35 label.set_justify(gtk.JUSTIFY_LEFT) 36 [Link](label) 37 vbox.pack_start(frame, [Link], [Link], 0) 38 39 frame = [Link]("Right Justified Label") 40 label = [Link]("This is a Right-Justified\nMulti-line label.\n" 41 "Fourth line, (j/k)") 42 label.set_justify(gtk.JUSTIFY_RIGHT) 43 [Link](label) 44 vbox.pack_start(frame, [Link], [Link], 0) 45 46 vbox = [Link]([Link], 5) 47 hbox.pack_start(vbox, [Link], [Link], 0) 48 frame = [Link]("Line wrapped label") 49 label = [Link]("This is an example of a line-wrapped label. It " 50 "should not be taking up the entire " 51 "width allocated to it, but automatically " 52 "wraps the words to fit. " 53 "The time has come, for all good men, to come to " 54 "the aid of their party. " 55 "The sixth sheik's six sheep's sick.\n" 56 " It supports multiple paragraphs correctly, " 57 "and correctly adds " 58 "many extra spaces. ") 59 label.set_line_wrap([Link]) 60 [Link](label) 61 vbox.pack_start(frame, [Link], [Link], 0) 62 63 frame = [Link]("Filled, wrapped label") 64 label = [Link]("This is an example of a line-wrapped, filled label. " 65 "It should be taking " 66 "up the entire width allocated to it. " 67 "Here is a sentence to prove " 68 "my point. Here is another sentence. " 69 "Here comes the sun, do de do de
do.\n" 70 " This is a new paragraph.\n" 71 " This is another newer, longer, better " 72 "paragraph. It is coming to an end, " 73 "unfortunately.") 74 label.set_justify(gtk.JUSTIFY_FILL) 75 label.set_line_wrap([Link]) 76 [Link](label) 77 vbox.pack_start(frame, [Link], [Link], 0) 78 79 frame = [Link]("Underlined label") 80 label = [Link]("This label is underlined!\n" 81 "This one is underlined in quite a funky fashion") 82 label.set_justify(gtk.JUSTIFY_LEFT) 83 label.set_pattern( 84 "_________________________ _ _________ _ ______ __ _______ ___") 85 [Link](label) 86 vbox.pack_start(frame, [Link], [Link], 0) 87 [Link].show_all () 88 89 def main(): 90 [Link]() 91 return 0 92 93 if __name__ == "__main__": 94 Labels() 95 main()
Obsrvese que la etiqueta "Filled, wrapped label" no tiene justificacin completa (fill justified).
La primera crea un control flecha con el tipo y apariencia indicados. La segunda permite cambiar cualquiera de estos valores. El argumento arrow_type puede tomar uno de lo siguientes valores:
ARROW_UP ARROW_DOWN ARROW_LEFT ARROW_RIGHT #(Arriba) #(Abajo) #(Izquierda) #(Derecha)
Estos valores obviamente indican la direccin hacia la que apunta la flecha. El argumento <keyword>shadow_type</keyword> puede tomar uno de los siguientes valores:
SHADOW_IN SHADOW_OUT # valor predeterminado SHADOW_ETCHED_IN SHADOW_ETCHED_OUT
El programa de ejemplo [Link] ilustra brevemente su uso. La figura Figura 9.2, Ejemplos de Botones con Flechas muestra el resultado de ejecutar el programa: Figura 9.2. Ejemplos de Botones con Flechas
16 [Link]() 17 return button 18 19 class Arrows: 20 def __init__(self): 21 # Creamos una ventana nueva 22 window = [Link](gtk.WINDOW_TOPLEVEL) 23 24 window.set_title("Arrow Buttons") 25 26 # Es buena idea hacer esto con todas las ventanas 27 [Link]("destroy", lambda x: gtk.main_quit()) 28 29 # Establecer el ancho del borde de ventana 30 window.set_border_width(10) 31 32 # Creamos una caja para poner las flechas/botones 33 box = [Link]([Link], 0) 34 box.set_border_width(2) 35 [Link](box) 36 37 # Empaquetar y mostrar todos los controles 38 [Link]() 39 40 button = create_arrow_button(gtk.ARROW_UP, gtk.SHADOW_IN) 41 box.pack_start(button, [Link], [Link], 3) 42 43 button = create_arrow_button(gtk.ARROW_DOWN, gtk.SHADOW_OUT) 44 box.pack_start(button, [Link], [Link], 3) 45 46 button = create_arrow_button(gtk.ARROW_LEFT, gtk.SHADOW_ETCHED_IN) 47 box.pack_start(button, [Link], [Link], 3) 48 49 button = create_arrow_button(gtk.ARROW_RIGHT, gtk.SHADOW_ETCHED_OUT) 50 box.pack_start(button, [Link], [Link], 3) 51 52 [Link]() 53 54 def main(): 55 [Link]() 56 return 0 57 58 if __name__ == "__main__": 59 Arrows() 60 main()
Las Tooltips (Pistas) son pequeas cadenas de texto que aparecen cuando se deja 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 se usar crea una nueva pista. Slo es necesario hacer esto una vez ya que el objeto que devuelve [Link] puede usarse para crear mltiples pistas.
tooltips = [Link]()
Una vez que se ha creado una nueva pista, y el control que se quiere que la use est preparado, simplemente se utiliza esta llamada para asociarlos:
tooltips.set_tip(widget, tip_text, tip_private=None)
El objeto tooltips es la pista que se acaba de crear. El primer argumento (widget) es el control que se quiere que muestre la pista; el segundo argumento (tip_text), el texto que se quiere visualizar. El ltimo argumento (tip_private) es una cadena de texto que puede usarse como identificador. El programa de ejemplo [Link] modifica el programa [Link] para aadir una pista a cada botn. La figura Figura 9.3, Ejemplo de Pistas ilustra la ventana resultante con la pista del segundo botn flecha activada: Figura 9.3. Ejemplo de Pistas
7 import gtk 8 9 # Crear una Flecha con los parmetros especificados 10 # y empaquetarlo en un botn 11 def create_arrow_button(arrow_type, shadow_type): 12 button = [Link]() 13 arrow = [Link](arrow_type, shadow_type) 14 [Link](arrow) 15 [Link]() 16 [Link]() 17 return button 18 19 class Tooltips: 20 def __init__(self): 21 # Creamos una ventana nueva 22 window = [Link](gtk.WINDOW_TOPLEVEL) 23 24 window.set_title("Tooltips") 25 26 # It's a good idea to do this for all windows. 27 [Link]("destroy", lambda w: gtk.main_quit()) 28 29 # Establece el grosor del borde de la ventana 30 window.set_border_width(10) 31 32 # Creamos una caja para poner las flechas/botones 33 box = [Link]([Link], 0) 34 box.set_border_width(2) 35 [Link](box) 36 37 # creamos un objeto de pista 38 [Link] = [Link]() 39 40 # Empaquetamos y mostramos todos los controles 41 [Link]() 42 43 button = create_arrow_button(gtk.ARROW_UP, gtk.SHADOW_IN) 44 box.pack_start(button, [Link], [Link], 3) 45 [Link].set_tip(button, "SHADOW_IN") 46 47 button = create_arrow_button(gtk.ARROW_DOWN, gtk.SHADOW_OUT) 48 box.pack_start(button, [Link], [Link], 3) 49 [Link].set_tip(button, "SHADOW_OUT") 50 51 button = create_arrow_button(gtk.ARROW_LEFT, gtk.SHADOW_ETCHED_IN) 52 box.pack_start(button, [Link], [Link], 3) 53 [Link].set_tip(button, "SHADOW_ETCHED_IN") 54 55 button = create_arrow_button(gtk.ARROW_RIGHT, gtk.SHADOW_ETCHED_OUT) 56 box.pack_start(button, [Link], [Link], 3) 57 [Link].set_tip(button, "SHADOW_ETCHED_OUT")
58 59 60 61 62 63 64 65 66 67
Hay otros mtodos que se pueden usar con las pistas. Simplemente los listaremos, junto con una breve descripcin sobre su funcin.
[Link]()
Fija los milisegundos que deben transcurrir con el puntero sobre el control antes de que la pista aparezca. El valor predefinido es de 500 milisegundos (medio segundo). Y esos son todos los mtodos asociados con las pistas. Ms de lo que siempre se querra saber :-)
El argumento adjustment (ajuste) especifica un ajuste para usarlo con la barra de progreso progressbar. Si no se especifica se crear un ajuste. Ahora que la barra de progreso est creada ya 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 significa 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 mtodo:
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 PROGRESS_RIGHT_TO_LEFT PROGRESS_BOTTOM_TO_TOP PROGRESS_TOP_TO_BOTTOM # # # # izquierda a derecha derecha a izquierda abajo a arriba arriba a abajo
Adems de indicar la cantidad de progreso que se ha completado, la barra de progreso tambin puede usarse simplemente 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.
[Link]()
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 Tngase 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.
Se puede desactivar la visualizacin de la cadena llamando a set_text() de nuevo sin argumentos. La cadena de texto actual de la barra de progreso se puede obtener con el siguiente 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 [Link] proporciona un ejemplo de barra de progreso, actualizada usando cronmetros. Este cdigo tambin muestra como reiniciar la Barra de Progreso. La figura Figura 9.4, Ejemplo de Barra de Progreso muestra la ventana resultante: Figura 9.4. Ejemplo de Barra de Progreso
10 # que tengamos algo de movimiento 11 def progress_timeout(pbobj): 12 if pbobj.activity_check.get_active(): 13 [Link]() 14 else: 15 # Calcular el valor de la barra de progreso usando el 16 # valor del rango establecido en el objeto ajuste 17 new_val = [Link].get_fraction() + 0.01 18 if new_val > 1.0: 19 new_val = 0.0 20 # Fijar el nuevo valor 21 [Link].set_fraction(new_val) 22 23 # Puesto que esta es una funcin de cronmetro, devolver TRUE de manera 24 # que contine siendo llamada 25 return [Link] 26 27 class ProgressBar: 28 # Retrollamada que conmuta el dibujado del texto en el 29 # canal de la barra de progreso 30 def toggle_show_text(self, widget, data=None): 31 if widget.get_active(): 32 [Link].set_text("some text") 33 else: 34 [Link].set_text("") 35 36 # Retrollamada que conmuta el modo de actividad de 37 # la barra de progreso 38 def toggle_activity_mode(self, widget, data=None): 39 if widget.get_active(): 40 [Link]() 41 else: 42 [Link].set_fraction(0.0) 43 44 # Retrollamada que conmuta la orientacin de la barra de progreso 45 def toggle_orientation(self, widget, data=None): 46 if [Link].get_orientation() == gtk.PROGRESS_LEFT_TO_RIGHT: 47 [Link].set_orientation(gtk.PROGRESS_RIGHT_TO_LEFT) 48 elif [Link].get_orientation() == gtk.PROGRESS_RIGHT_TO_LEFT: 49 [Link].set_orientation(gtk.PROGRESS_LEFT_TO_RIGHT) 50 51 # Limpiamos la memoria reservada y eliminamos el temporizador 52 def destroy_progress(self, widget, data=None): 53 gtk.timeout_remove([Link]) 54 [Link] = 0 55 gtk.main_quit() 56 57 def __init__(self): 58 [Link] = [Link](gtk.WINDOW_TOPLEVEL) 59 [Link].set_resizable([Link])
60 61 [Link]("destroy", self.destroy_progress) 62 [Link].set_title("ProgressBar") 63 [Link].set_border_width(0) 64 65 vbox = [Link]([Link], 5) 66 vbox.set_border_width(10) 67 [Link](vbox) 68 [Link]() 69 70 # Creamos un objeto de alineacin centrador 71 align = [Link](0.5, 0.5, 0, 0) 72 vbox.pack_start(align, [Link], [Link], 5) 73 [Link]() 74 75 # Creamos la barra de progreso 76 [Link] = [Link]() 77 78 [Link]([Link]) 79 [Link]() 80 81 # Aadimos una retrollamada temporizada para actualizar el valor de la barra 82 [Link] = gtk.timeout_add (100, progress_timeout, self) 83 84 separator = [Link]() 85 vbox.pack_start(separator, [Link], [Link], 0) 86 [Link]() 87 88 # filas, columnas, homogneas 89 table = [Link](2, 2, [Link]) 90 vbox.pack_start(table, [Link], [Link], 0) 91 [Link]() 92 93 # Aadir un botn de activacin para mostrar o no el texto del canal 94 check = [Link]("Show text") 95 [Link](check, 0, 1, 0, 1, 96 [Link] | [Link], [Link] | [Link], 97 5, 5) 98 [Link]("clicked", self.toggle_show_text) 99 [Link]() 100 101 # Aadir un botn de activacin para conmutar el modo de actividad 102 self.activity_check = check = [Link]("Activity mode") 103 [Link](check, 0, 1, 1, 2, 104 [Link] | [Link], [Link] | [Link], 105 5, 5) 106 [Link]("clicked", self.toggle_activity_mode) 107 [Link]() 108 109 # Aadir un botn de activacin para conmutar de
orientacin 110 check = [Link]("Right to Left") 111 [Link](check, 0, 1, 2, 3, 112 [Link] | [Link], [Link] | [Link], 113 5, 5) 114 [Link]("clicked", self.toggle_orientation) 115 [Link]() 116 117 # Aadir un botn para salir del programa 118 button = [Link]("close") 119 [Link]("clicked", self.destroy_progress) 120 vbox.pack_start(button, [Link], [Link], 0) 121 122 # Esto lo hace el botn por defecto 123 button.set_flags(gtk.CAN_DEFAULT) 124 125 # Esto hace que el botn tome el foco por defecto. Pulsando simplemente 126 # la tecla "Enter" se producir la activacin de este botn. 127 button.grab_default () 128 [Link]() 129 130 [Link]() 131 132 def main(): 133 [Link]() 134 return 0 135 136 if __name__ == "__main__": 137 ProgressBar() 138 main()
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 = [Link](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 establece varios modos de operacin para el dilogo:
DIALOG_MODAL - hace el dilogo modal DIALOG_DESTROY_WITH_PARENT - destruye el dilogo cuando su padre 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 especificarse usando palabras clave. Esto crear la caja de dilogo, y ahora depende del desarrollador el usarla. Se podra empaquetar un botn en el rea de accin:
button = ... dialog.action_area.pack_start(button, TRUE, TRUE, 0) [Link]()
Y se podra aadir, por ejemplo, una etiqueta, al rea vbox usando el empaquetamiento, con algo as:
label = [Link]("Los dilogos molan") [Link].pack_start(label, TRUE, TRUE, 0) [Link]()
Como ejemplo del uso de una caja de dilogo, se podran poner dos botones en el rea de accin, un botn de Cancelar, un botn de Aceptar y una etiqueta en el rea vbox, haciendo una pregunta al usuario, informando de un error, etc. Luego se podran 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 dan el suficiente control para la aplicacin, entonces se puede sencillamente empaquetar otro control dentro de las cajas proporcionadas. Por ejemplo, se podra empaquetar una tabla en 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.), e incluso ficheros de animacin. Las Images (Imgenes) se crean usando la funcin:
image = [Link]()
Donde pixbuf es un GdkPixbuf; pixmap y mask son [Link]; image es una [Link]; stock_id es el nombre de un [Link]; icon_set es un [Link]; y, animationes una [Link]. 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 [Link] muestra cmo cargar varios tipos de imagen ([Link], [Link], [Link], [Link], [Link]) en imgenes que se colocan dentro de botones: Figura 9.5. Ejemplo de Imgenes en Botones
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
[Link](image) [Link]() hbox.pack_start(button) [Link]("clicked", self.button_clicked, "1") # crear varias imgenes con datos de archivos y cargarlos # en botones image = [Link]() image.set_from_file("[Link]") [Link]() # un botn que cotenga el control de imagen button = [Link]() [Link](image) [Link]() hbox.pack_start(button) [Link]("clicked", self.button_clicked, "2") image = [Link]() image.set_from_file("[Link]") [Link]() # un botn que cotenga el control de imagen button = [Link]() [Link](image) [Link]() hbox.pack_start(button) [Link]("clicked", self.button_clicked, "3") image = [Link]() image.set_from_file("[Link]") [Link]() # un botn que cotenga el control de imagen button = [Link]() [Link](image) [Link]() hbox.pack_start(button) [Link]("clicked", self.button_clicked, "4") image = [Link]() image.set_from_file("[Link]") [Link]() # un botn que cotenga el control de imagen button = [Link]() [Link](image) [Link]() hbox.pack_start(button) [Link]("clicked", self.button_clicked, "5") def main(): [Link]() return 0 if __name__ == "__main__": ImagesExample()
92
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 grficos 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 significa que, una vez que los valores de un pixmap se establecen, no hay que seguir transmitiendolos por la red; en lugar de eso, se enva un comando para "mostrar el pixmap nmero XYZ aqui." Incluso si no se est usando X con GTK simultneamente, usando construcciones como Pixmaps har que los programas funcionen de forma aceptable en X. Para usar pixmaps en PyGTK, primero debemos construir un [Link] usando las funciones de [Link] en PyGTK. Los Pixmaps se pueden crear a partir de datos en memoria, o a partir de datos ledos desde un fichero. Veamos cada una de las llamadas usadas para crear un pixmap.
pixmap = [Link].pixmap_create_from_data(window, data, width, height, depth, fg, bg)
Esta rutina se usa para crear un pixmap con la profundidad de color dada por el argumento depth a partir de los datos data en memoria. Si depth es -1 su valor se deduce de la de la ventana window. Cada pixel usa un 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 [Link] 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. Se pueden crear pixmaps desde ficheros XPM usando:
pixmap, mask = [Link].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 ampliamente y hay muchas utilidades disponibles para crear ficheros de imgenes en este formato. En la funcin pixmap_create_from_xpm() el primer argumento es del tipo [Link] . (La mayora de los controles GTK tienen una [Link] subyacente que se puede obtener usando el atributo window (ventana) del control.) El fichero se especifica con filename y debe contener una imagen en formato XPM el cual se carga en la estructura del pixmap. La mask (mscara) es un bitmap que especifica qu bits del pixmap son opacos; se crea con la funcin. Todos los dems pixeles se colorean con el color especificado por transparent_color. Un ejemplo del uso de esta funcin se recoge a continuacin. Los Pixmaps tambin puede crearse a partir de datos en memoria usando la funcin:
pixmap, mask = [Link].pixmap_create_from_xpm_d(window, transparent_color, data)
Imagenes pequeas se pueden incorporar a un programa como datos en el formato XPM usando la funcin anterior. Un pixmap se crea usando estos datos, en lugar de leerlo de un fichero. Un ejemplo de este tipo de datos es:
xpm_data = [ "16 16 3 1", " c None", ". c #000000000000", "X c #FFFFFFFFFFFF", " ", " ...... ", " .XXX.X. ", " .[Link]. ", " .[Link]. ", " .XXX..... ", " .XXXXXXX. ", " .XXXXXXX. ",
La ltima forma para crear un pixmap en blanco disponible para operaciones de dibujo es:
pixmap = [Link](window, width, height, depth=-1)
es o una [Link] o None. Si window es una [Link] entonces depth puede ser -1 para indicar que la profundidad de color se obtiene de la ventana. Si window es Noneentonces depth debe especificarse.
window
El programa [Link] es un ejemplo del uso de un pixmap en un botn. La figura Figura 9.6, Ejemplo de Pixmap en un Botn muestra el resultado: Figura 9.6. Ejemplo de Pixmap en un Botn
16 " ...... ", 17 " .XXX.X. ", 18 " .[Link]. ", 19 " .[Link]. ", 20 " .XXX..... ", 21 " .XXXXXXX. ", 22 " .XXXXXXX. ", 23 " .XXXXXXX. ", 24 " .XXXXXXX. ", 25 " .XXXXXXX. ", 26 " .XXXXXXX. ", 27 " .XXXXXXX. ", 28 " ......... ", 29 " ", 30 " " 31 ] 32 33 class PixmapExample: 34 # cuando se invoca (con la seal delete_event), finaliza la aplicacin. 35 def close_application(self, widget, event, data=None): 36 gtk.main_quit() 37 return [Link] 38 39 # se invoca al pulsar el botn. Simplemente imprime un mensaje 40 def button_clicked(self, widget, data=None): 41 print "button clicked" 42 43 def __init__(self): 44 # crea la ventana principal y conecta la seal delete_event para finalizar 45 # la aplicacin 46 window = [Link](gtk.WINDOW_TOPLEVEL) 47 [Link]("delete_event", self.close_application) 48 window.set_border_width(10) 49 [Link]() 50 51 # ahora el pixmap desde datos XPM 52 pixmap, mask = [Link].pixmap_create_from_xpm_d([Link], 53 None, 54 xpm_data) 55 56 # un control de imagen que contenga el pixmap 57 image = [Link]() 58 image.set_from_pixmap(pixmap, mask) 59 [Link]() 60 61 # un botn que contenga el control de imagen 62 button = [Link]() 63 [Link](image) 64 [Link](button) 65 [Link]()
66 67 68 69 70 71 72 73 74 75
[Link]("clicked", self.button_clicked) def main(): [Link]() return 0 if __name__ == "__main__": PixmapExample() main()
Una desventaja de usar pixmaps es que que el objeto mostrado siempre es rectangular, independientemente de la imagen. Nos gustara crear escritorios y aplicaciones con iconos que tengan formas ms naturales. Por ejemplo, para la 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 imagen de fondo se colorea, no la sobreescribimos con un borde rectangular y que no encaja, de nuestro icono. El programa de ejemplo wheelbarrow.p muestra una imagen completa en el escritorio. La figura Figura 9.7, Ejemplo de Ventana con Forma muestra la imagen sobre una ventana de terminal: Figura 9.7. Ejemplo de Ventana con Forma
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
WheelbarrowFull_xpm = [ "48 48 64 1", " c None", ". c #DF7DCF3CC71B", "X c #965875D669A6", "o c #71C671C671C6", "O c #A699A289A699", "+ c #965892489658", "@ c #8E38410330C2", "# c #D75C7DF769A6", "$ c #F7DECF3CC71B", "% c #96588A288E38", "& c #A69992489E79", "* c #8E3886178E38", "= c #104008200820", "c #596510401040", "; c #C71B30C230C2", ": c #C71B9A699658", "> c #618561856185", ", c #20811C712081", "< c #104000000000", "1 c #861720812081", "2 c #DF7D4D344103", "3 c #79E769A671C6", "4 c #861782078617", "5 c #41033CF34103", "6 c #000000000000", "7 c #49241C711040", "8 c #492445144924", "9 c #082008200820", "0 c #69A618611861", "q c #B6DA71C65144", "w c #410330C238E3", "e c #CF3CBAEAB6DA", "r c #71C6451430C2", "t c #EFBEDB6CD75C", "y c #28A208200820", "u c #186110401040", "i c #596528A21861", "p c #71C661855965", "a c #A69996589658", "s c #30C228A230C2", "d c #BEFBA289AEBA", "f c #596545145144", "g c #30C230C230C2", "h c #8E3882078617", "j c #208118612081", "k c #38E30C300820", "l c #30C2208128A2", "z c #38E328A238E3", "x c #514438E34924", "c c #618555555965", "v c #30C2208130C2", "b c #38E328A230C2",
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
"n c #28A228A228A2", "m c #41032CB228A2", "M c #104010401040", "N c #492438E34103", "B c #28A2208128A2", "V c #A699596538E3", "C c #30C21C711040", "Z c #30C218611040", "A c #965865955965", "S c #618534D32081", "D c #38E31C711040", "F c #082000000820", " ", " .XoO ", " +@#$%o& ", " *=-;#::o+ ", " >,<12#:34 ", " 45671#:X3 ", " +89<02qwo ", "e* >,67;ro ", "ty> 459@>+&& ", "$2u+ ><ipas8* ", "%$;=* *3:.[Link]> ", "Oh$;ya *3d.a8j,Xe.d3g8+ ", " Oh$;ka *3d$a8lz,,xxc:.e3g54 ", " Oh$;kO *pd$%svbzz,sxxxxfX..&wn> ", " Oh$@mO *3dthwlsslszjzxxxxxxx3:td8M4 ", " Oh$@g& *3d$XNlvvvlllm,mNwxxxxxxxfa.:,B* ", " Oh$@,[Link]@V#V@fxxxxxxxf:%j5& ", " Oh$1hd5lllslllCCZrV#r#:#2AxxxxxxxxxcdwM* ", " OXq6c.%8vvvllZZiqqApA:mq:Xxcpcxxxxxfdc9* ", " 2r<6gde3bllZZrVi7S@SV77A::qApxxxxxxfdcM ", " :,[Link]:#riirDSAX@Af5xxxxxfevo", " +A26jguXtAZZZC7iDiCCrVVii7Cmmmxxxxxx%3g", " *#16jszN..3DZZZZrCVSA2rZrV7Dmmwxxxx&en", " p2yFvzssXe:fCZZCiiD7iiZDiDSSZwwxx8e*>", " OA1<jzxwwc:$d%NDZZZZCCCZCCZZCmxxfd.B ", " 3206Bwxxszx%et.eaAp77m77mmmf3&eeeg* ", " @26MvzxNzvlbwfpdettttttttttt.c,n& ", " *;16=lsNwwNwgsvslbwwvccc3pcfu<o ", " p;<69BvwwsszslllbBlllllllu<5+ ", " OS0y6FBlvvvzvzss,u=Blllj=54 ", " c1-699Blvlllllu7k96MMMg4 ", " *10y8n6FjvllllB<166668 ", " S-kg+>666<M<996-y6n<8* ", " p71=4 m69996kD8Z-66698&& ", " &i0ycm6n4 ogk17,0<6666g ", " N-k-<> >=01-kuu666> ", " ,6ky& &46-10ul,66, ", " Ou0<> o66y<ulw<66& ", " *kk5 >66By7=xu664 ", " <<M4 466lj<Mxu66o ", " *>> +66uv,zN666* ", " 566,xxj669 ",
118 " 4666FF666> ", 119 " >966666M ", 120 " oM6668+ ", 121 " *4 ", 122 " ", 123 " " 124 ] 125 126 class WheelbarrowExample: 127 # Cuando se invoca (con la seal delete_event), finaliza la aplicacin 128 def close_application(self, widget, event, data=None): 129 gtk.main_quit() 130 return [Link] 131 132 def __init__(self): 133 # Crea la ventana principal y conecta la seal delete_event para finalizar 134 # la aplicacin. Obsrvese que la ventana principal no tendr ttulo 135 # ya que vamos a hacer una ventana emergente (popup). 136 window = [Link](gtk.WINDOW_POPUP) 137 [Link]("delete_event", self.close_application) 138 window.set_events(window.get_events() | [Link].BUTTON_PRESS_MASK) 139 [Link]("button_press_event", self.close_application) 140 [Link]() 141 142 # ahora para el pixmap y el control de imagen 143 pixmap, mask = [Link].pixmap_create_from_xpm_d( 144 [Link], None, WheelbarrowFull_xpm) 145 image = [Link]() 146 image.set_from_pixmap(pixmap, mask) 147 [Link]() 148 149 # Para mostrar la imagen usamos un control fijo para situarla 150 fixed = [Link]() 151 fixed.set_size_request(200, 200) 152 [Link](image, 0, 0) 153 [Link](fixed) 154 [Link]() 155 156 # Esto enmascara todo salvo la imagen misma 157 window.shape_combine_mask(mask, 0, 0) 158 159 # mostramos la ventana 160 window.set_position(gtk.WIN_POS_CENTER_ALWAYS) 161 [Link]() 162 163 def main(): 164 [Link]() 165 return 0
Para hacer la imagen sensible, conectamos la seal "button_press_event" para que el programa finalice. Las lineas 138-139 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 respecto a la regla. Antes de nada es necesario crear una regla. Las reglas horizontales y verticales se crean usando las siguientes funciones:
hruler = [Link]() vruler = [Link]() # regla horizontal # regla vertical
Una vez que se crea una regla podemos definir la unidad de medida. Las unidades de medida para las reglas pueden ser PIXELS (pxeles), INCHES (pulgadas) o CENTIMETERS (centmetros). Esto se fija con el mtodo:
ruler.set_metric(metric)
Otra caracterstica importante de una regla es cmo marca las unidades de escala y donde se coloca el indicador de posicin inicialmente. Esto se fija usando el mtodo:
ruler.set_range(lower, upper, position, max_size)
Los argumentos lower (bajo) y upper (alto) definen la extensin de la regla, y max_size (tamao mximo) es el mayor nmero posible que se visualizar.
La Position (Posicin) define la posicin inicial del indicador del puntero dentro de la regla. Una regla vertical puede medir una ventana de 800 pxeles de ancho as:
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 configurar 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 [Link]("motion_notify_event", event) area.connect_object("motion_notify_event", motion_notify, ruler)
El programa de ejemplo [Link] 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 figura Figura 9.8, Ejemplo de Reglas ilustra el resultado: Figura 9.8. Ejemplo de Reglas
19 window = [Link](gtk.WINDOW_TOPLEVEL) 20 [Link]("delete_event", self.close_application) 21 window.set_border_width(10) 22 23 # Crea una tabla para colocar la regla y el rea de dibujo 24 table = [Link](3, 2, [Link]) 25 [Link](table) 26 27 area = [Link]() 28 area.set_size_request([Link], [Link]) 29 [Link](area, 1, 2, 1, 2, 30 [Link]|[Link], [Link], 0, 0 ) 31 area.set_events([Link].POINTER_MOTION_MASK | 32 [Link].POINTER_MOTION_HINT_MASK ) 33 34 # La regla horizontal est arriba. Cuando el ratn se mueve por el 35 # rea de dibujo se pasa un evento motion_notify_event al manejador 36 # adecuado para la regla 37 hrule = [Link]() 38 hrule.set_metric([Link]) 39 hrule.set_range(7, 13, 0, 20) 40 def motion_notify(ruler, event): 41 return [Link]("motion_notify_event", event) 42 area.connect_object("motion_notify_event", motion_notify, hrule) 43 [Link](hrule, 1, 2, 0, 1, 44 [Link]|[Link]|[Link], [Link], 0, 0 ) 45 46 # La regla vertical est a la izquierda. Cuando el ratn se mueve por el 47 # rea de dibujo se pasa un evento motion_notify_event al manejador 48 # adecuado para la regla 49 vrule = [Link]() 50 vrule.set_metric([Link]) 51 vrule.set_range(0, [Link], 10, [Link]) 52 area.connect_object("motion_notify_event", motion_notify, vrule) 53 [Link](vrule, 0, 1, 1, 2, 54 [Link], [Link]|[Link]|[Link], 0, 0 ) 55 56 # Ahora mostramos todo 57 [Link]() 58 [Link]() 59 [Link]() 60 [Link]() 61 [Link]() 62 63 def main(): 64 [Link]()
65 66 67 68 69
Las lineas 42 y 52 conectan la retrollamada motion_notify() al rea pasandole hrule en la linea 42 y vrule en la lnea 52 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.
Se puede solicitar un nuevo Identificador de Contexto usando una llamada al siguiente mtodo con una pequea descripcin textual del contexto:
context_id = statusbar.get_context_id(context_description)
El primero, push(), se usa para aadir un nuevo mensaje a la statusbar (barra de estado). Devuelve un message_id (identificador 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 identificador de contexto context_id. El programa de ejemplo [Link] crea una barra de estado y dos botones, uno para insertar elementos en la barra de estado, y otro para sacar el ltimo elemento fuera. La figura Figura 9.9, Ejemplo de Barra de Estado muestra el resultado: Figura 9.9. Ejemplo de Barra de Estado
23 window = [Link](gtk.WINDOW_TOPLEVEL) 24 window.set_size_request(200, 100) 25 window.set_title("PyGTK Statusbar Example") 26 [Link]("delete_event", lambda w,e: gtk.main_quit()) 27 28 vbox = [Link]([Link], 1) 29 [Link](vbox) 30 [Link]() 31 32 self.status_bar = [Link]() 33 vbox.pack_start(self.status_bar, [Link], [Link], 0) 34 self.status_bar.show() 35 36 context_id = self.status_bar.get_context_id("Statusbar example") 37 38 button = [Link]("push item") 39 [Link]("clicked", self.push_item, context_id) 40 vbox.pack_start(button, [Link], [Link], 2) 41 [Link]() 42 43 button = [Link]("pop last item") 44 [Link]("clicked", self.pop_item, context_id) 45 vbox.pack_start(button, [Link], [Link], 2) 46 [Link]() 47 48 # siempre mostramos la ventana al final para que se muestre 49 # de una vez en pantalla. 50 [Link]() 51 52 def main(): 53 [Link]() 54 return 0 55 56 if __name__ == "__main__": 57 StatusbarExample() 58 main()
entry = [Link](max=0)
Si el argumento max se especifica 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 mtodo set_text() fija el contenido del control Entry a text, remplazando el contenido actual. Obsrvese que la clase Entry implementa la 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.
text = entry.get_text()
Si no queremos que el contenido de la Entry sea modificada 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 notificacin 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 controlEntry. 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 [Link] muestra el uso de un control Entry . La figura Figura 9.10, Ejemplo de Entrada muestra el resultado de ejecutar el programa: Figura 9.10. Ejemplo de Entrada
19 20 def __init__(self): 21 # create a new window 22 window = [Link](gtk.WINDOW_TOPLEVEL) 23 window.set_size_request(200, 100) 24 window.set_title("GTK Entry") 25 [Link]("delete_event", lambda w,e: gtk.main_quit()) 26 27 vbox = [Link]([Link], 0) 28 [Link](vbox) 29 [Link]() 30 31 entry = [Link]() 32 entry.set_max_length(50) 33 [Link]("activate", self.enter_callback, entry) 34 entry.set_text("hello") 35 entry.insert_text(" world", len(entry.get_text())) 36 entry.select_region(0, len(entry.get_text())) 37 vbox.pack_start(entry, [Link], [Link], 0) 38 [Link]() 39 40 hbox = [Link]([Link], 0) 41 [Link](hbox) 42 [Link]() 43 44 check = [Link]("Editable") 45 hbox.pack_start(check, [Link], [Link], 0) 46 [Link]("toggled", self.entry_toggle_editable, entry) 47 check.set_active([Link]) 48 [Link]() 49 50 check = [Link]("Visible") 51 hbox.pack_start(check, [Link], [Link], 0) 52 [Link]("toggled", self.entry_toggle_visibility, entry) 53 check.set_active([Link]) 54 [Link]() 55 56 button = [Link](stock=gtk.STOCK_CLOSE) 57 [Link]("clicked", lambda w: gtk.main_quit()) 58 vbox.pack_start(button, [Link], [Link], 0) 59 button.set_flags(gtk.CAN_DEFAULT) 60 button.grab_default() 61 [Link]() 62 [Link]() 63 64 def main(): 65 [Link]() 66 return 0 67 68 if __name__ == "__main__": 69 EntryExample()
70
main()
valor inicial para el Botn Aumentar/Disminuir el valor ms bajo del rango el valor ms alto del rango en un botn
step_increment valor que se incrementa/decrementa cuando se pulsa el botn-1 del ratn page_increment
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 = [Link](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 especifica el nmero de cifras decimales que se mostrarn. Un SpinButton se puede reconfigurar despus de su creacin usando el siguiente mtodo:
spin_button.configure(adjustment, climb_rate, digits)
La variable spin_button especifica el botn aumentar/disminuir que se va a reconfigurar. Los otros argumentos son los mismos que antes. El adjustment (ajuste) se puede fijar y recupar independientemente usando los siguientes dos mtodos:
spin_button.set_adjustment(adjustment) adjustment = spin_button.get_adjustment()
El valor que un SpinButton est 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)
Este mtodo comprime bastante funcionalidad, que explicaremos ahora. Muchos de estos parmetros usan valores del objeto Adjustment (Ajuste) que est asociado con un SpinButton (Botn Aumentar/Disminuir). (paso adelante) y SPIN_STEP_BACKWARD (paso atrs) cambian el valor del SpinButton con una cantidad especificada por el increment (incremento), a menos que increment(incremento) sea igual a 0, en cuyo caso el valor se modifica con el step_increment (incremento de paso) del Adjustment.
SPIN_STEP_FORWARD
(pgina adelante) y SPIN_PAGE_BACKWARD (pgina atrs) simplemente alteran el valor del SpinButton por increment (incremento).
SPIN_PAGE_FORWARD
(inicio) pone el valor del SpinButton a la parte de abajo del rango del Adjustment .
SPIN_HOME
(fin) fija el valor del SpinButton a la parte de arriba del rango del Adjustment .
SPIN_END
(definido por el usuario) simplemente modifica el valor del SpinButton con la cantidad especificada.
SPIN_USER_DEFINED
Ahora nos alejamos de los mtodos para fijar y recuperar los atributos del rango de un SpinButton, y nos centramos en los mtodos que modifican la apariencia y comportamiento del propio controlSpinButton. 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 fijar 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 fija 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)
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 especificado 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, se puede solicitar una actualizacin del SpinButton :
spin_button.update()
El programa de ejemplo [Link] muestra el uso de botones de aumentar/disminuir incluyendo el uso de varias caractersticas. La figura 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
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
import pygtk [Link]('2.0') import gtk class SpinButtonExample: def toggle_snap(self, widget, spin): spin.set_snap_to_ticks(widget.get_active()) def toggle_numeric(self, widget, spin): spin.set_numeric(widget.get_active()) def change_digits(self, widget, spin, spin1): spin1.set_digits(spin.get_value_as_int()) def get_value(self, widget, data, spin, spin2, label): if data == 1: buf = "%d" % spin.get_value_as_int() else: buf = "%0.*f" % (spin2.get_value_as_int(), spin.get_value()) label.set_text(buf) def __init__(self): window = [Link](gtk.WINDOW_TOPLEVEL) [Link]("destroy", lambda w: gtk.main_quit()) window.set_title("Spin Button") main_vbox = [Link]([Link], 5) main_vbox.set_border_width(10) [Link](main_vbox) frame = [Link]("Not accelerated") main_vbox.pack_start(frame, [Link], [Link], 0) vbox = [Link]([Link], 0) vbox.set_border_width(5) [Link](vbox) # Botones de aumentar/disminuir da, mes y ao hbox = [Link]([Link], 0) vbox.pack_start(hbox, [Link], [Link], 5) vbox2 = [Link]([Link], 0) hbox.pack_start(vbox2, [Link], [Link], 5) label = [Link]("Day :") label.set_alignment(0, 0.5) vbox2.pack_start(label, [Link], [Link], 0) adj = [Link](1.0, 1.0, 31.0, 1.0, 5.0, 0.0) spinner = [Link](adj, 0, 0) spinner.set_wrap([Link]) vbox2.pack_start(spinner, [Link], [Link], 0)
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 0.0) 102 103 104 105 106 107 108 109 110 111
vbox2 = [Link]([Link], 0) hbox.pack_start(vbox2, [Link], [Link], 5) label = [Link]("Month :") label.set_alignment(0, 0.5) vbox2.pack_start(label, [Link], [Link], 0) adj = [Link](1.0, 1.0, 12.0, 1.0, 5.0, 0.0) spinner = [Link](adj, 0, 0) spinner.set_wrap([Link]) vbox2.pack_start(spinner, [Link], [Link], 0) vbox2 = [Link]([Link], 0) hbox.pack_start(vbox2, [Link], [Link], 5) label = [Link]("Year :") label.set_alignment(0, 0.5) vbox2.pack_start(label, [Link], [Link], 0) adj = [Link](1998.0, 0.0, 2100.0, 1.0, 100.0, 0.0) spinner = [Link](adj, 0, 0) spinner.set_wrap([Link]) spinner.set_size_request(55, -1) vbox2.pack_start(spinner, [Link], [Link], 0) frame = [Link]("Accelerated") main_vbox.pack_start(frame, [Link], [Link], 0) vbox = [Link]([Link], 0) vbox.set_border_width(5) [Link](vbox) hbox = [Link]([Link], 0) vbox.pack_start(hbox, [Link], [Link], 5) vbox2 = [Link]([Link], 0) hbox.pack_start(vbox2, [Link], [Link], 5) label = [Link]("Value :") label.set_alignment(0, 0.5) vbox2.pack_start(label, [Link], [Link], 0) adj = [Link](0.0, -10000.0, 10000.0, 0.5, 100.0, spinner1 = [Link](adj, 1.0, 2) spinner1.set_wrap([Link]) spinner1.set_size_request(100, -1) vbox2.pack_start(spinner1, [Link], [Link], 0) vbox2 = [Link]([Link], 0) hbox.pack_start(vbox2, [Link], [Link], 5) label = [Link]("Digits :") label.set_alignment(0, 0.5)
112 vbox2.pack_start(label, [Link], [Link], 0) 113 114 adj = [Link](2, 1, 5, 1, 1, 0) 115 spinner2 = [Link](adj, 0.0, 0) 116 spinner2.set_wrap([Link]) 117 [Link]("value_changed", self.change_digits, spinner2, spinner1) 118 vbox2.pack_start(spinner2, [Link], [Link], 0) 119 120 hbox = [Link]([Link], 0) 121 vbox.pack_start(hbox, [Link], [Link], 5) 122 123 button = [Link]("Snap to 0.5-ticks") 124 [Link]("clicked", self.toggle_snap, spinner1) 125 vbox.pack_start(button, [Link], [Link], 0) 126 button.set_active([Link]) 127 128 button = [Link]("Numeric only input mode") 129 [Link]("clicked", self.toggle_numeric, spinner1) 130 vbox.pack_start(button, [Link], [Link], 0) 131 button.set_active([Link]) 132 133 val_label = [Link]("") 134 135 hbox = [Link]([Link], 0) 136 vbox.pack_start(hbox, [Link], [Link], 5) 137 button = [Link]("Value as Int") 138 [Link]("clicked", self.get_value, 1, spinner1, spinner2, 139 val_label) 140 hbox.pack_start(button, [Link], [Link], 5) 141 142 button = [Link]("Value as Float") 143 [Link]("clicked", self.get_value, 2, spinner1, spinner2, 144 val_label) 145 hbox.pack_start(button, [Link], [Link], 5) 146 147 vbox.pack_start(val_label, [Link], [Link], 0) 148 val_label.set_text("0") 149 150 hbox = [Link]([Link], 0) 151 main_vbox.pack_start(hbox, [Link], [Link], 0) 152 153 button = [Link]("Close") 154 [Link]("clicked", lambda w: gtk.main_quit()) 155 hbox.pack_start(button, [Link], [Link], 5) 156 window.show_all() 157 158 def main(): 159 [Link]() 160 return 0 161 162 if __name__ == "__main__":
163 164
SpinButtonExample() main()
Ahora, si se quiere fijar la cadena en la seccin de la entrada de la lista desplegable, esto se hace manipulando el control entrada directamente:
[Link].set_text(text)
Antes de que se pueda hacer esto, hay que componer una lista con las opciones que se deseen.
En este punto ya se tiene una lista desplegable funcionando. Hay unos cuantos aspectos de su comportamiento que se pueden cambiar. Esto se consigue con los 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 flecha 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 flecha 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 flecha abajo se cambia el foco (lo mismo ocurre cuando estas en el primer elemento y pulsas la tecla flecha arriba). Si el valor actual de la entrada no est en la lista, el mtodo set_use_arrows() se desactiva. El mtodo set_use_arrows_always() , cuando val es TRUE, tambin permite al usuario el uso de las teclas de flecha 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 flechas 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 en necesario preocuparse es de obtener los datos de la entrada. La entrada es accesible simplemente como [Link]. Las dos cosas fundamentales que se querrn 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:
[Link]("activate", my_callback, my_data)
que desactivar la seal "activate" en el control de entrada de la lista desplegable. Personalmente, no se me ocurre ninguna situacin en la que se quiera usar, 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 = [Link]()
Puede haber ocasiones en las que se necesite cambiar mucha informacin dentro de este control y los siguientes mtodos permiten realizar mltiples cambios al control Calendar sin que el usuario vea muchos cambios en pantalla.
[Link]() # congelar [Link]() # reanudar
Funcionan exactamente igual que los mtodos freeze/thaw de cualquier otro control (desactivando los cambios y reanudndolos). El control Calendar tiene unas cuantas opciones que 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 especifica que el mes y el ao deben mostrarse cuando se dibuje el calendario. esta opcin especifica que la descripcin de tres letras para cada da (Lun, Mar, etc.) debe mostrarse. esta opcin dice que el usuario no podr cambiar el mes que se muestra. Esto puede ser bueno si slo se necesita mostrar un mes en particular como cuando se muestran 12 controles de calendario uno para cada mes dentro de un mes en particular.
CALENDAR_SHOW_DAY_NAMES
CALENDAR_NO_MONTH_CHANGE
esta opcin especifica que se muestre el nmero de cada semana en la parte de abajo CALENDAR_SHOW_WEEK_NUMBERS izquierda del calendario (ejemplo: Enero 1 = Semana 1, Diciembre 31 = Semana 52). esta opcin dice que la semana empezar en CALENDAR_WEEK_START_MONDAY 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
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 especificado 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. Ha de advertirse que las marcas son persistentes entre cambios de mes y ao. 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
Esto nos deja con la necesidad de poner todo ello junto en el programa de ejemplo [Link]. La figura Figura 9.12, Ejemplo de Calendario muestra el resultado del programa: Figura 9.12. Ejemplo de Calendario
8 # 9 # This program is free software; you can redistribute it and/or modify 10 # it under the terms of the GNU General Public License as published by 11 # the Free Software Foundation; either version 2 of the License, or 12 # (at your option) any later version. 13 # 14 # This program is distributed in the hope that it will be useful, 15 # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 # GNU General Public License for more details. 18 # 19 # You should have received a copy of the GNU General Public License 20 # along with this program; if not, write to the Free Software 21 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22 23 import pygtk 24 [Link]('2.0') 25 import gtk, pango 26 import time 27 28 class CalendarExample: 29 DEF_PAD = 10 30 DEF_PAD_SMALL = 5 31 TM_YEAR_BASE = 1900 32 33 calendar_show_header = 0 34 calendar_show_days = 1 35 calendar_month_change = 2 36 calendar_show_week = 3 37 38 def calendar_date_to_string(self): 39 year, month, day = [Link].get_date() 40 mytime = [Link]((year, month+1, day, 0, 0, 0, 0, 0, 1)) 41 return [Link]("%x", [Link](mytime)) 42 43 def calendar_set_signal_strings(self, sig_str): 44 prev_sig = self.prev_sig.get() 45 self.prev2_sig.set_text(prev_sig) 46 47 prev_sig = self.last_sig.get() 48 self.prev_sig.set_text(prev_sig) 49 self.last_sig.set_text(sig_str) 50 51 def calendar_month_changed(self, widget): 52 buffer = "month_changed: %s" % self.calendar_date_to_string() 53 self.calendar_set_signal_strings(buffer) 54 55 def calendar_day_selected(self, widget):
56 buffer = "day_selected: %s" % self.calendar_date_to_string() 57 self.calendar_set_signal_strings(buffer) 58 59 def calendar_day_selected_double_click(self, widget): 60 buffer = "day_selected_double_click: %s" 61 buffer = buffer % self.calendar_date_to_string() 62 self.calendar_set_signal_strings(buffer) 63 64 year, month, day = [Link].get_date() 65 66 if self.marked_date[day-1] == 0: 67 [Link].mark_day(day) 68 self.marked_date[day-1] = 1 69 else: 70 [Link].unmark_day(day) 71 self.marked_date[day-1] = 0 72 73 def calendar_prev_month(self, widget): 74 buffer = "prev_month: %s" % self.calendar_date_to_string() 75 self.calendar_set_signal_strings(buffer) 76 77 def calendar_next_month(self, widget): 78 buffer = "next_month: %s" % self.calendar_date_to_string() 79 self.calendar_set_signal_strings(buffer) 80 81 def calendar_prev_year(self, widget): 82 buffer = "prev_year: %s" % self.calendar_date_to_string() 83 self.calendar_set_signal_strings(buffer) 84 85 def calendar_next_year(self, widget): 86 buffer = "next_year: %s" % self.calendar_date_to_string() 87 self.calendar_set_signal_strings(buffer) 88 89 def calendar_set_flags(self): 90 options = 0 91 for i in range(5): 92 if [Link][i]: 93 options = options + (1<<i) 94 if [Link]: 95 [Link].display_options(options) 96 97 def calendar_toggle_flag(self, toggle): 98 j = 0 99 for i in range(5): 100 if self.flag_checkboxes[i] == toggle: 101 j = i 102 103 [Link][j] = not [Link][j] 104 self.calendar_set_flags() 105 106 def calendar_font_selection_ok(self, button): 107 [Link] = self.font_dialog.get_font_name() 108 if [Link]:
109 font_desc = [Link]([Link]) 110 if font_desc: 111 [Link].modify_font(font_desc) 112 113 def calendar_select_font(self, button): 114 if not self.font_dialog: 115 window = [Link]("Font Selection Dialog") 116 self.font_dialog = window 117 118 window.set_position(gtk.WIN_POS_MOUSE) 119 120 [Link]("destroy", self.font_dialog_destroyed) 121 122 window.ok_button.connect("clicked", 123 self.calendar_font_selection_ok) 124 window.cancel_button.connect_object("clicked", 125 lambda wid: [Link](), 126 self.font_dialog) 127 window = self.font_dialog 128 if not ([Link]() & [Link]): 129 [Link]() 130 else: 131 [Link]() 132 self.font_dialog = None 133 134 def font_dialog_destroyed(self, data=None): 135 self.font_dialog = None 136 137 def __init__(self): 138 flags = [ 139 "Show Heading", 140 "Show Day Names", 141 "No Month Change", 142 "Show Week Numbers", 143 ] 144 [Link] = None 145 [Link] = None 146 self.font_dialog = None 147 self.flag_checkboxes = 5*[None] 148 [Link] = 5*[0] 149 self.marked_date = 31*[0] 150 151 window = [Link](gtk.WINDOW_TOPLEVEL) 152 window.set_title("Calendar Example") 153 window.set_border_width(5) 154 [Link]("destroy", lambda x: gtk.main_quit()) 155 156 window.set_resizable([Link]) 157 158 vbox = [Link]([Link], self.DEF_PAD) 159 [Link](vbox)
160 161 # La parte superior de la ventana, el Calendario, las opcines y fuente. 162 hbox = [Link]([Link], self.DEF_PAD) 163 vbox.pack_start(hbox, [Link], [Link], self.DEF_PAD) 164 hbbox = [Link]() 165 hbox.pack_start(hbbox, [Link], [Link], self.DEF_PAD) 166 hbbox.set_layout(gtk.BUTTONBOX_SPREAD) 167 hbbox.set_spacing(5) 168 169 # Control calendario 170 frame = [Link]("Calendar") 171 hbbox.pack_start(frame, [Link], [Link], self.DEF_PAD) 172 calendar = [Link]() 173 [Link] = calendar 174 self.calendar_set_flags() 175 calendar.mark_day(19) 176 self.marked_date[19-1] = 1 177 [Link](calendar) 178 [Link]("month_changed", self.calendar_month_changed) 179 [Link]("day_selected", self.calendar_day_selected) 180 [Link]("day_selected_double_click", 181 self.calendar_day_selected_double_click) 182 [Link]("prev_month", self.calendar_prev_month) 183 [Link]("next_month", self.calendar_next_month) 184 [Link]("prev_year", self.calendar_prev_year) 185 [Link]("next_year", self.calendar_next_year) 186 187 separator = [Link]() 188 hbox.pack_start(separator, [Link], [Link], 0) 189 190 vbox2 = [Link]([Link], self.DEF_PAD) 191 hbox.pack_start(vbox2, [Link], [Link], self.DEF_PAD) 192 193 # Crear el frame derecho con sus opciones 194 frame = [Link]("Flags") 195 vbox2.pack_start(frame, [Link], [Link], self.DEF_PAD) 196 vbox3 = [Link]([Link], self.DEF_PAD_SMALL) 197 [Link](vbox3) 198 199 for i in range(len(flags)): 200 toggle = [Link](flags[i]) 201 [Link]("toggled", self.calendar_toggle_flag) 202 vbox3.pack_start(toggle, [Link], [Link], 0) 203 self.flag_checkboxes[i] = toggle 204 205 # Crear el botn de fuentes derecho 206 button = [Link]("Font...") 207 [Link]("clicked", self.calendar_select_font) 208 vbox2.pack_start(button, [Link], [Link], 0) 209 210 # Crear la parte relativo a seales
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
frame = [Link]("Signal events") vbox.pack_start(frame, [Link], [Link], self.DEF_PAD) vbox2 = [Link]([Link], self.DEF_PAD_SMALL) [Link](vbox2) hbox = [Link] ([Link], 3) vbox2.pack_start(hbox, [Link], [Link], 0) label = [Link]("Signal:") hbox.pack_start(label, [Link], [Link], 0) self.last_sig = [Link]("") hbox.pack_start(self.last_sig, [Link], [Link], 0) hbox = [Link] ([Link], 3) vbox2.pack_start(hbox, [Link], [Link], 0) label = [Link]("Previous signal:") hbox.pack_start(label, [Link], [Link], 0) self.prev_sig = [Link]("") hbox.pack_start(self.prev_sig, [Link], [Link], 0) hbox = [Link] ([Link], 3) vbox2.pack_start(hbox, [Link], [Link], 0) label = [Link]("Second previous signal:") hbox.pack_start(label, [Link], [Link], 0) self.prev2_sig = [Link]("") hbox.pack_start(self.prev2_sig, [Link], [Link], 0) bbox = [Link] () vbox.pack_start(bbox, [Link], [Link], 0) bbox.set_layout(gtk.BUTTONBOX_END) button = [Link]("Close") [Link]("clicked", lambda w: gtk.main_quit()) [Link](button) button.set_flags(gtk.CAN_DEFAULT) button.grab_default() window.show_all() def main(): [Link]() return 0 if __name__ == "__main__": CalendarExample() main()
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 tonosaturacin y una barra de valor. Opcionalmente, la opacidad del color tambin se puede especificar. 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 especifique explcitamente a travs del mtodo set_color() . Veamos lo que nos ofrece el control de seleccin de color. El control viene en dos sabores: [Link] y [Link].
colorsel = [Link]()
Probablemente no se use este constructor directamente. Se crea un control ColorSelection huerfano que habra que emparentar uno mismo. El control ColorSelection hereda del control VBox.
colorseldlg = [Link](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. ste consiste en un Frame que contiene un control ColorSelection, un HSeparator y un HBox con tres botones, Ok, Cancelar y Ayuda. Se pueden 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 = [Link]
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 TRUEactiva la opacidad. De la misma forma, has_opacity igual a FALSE desactivar la opacidad.
colorsel.set_current_color(color) 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 valor del canal alfaalpha debe estar entre 0 (completamente transparente) y 65636 (completamente opaco).
color = colorsel.get_current_color() alpha = colorsel.get_current_alpha()
Cuando se tenga que mirar el color actual, tpicamente al recibir la seal "color_changed", se pueden usar esos mtodos. El programa de ejemplo [Link] 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 figura 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
15 # Obtenemos el color actual 16 color = [Link].get_current_color() 17 18 # Fijamos el color de fondo de la ventana 19 [Link].modify_bg(gtk.STATE_NORMAL, color) 20 21 # manejador de eventos del rea de dibujo 22 def area_event(self, widget, event): 23 handled = [Link] 24 25 # Comprobamos si se ha recibido un evento de pulsacin de botn 26 if [Link] == [Link].BUTTON_PRESS: 27 handled = [Link] 28 29 # Creamos el dilogo de seleccin de color 30 if [Link] == None: 31 [Link] = [Link]( 32 "Select background color") 33 34 # Obtenemos el control ColorSelection 35 colorsel = [Link] 36 37 colorsel.set_previous_color([Link]) 38 colorsel.set_current_color([Link]) 39 colorsel.set_has_palette([Link]) 40 41 # Lo conectamos a la seal "color_changed" 42 [Link]("color_changed", self.color_changed_cb) 43 # Mostramos el dilogo 44 response = [Link]() 45 46 if response -- gtk.RESPONSE_OK: 47 [Link] = colorsel.get_current_color() 48 else: 49 [Link].modify_bg(gtk.STATE_NORMAL, [Link]) 50 51 [Link]() 52 53 return handled 54 55 # manejador de cierre y salida 56 def destroy_window(self, widget, event): 57 gtk.main_quit() 58 return [Link] 59 60 def __init__(self): 61 [Link] = None 62 # creacin de la ventana principal, ttulo y polticas 63 window = [Link](gtk.WINDOW_TOPLEVEL) 64 window.set_title("Color selection test") 65 window.set_resizable([Link])
66 67 # La conectamos a los eventos "delete" y "destroy" para poder salir 68 [Link]("delete_event", self.destroy_window) 69 70 # Creamos un rea de dibujo, fijamos su tamao y capturamos eventos de botn 71 [Link] = [Link]() 72 73 [Link] = [Link].get_colormap().alloc_color(0, 65535, 0) 74 75 [Link].set_size_request(200, 200) 76 [Link].set_events([Link].BUTTON_PRESS_MASK) 77 [Link]("event", self.area_event) 78 79 # Aadimos el rea de dibujo a la ventana y mostramos ambos controles 80 [Link]([Link]) 81 [Link]() 82 [Link]() 83 84 def main(): 85 [Link]() 86 return 0 87 88 if __name__ == "__main__": 89 ColorSelectionExample() 90 main()
Para fijar el nombre de fichero, por ejemplo para mostrar un directorio especfico, o establecer un fichero predeterminado, usa este mtodo:
filesel.set_filename(filename)
Para obtener el nombre de fichero que el usuario ha escrito o seleccionado, se usa este mtodo:
filename = filesel.get_filename()
Tambin hay referencias a los controles contenidos en el control de seleccin de ficheros. 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 # dilogo filesel.fileop_entry # entrada filesel.fileop_file # fichero filesel.fileop_c_dir # cambio de directorio filesel.fileop_del_file # borrar fichero filesel.fileop_ren_file # renombrar fichero filesel.button_area # rea de botones filesel.action_area # rea de accin
Lo ms probable es que se quieran usar los atributos ok_button, cancel_button, y help_button para conectar sus seales a las retrollamadas. El programa de ejemplo [Link] ilustra el uso del control de seleccin de ficheros. Como se puede ver, no hay mucho ms que decir para crear un control de seleccin de ficheros. Aunque en este ejemplo el botn Ayuda aparece en pantalla, no hace nada porque no hay ninguna seal conectada a l. La figura Figura 9.14, Ejemplo de Seleccin de Ficheros muestra la pantalla resultante: Figura 9.14. Ejemplo de Seleccin de Ficheros
25 # Conectar cancel_button para destruir el control 26 [Link].cancel_button.connect("clicked", 27 lambda w: [Link]()) 28 29 # Fijamos el nombre de fichero, como si fuese un dilogo de guardado, 30 # y damos un nombre por defecto 31 [Link].set_filename("[Link]") 32 33 [Link]() 34 35 def main(): 36 [Link]() 37 return 0 38 39 if __name__ == "__main__": 40 FileSelectionExample() 41 main()
una interfaz para seleccionar la fuente, el estilo y el tamao informacin detallada sobre la fuente seleccionada una interfaz para el mecanismo de filtrado de fuente que restringe las fuentes disponibles para seleccionar
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 cancel_button
El atributo fontsel es una referencia al control de seleccin de fuente. main_vbox es una referencia a la [Link] que contiene el fontsel y el action_area en el dilogo. El atributo action_area es una referencia a
la [Link] que contiene los botones OK, Aplicar y Cancelar. Los atributos ok_button, cancel_button y apply_button son referencias a los botones OK, Cancelar y Aplicarque 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 Aplicar mediante el mtodo show() . Se puede fijar 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 completo o parcialmente especificado. Por ejemplo:
fontseldlg.set_font_name('-adobe-courier-bold-*-*-*-*-120-*-*-*-*-*-*')
especifica 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 programa de ejemplo [Link] usa un dilogo de seleccin de fuentes para seleccionar la fuente que se usa para mostrar la informacin del calendario. Las lineas 105-110 definen una retrollamada para obtener el nombre de la fuente a partir del Dilogo de Seleccin de Fuentes y lo usa para fijar la fuente para el control del calendario. Las lineas 112-131 definen el mtodo que crea un Dilogo de Seleccin de Fuentes, configura las retrollamadas para los botones OK y Cancelar y muestra el dilogo.
Tabla de contenidos 10.1. La Caja de Eventos (EventBox) 10.2. El control Alineador 10.3. Contenedor Fijo (Fixed) 10.4. Contenedor de Disposicin (Layout) 10.5. Marcos (Frame) 10.6. Marcos Proporcionales (AspectFrame) 10.7. Controles de Panel (HPaned y VPaned) 10.8. Vistas (Viewport) 10.9. Ventanas de Desplazamiento (ScrolledWindow) 10.10. Cajas de Botones (ButtonBoxes) 10.11. Barra de Herramientas (Toolbar) 10.12. Fichas (Notebook) 10.13. Elementos incrustables y puntos de conexin (Plugs y Sockets) 10.13.1. Elementos incrustables (Plugs) 10.13.2. Puntos de Conexin (Sockets)
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, se usa:
event_box = [Link]()
El programa de ejemplo [Link] muestra dos usos de un EventBox - se crea una etiqueta y se recorta en una caja pequea, tiene un fondo verde y se ha configurado 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 figura Figura 10.1, Ejemplo de Caja de Eventos muestra la ventana del programa: Figura 10.1. Ejemplo de Caja de Eventos
principal 17 event_box = [Link]() 18 [Link](event_box) 19 event_box.show() 20 21 # Creamos una etiqueta larga 22 label = [Link]("Click here to quit, quit, quit, quit, quit") 23 event_box.add(label) 24 [Link]() 25 26 # La recortamos 27 label.set_size_request(110, 20) 28 29 # Y conectamos una accin a la misma 30 event_box.set_events([Link].BUTTON_PRESS_MASK) 31 event_box.connect("button_press_event", lambda w,e: gtk.main_quit()) 32 33 # Ms cosas para las que se necesita una ventana de X ... 34 event_box.realize() 35 event_box.window.set_cursor([Link]([Link].HAND1)) 36 37 # Poner el fondo en verde 38 event_box.modify_bg(gtk.STATE_NORMAL, 39 event_box.get_colormap().alloc_color("green")) 40 41 [Link]() 42 43 def main(): 44 [Link]() 45 return 0 46 47 if __name__ == "__main__": 48 EventBoxExample() 49 main()
La funcin [Link]() crea un nuevo control Alignment con los parmetros especificados. El mtodo set() permite alterar los parmetros de alineacin de un control Alignment existente. Los cuatro parmetros son nmeros en coma flotante que pueden estar entre 0.0 y 1.0. Los argumentos xalign y yalign afectan a la posicin del control dentro del Alignment. Las propiedades de alineacin especifican la fraccin de espacio libre que se colocar por encima o a la izquierda del control hijo. Sus valoren van de 0.0 (sin espacio libre por encima o a la izquierda del hijo) a 1.0 (todo espacio libre o a la izquierda del hijo). Naturalmente, si las dos propiedades de escala estn puestas a 1.0, entonces las propiedades de alineacin no tienen efecto, puesto que el control hijo se expandir para llenar el espacio disponible. Los argumentos xscale e yscale especifican la fraccin de espacio libre absorbido por el control hijo. Los valores pueden variar desde 0.0 (el hijo no absorbe nada) hasta 1.0 (el hijo toma todo el espaciolibre. Un control hijo puede aadirse a este Alignment usando:
[Link](widget)
Para un ejemplo del uso de un control Alignment, consulte el ejemplo del control de Barra de Progreso [Link]
El mtodo put() coloca al control en el contenedor fijo en la posicin especificada por x e y. El mtodo move() te permite mover el control especificado a una nueva posicin. El ejemplo [Link] ilustra cmo usar el contenedor Fixed . La figura Figura 10.2, Ejemplo de Fijo muestra el resultado: Figura 10.2. Ejemplo de Fijo
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 fijo 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
def __init__(self): self.x = 50 self.y = 50 # Creamos una nueva ventana window = [Link](gtk.WINDOW_TOPLEVEL) window.set_title("Fixed Container") # Conectamos el evento "destroy" a un manejador de seales [Link]("destroy", lambda w: gtk.main_quit()) # Fija el grosor del borde de ventana window.set_border_width(10) # Creamos un contenedor Fixed [Link] = [Link]() [Link]([Link]) [Link]() for i in range(1, 4): # Crea un nuevo ton con la etiqueta "Press me" button = [Link]("Press me") # Cuando el botn recibe la seal "clicked" llamar al # mtodo move_button(). [Link]("clicked", self.move_button) # Empaquetamos el botn en la ventana del contenedor [Link](button, i*50, i*50) # El paso final es mostrar el control recin creado [Link]() # Mostramos la ventana [Link]() def main(): # Entramos en el bucle de eventos [Link]() return 0 if __name__ == "__main__": FixedExample() main()
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 se tenga un desplazamiento suave incluso cuando se tienen muchos controles en el rea de desplazamiento. Un contenedor Layout se crea con:
layout = [Link](hadjustment=None, vadjustment=None)
Como se puede ver, se puede especificar opcionalmente los objetos Adjustment que el control Layout usar para su desplazamiento. Si no se especifican los objetos Adjustment, se crearn unos nuevos. Se pueden aadir y mover controles en el contenedor Layout usando los dos mtodos siguientes:
[Link](child_widget, x, y) [Link](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 [Link] 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 figura Figura 10.3, Ejemplo de Disposicin ilustra la ventana inicial del programa: Figura 10.3. Ejemplo de Disposicin
23 24 def __init__(self): 25 # creamos la ventana principal 26 window = [Link](gtk.WINDOW_TOPLEVEL) 27 window.set_title("Layout Example") 28 window.set_default_size(300, 300) 29 [Link]("delete-event", [Link]) 30 [Link]("destroy", [Link]) 31 # creamos la tabla y la empaquetamos en la ventana 32 table = [Link](2, 2, [Link]) 33 [Link](table) 34 # creamos el control disposicin y lo empaquetamos en la tabla 35 [Link] = [Link](None, None) 36 [Link].set_size(600, 600) 37 [Link]([Link], 0, 1, 0, 1, [Link]|[Link], 38 [Link]|[Link], 0, 0) 39 # creamos las barras de desplazamiento y las empaquetamos tambin 40 vScrollbar = [Link](None) 41 [Link](vScrollbar, 1, 2, 0, 1, [Link]|[Link], 42 [Link]|[Link], 0, 0) 43 hScrollbar = [Link](None) 44 [Link](hScrollbar, 0, 1, 1, 2, [Link]|[Link], 45 [Link]|[Link], 0, 0) 46 # indicamos a las barras de desp. que usen el ajuste del control disposicin 47 vAdjust = [Link].get_vadjustment() 48 vScrollbar.set_adjustment(vAdjust) 49 hAdjust = [Link].get_hadjustment() 50 hScrollbar.set_adjustment(hAdjust) 51 # creamos 3 botones ylos ponemos en el control disposicin 52 button = [Link]("Press Me") 53 [Link]("clicked", [Link]) 54 [Link](button, 0, 0) 55 button = [Link]("Press Me") 56 [Link]("clicked", [Link]) 57 [Link](button, 100, 0) 58 button = [Link]("Press Me") 59 [Link]("clicked", [Link]) 60 [Link](button, 200, 0) 61 # mostramos todos los controles 62 window.show_all() 63 64 def main(): 65 # entramos en el bucle principal 66 [Link]() 67 return 0 68 69 if __name__ == "__main__": 70 LayoutExample() 71 main()
El label (ttulo) se coloca en la esquina superior izquierda del marco de manera predeterminada. Especificando un valor de None para el argumento label o sin especificar el argumento label har que no se visualice ningn ttulo. El texto del ttulo se puede cambiar usando el mtodo:
frame.set_label(label)
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.
xalign
El siguiente mtodo modifica el estilo de la caja que se usa para rodear el marco.
frame.set_shadow_type(type)
El ejemplo [Link] muestra el uso del control Marco. La figura Figura 10.4, Ejemplo de Marco muestra la ventana resultante: Figura 10.4. Ejemplo de Marco
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
# Alineamos la etiqueta a la derecha del marco frame.set_label_align(1.0, 0.0) # Fijamos el estilo del marco frame.set_shadow_type(gtk.SHADOW_ETCHED_OUT) [Link]() # Mostramos la ventana [Link]() def main(): # Entramos en el bucle de eventos [Link]() return 0 if __name__ == "__main__": FrameExample() main()
especifica el texto a mostrar en el ttulo. xalign e yalign especifican 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 especifica dicho cociente con el argumento ratio.
label
Como ejemplo, el programa [Link] usa un AspectFrame para presentar un rea de dibujo cuyo cociente de proporcionalidad ser siempre 2:1, aunque el usuario redimensione la ventana contenedora. La figura Figura 10.5, Ejemplo de Marco Proporcional muestra la ventana del programa: Figura 10.5. Ejemplo de Marco Proporcional
22 [Link](aspect_frame) 23 aspect_frame.show() 24 25 # Aadimos un control hijo al marco proporcional 26 drawing_area = [Link]() 27 28 # Solicitamos una ventana 200x200, pero AspectFrame nos devolver una 200x100 29 # puesto que forzamos una proporcin 2x1 30 drawing_area.set_size_request(200, 200) 31 aspect_frame.add(drawing_area) 32 drawing_area.show() 33 [Link]() 34 35 def main(): 36 [Link]() 37 return 0 38 39 if __name__ == "__main__": 40 AspectFrameExample() 41 main()
Despus de crear el control de panel, hay que aadir hijos a sus dos mitades. Para hacer eso, se usan los mtodos:
paned.add1(child) paned.add2(child)
El mtodo add1() aade el control hijo child a la izquierda o arriba del control de panel. El mtodo add2() aade un control hijo child a la derecha o abajo del panel.
El programa de ejemplo [Link] 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 figura Figura 10.6, Ejemplo de Panel muestra el resultado de ejecutar el programa: Figura 10.6. Ejemplo de Panel
1 #!/usr/bin/env python 2 3 # ejemplo [Link] 4 5 import pygtk 6 [Link]('2.0') 7 import gtk, gobject 8 9 class PanedExample: 10 # Creamos la lista de "mensajes" 11 def create_list(self): 12 # Creamos una ventana, con desplazamiento si es necesario 13 scrolled_window = [Link]() 14 scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) 15 16 model = [Link](gobject.TYPE_STRING) 17 tree_view = [Link](model) 18 scrolled_window.add_with_viewport (tree_view) 19 tree_view.show() 20 21 # Aadimos algunos mensajes a la ventana 22 for i in range(10): 23 msg = "Message #%d" % i 24 iter = [Link]() 25 [Link](iter, 0, msg) 26 27 cell = [Link]() 28 column = [Link]("Messages", cell, text=0) 29 tree_view.append_column(column) 30 31 return scrolled_window 32 33 # Aadimos texto a nuestro control de texto - esta retrollamada se invoca 34 # cuando se realiza nuestra ventana. Podramos forzar tambin la realizacin 35 # mediante [Link](), pero primero tendra que ser parte 36 # de una jerarqua 37 def insert_text(self, buffer): 38 iter = buffer.get_iter_at_offset(0) 39 [Link](iter, 40 "From: pathfinder@[Link]\n" 41 "To: mom@[Link]\n" 42 "Subject: Made it!\n" 43 "\n" 44 "We just got in this morning. The weather has been\n" 45 "great - clear but cold, and there are lots of fun sights.\n" 46 "Sojourner says hi. See you soon.\n" 47 " -Path\n") 48
49 # Creamos un rea de texto desplazable que muestra un "mensaje" 50 def create_text(self): 51 view = [Link]() 52 buffer = view.get_buffer() 53 scrolled_window = [Link]() 54 scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) 55 scrolled_window.add(view) 56 self.insert_text(buffer) 57 scrolled_window.show_all() 58 return scrolled_window 59 60 def __init__(self): 61 window = [Link](gtk.WINDOW_TOPLEVEL) 62 window.set_title("Paned Windows") 63 [Link]("destroy", lambda w: gtk.main_quit()) 64 window.set_border_width(10) 65 window.set_size_request(450, 400) 66 67 # creamos un control vpaned y lo aadimos a la ventana principal 68 vpaned = [Link]() 69 [Link](vpaned) 70 [Link]() 71 72 # Ahora creamos los contenidos de las dos partes de la ventana 73 list = self.create_list() 74 vpaned.add1(list) 75 [Link]() 76 77 text = self.create_text() 78 vpaned.add2(text) 79 [Link]() 80 [Link]() 81 82 def main(): 83 [Link]() 84 return 0 85 86 if __name__ == "__main__": 87 PanedExample() 88 main()
Un control de vista permite colocar un control ms grande dentro de l de tal forma que se pueda ver una parte de l de una vez. Usa Adjustments para definir el rea que se ve. Un Viewport se crea con la funcin:
viewport = [Link](hadjustment=None, vadjustment=None)
Como se puede ver se pueden especificar los Adjustments horizontal y vertical que el control usa cuando se crea. Crear sus propios ajustes si se le pasa None como valor de los argumentos o simplemente no se le pasan argumentos. Se pueden consultar y fijar 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)
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 especifican.
scrolled_window.set_policy(hscrollbar_policy, vscrollbar_policy)
Este mtodo especifica la poltica a usar con respecto a las barras de desplazamiento. El primer argumento le fija 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 decidir automticamente si son necesarias las barras de desplazamiento, mientras que POLICY_ALWAYSsiempre dejar visibles las barras de desplazamiento. Tras esto se puede colocar el objeto dentro de la ventana de desplazamiento usando el siguiente mtodo.
scrolled_window.add_with_viewport(child)
El programa de ejemplo [Link] coloca una tabla con 100 botones biestado dentro de una ventana de desplazamiento. Slo se comentan las partes que pueden ser nuevas. La figura Figura 10.7, Ejemplo de Ventana de Desplazamiento muestra la ventana del programa: Figura 10.7. Ejemplo de Ventana de Desplazamiento
27 # POLICY_AUTOMATIC decidir automticamente la necesidad de barras de 28 # desplazamiento, mientras que POLICY_ALWAYS dejar permanentemente las 29 # barras. La primera es la barra de desplazamiento horizontal, la segunda la 30 # vertical. 31 scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS) 32 33 # Se crea la ventana de dilogo con una vbox en ella 34 [Link].pack_start(scrolled_window, [Link], [Link], 0) 35 scrolled_window.show() 36 37 # creamos una tabla de 10 por 10 casillas 38 table = [Link](10, 10, [Link]) 39 40 # fijamos el espaciado a 10 en x y 10 en y 41 table.set_row_spacings(10) 42 table.set_col_spacings(10) 43 44 # empaquetamos la tabla en la ventana de desplazamiento 45 scrolled_window.add_with_viewport(table) 46 [Link]() 47 48 # esto simplemente crea una trama de botones biestado en la tabla 49 # para demostrar el uso de la ventana de desplazamiento 50 for i in range(10): 51 for j in range(10): 52 buffer = "button (%d,%d)" % (i, j) 53 button = [Link](buffer) 54 [Link](button, i, i+1, j, j+1) 55 [Link]() 56 57 # Aadimos un botn "close" en la parte inferior del dilogo 58 button = [Link]("close") 59 button.connect_object("clicked", [Link], window) 60 61 # ponemos el botn como posible predeterminado 62 button.set_flags(gtk.CAN_DEFAULT) 63 window.action_area.pack_start( button, [Link], [Link], 0) 64 65 # Esto lo establece como predeterminado. Pulsando 66 # "Enter" har que se active este botn 67 button.grab_default() 68 [Link]() 69 [Link]() 70 71 def main(): 72 [Link]()
73 74 75 76 77
Si se prueba a cambiar el tamao a la ventana se ver cmo reaccionan las barras de desplazamiento. Puede que tambin se quiera usar el mtodo set_size_request() para fijar el tamao por defecto de la ventana o de otros controles.
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)
button_box.add(widget)
El programa de ejemplo [Link] ilustra todos los tipos de disposicin de las ButtonBoxes. La ventana resultante es:
6 [Link]('2.0') 7 import gtk 8 9 class ButtonBoxExample: 10 # Creamos una Button Box con los parmetros especificados 11 def create_bbox(self, horizontal, title, spacing, layout): 12 frame = [Link](title) 13 14 if horizontal: 15 bbox = [Link]() 16 else: 17 bbox = [Link]() 18 19 bbox.set_border_width(5) 20 [Link](bbox) 21 22 # Fijamos el aspecto de Button Box 23 bbox.set_layout(layout) 24 bbox.set_spacing(spacing) 25 26 button = [Link](stock=gtk.STOCK_OK) 27 [Link](button) 28 29 button = [Link](stock=gtk.STOCK_CANCEL) 30 [Link](button) 31 32 button = [Link](stock=gtk.STOCK_HELP) 33 [Link](button) 34 35 return frame 36 37 def __init__(self): 38 window = [Link](gtk.WINDOW_TOPLEVEL) 39 window.set_title("Button Boxes") 40 41 [Link]("destroy", lambda x: gtk.main_quit()) 42 43 window.set_border_width(10) 44 45 main_vbox = [Link]([Link], 0) 46 [Link](main_vbox) 47 48 frame_horz = [Link]("Horizontal Button Boxes") 49 main_vbox.pack_start(frame_horz, [Link], [Link], 10) 50 51 vbox = [Link]([Link], 0) 52 vbox.set_border_width(10) 53 frame_horz.add(vbox) 54 55 vbox.pack_start(self.create_bbox([Link], "Spread (spacing 40)", 56 40, gtk.BUTTONBOX_SPREAD), 57 [Link], [Link], 0)
58 59 vbox.pack_start(self.create_bbox([Link], "Edge (spacing 30)", 60 30, gtk.BUTTONBOX_EDGE), 61 [Link], [Link], 5) 62 63 vbox.pack_start(self.create_bbox([Link], "Start (spacing 20)", 64 20, gtk.BUTTONBOX_START), 65 [Link], [Link], 5) 66 67 vbox.pack_start(self.create_bbox([Link], "End (spacing 10)", 68 10, gtk.BUTTONBOX_END), 69 [Link], [Link], 5) 70 71 frame_vert = [Link]("Vertical Button Boxes") 72 main_vbox.pack_start(frame_vert, [Link], [Link], 10) 73 74 hbox = [Link]([Link], 0) 75 hbox.set_border_width(10) 76 frame_vert.add(hbox) 77 78 hbox.pack_start(self.create_bbox([Link], "Spread (spacing 5)", 79 5, gtk.BUTTONBOX_SPREAD), 80 [Link], [Link], 0) 81 82 hbox.pack_start(self.create_bbox([Link], "Edge (spacing 30)", 83 30, gtk.BUTTONBOX_EDGE), 84 [Link], [Link], 5) 85 86 hbox.pack_start(self.create_bbox([Link], "Start (spacing 20)", 87 20, gtk.BUTTONBOX_START), 88 [Link], [Link], 5) 89 90 hbox.pack_start(self.create_bbox([Link], "End (spacing 20)", 91 20, gtk.BUTTONBOX_END), 92 [Link], [Link], 5) 93 94 window.show_all() 95 96 def main(): 97 # Entramos en el bucle de eventos 98 [Link]() 99 return 0 100 101 if __name__ == "__main__": 102 ButtonBoxExample() 103 main()
Despus de crear una barra de herramientas uno puede aadir al principio, al final 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 final un item se pueden 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 se quiere usar el mtodo insert_item(), el nico parmetro adicional que debe especificarse, es la posicin en la cual el elemento se debe insertar. As:
toolbar.insert_item(text, tooltip_text, tooltip_private_text, icon, callback, user_data, position)
Para aadir de forma sencilla espacios entre items de la barra de herramientas se pueden 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 u ORIENTATION_VERTICAL. El style se usa para especificar 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 cosas que se pueden hacer con una barra de herramientas veamos el siguiente programa de ejemplo [Link] (interrumpiremos el listado con explicaciones adicionales):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #!/usr/bin/env python # ejemplo [Link] import pygtk [Link]('2.0') import gtk class ToolbarExample: # Este mtodo se conecta al botn Close o # al cierre de la ventana desde el Gestor de Ventanas def delete_event(self, widget, event=None): gtk.main_quit() return [Link]
Este principio debera resultar familiar si no es el primer programa PyGTK. No obstante hay una cosa ms, vamos a importar un bonito dibujo XPM ([Link]) para que nos sirva de icono para todos los botones. La linea 10 empieza la clase de ejemplo ToolbarExample y las lineas 12-14 definen el mtodo de retrollamada que finalizar el programa.
16 # es fcil... cuando se conmuta uno de los botones, simplemente 17 # comprobamos cul est activo y cambiamos el estilo de la barra de herramientas
18 19 20 21 22 23 24 25 26 27 28 29 30 31
# de acuerdo con ello def radio_event(self, widget, toolbar): if self.text_button.get_active(): toolbar.set_style(gtk.TOOLBAR_TEXT) elif self.icon_button.get_active(): toolbar.set_style(gtk.TOOLBAR_ICONS) elif self.both_button.get_active(): toolbar.set_style(gtk.TOOLBAR_BOTH) # incluso ms fcil, comprobamos la conmutacin del botn # y activamos/desactivamos las pistas def toggle_event(self, widget, toolbar): toolbar.set_tooltips(widget.get_active())
Las lineas 19-30 son dos mtodos de retrollamada que se llamarn cuando uno de los botones de la barra de herramientas se active. Estas cosas resultan familiares si ya se han usado botones biestado (y botones de exclusin mtua).
32 def __init__(self): 33 # Aqu est la ventana principal (un dilogo) y el asa 34 # necesitamos una barra de herramientas, un icono con mscara (uno para todos 35 # los botones) y un control de icono en el que ponerlo (aunque crearemos 36 # un control aparte para cada botn) 37 # creamos una nueva ventana con su ttulo y un tamao adecuado 38 dialog = [Link]() 39 dialog.set_title("GTKToolbar Tutorial") 40 dialog.set_size_request(450, 250) 41 dialog.set_resizable([Link]) 42 43 # generalmente querremos salir si cierran la ventana 44 [Link]("delete_event", self.delete_event) 45 46 # para que tenga mejor aspecto ponemos la barra en la caja con asa 47 # de manera que se pueda separar de la ventana principal 48 handlebox = [Link]() 49 [Link].pack_start(handlebox, [Link], [Link], 5) 50
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 explicacin: una caja con mango (asa) (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 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 flotante). Normalmente es bueno tener una barra de herramientas separable, por lo que estos dos controles suelen ir juntos normalmente.
51 texto, y 52 53 54 55 56 57 58 59 # la barra de herramientas ser horizontal, con iconos y # con espacios de 5pxl entre elementos y, finalmente, # la insertaremos en la caja con asa toolbar = [Link]() toolbar.set_orientation(gtk.ORIENTATION_HORIZONTAL) toolbar.set_style(gtk.TOOLBAR_BOTH) toolbar.set_border_width(5) [Link](toolbar)
Bien, lo que hacemos arriba es una simple inicializacin del control de la barra de herramientas.
60 61 62 63 64 65 66 67 68 69 70 # nuestro primer elemento es el botn <close> iconw = [Link]() # control de icono iconw.set_from_file("[Link]") close_button = toolbar.append_item( "Close", # etiqueta de botn "Closes this app", # la pista del botn "Private", # informacin privada de la pista iconw, # control icono self.delete_event) # una seal toolbar.append_space() # espacio tras el elemento
En el cdigo anterior se puede ver el caso ms simple: aadir un botn a la barra de herramientas. Justo antes de aadir el nuevo elemento, tenemos que construir un control de imgen que servir como icono para este elemento; este paso tiene que repetirse para cada nuevo elemento. Justo despus del elemento aadimos tambin espacio, para que los elementos siguientes no se toquen unos a otros. Como se puede ver, el mtodo append_item() devuelve una referencia al control de botn recin creado, para que se pueda trabajar con l de la forma habitual.
71 72 73 74 75 76 77 78 # ahora, hagamos el grupo de botones de exclusin... iconw = [Link]() # control de icono iconw.set_from_file("[Link]") icon_button = toolbar.append_element( gtk.TOOLBAR_CHILD_RADIOBUTTON, # type of element None, # control "Icon", # etiqueta "Only icons in toolbar", # pista
79 pista 80 81 82 83 84 85
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 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.
86 anteriores 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 # los siguientes botones de exclusin se refieren a los iconw = [Link]() # control de icono iconw.set_from_file("[Link]") text_button = toolbar.append_element( gtk.TOOLBAR_CHILD_RADIOBUTTON, icon_button, "Text", "Only texts in toolbar", "Private", iconw, self.radio_event, toolbar) toolbar.append_space() self.text_button = text_button iconw = [Link]() # control de icono iconw.set_from_file("[Link]") both_button = toolbar.append_element( gtk.TOOLBAR_CHILD_RADIOBUTTON, text_button, "Both", "Icons and text in toolbar", "Private", iconw, self.radio_event, toolbar) toolbar.append_space() self.both_button = both_button
114 115
both_button.set_active([Link])
Creamos otros botones de exclusin mtua de la misma forma excepto que le pasamos uno de los botones creados al mtodo append_element() para especificar el grupo. Al final tenemos que establecer el estado de uno de los botones manualmente (si no todos tienen el estado activo, impidindonos que los vayamos intercambiando).
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 # aqu ponemos simplemente un botn biestado iconw = [Link]() # control de icono iconw.set_from_file("[Link]") tooltips_button = toolbar.append_element( gtk.TOOLBAR_CHILD_TOGGLEBUTTON, None, "Tooltips", "Toolbar with or without tips", "Private", iconw, self.toggle_event, toolbar) toolbar.append_space() tooltips_button.set_active([Link])
Un botn biestado se puede crear de la forma obvia (si ya se han creado botones de exclusin mtua alguna vez).
131 # para empaquetar un control en la barra, solamente tenemos 132 # crearlo y aadirlo con una pista apropiada 133 entry = [Link]() 134 toolbar.append_widget(entry, "This is just an entry", "Private") 135 136 # bien, no est creada dentro de la barra, as que tenemos que mostrarla 137 [Link]() 138
Como se puede ver, aadir cualquier tipo de control a una barra de herramientas es fcil. La nica cosa que se tiene que recordar es que este control debe mostrarse manualmente (al contrario que los elementos, que se mostrarn de golpe con la barra de herramientas).
139 # ya est! Mostremos todo. 140 [Link]() 141 [Link]() 142 [Link]() 143 144 def main(): 145 # nos quedamos en gtk_main y esperamos que empiece la diversin! 146 [Link]() 147 return 0 148 149 if __name__ == "__main__": 150 ToolbarExample() 151 main()
La linea 142 termina la definicin de la clase ToolbarExample. Las lineas 144-147 definen la funcin main() que simplemente llama a la funcin [Link]() para iniciar el bucle de procesamiento de eventos. Las lineas 149-151 crean una instancia de ToolbarExample y luego entran en el bucle de procesamiento de eventos. As termina el tutorial de la barra de herramientas. Por supuesto, para apreciarla en su mximo esplendor se necesita tambin el icono XPM, [Link]. La figura Figura 10.8, Ejemplo de Barra de Herramientas muestar la ventana resultante: Figura 10.8. Ejemplo de Barra de Herramientas
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 a un tiempo. Este control se ha hecho muy popular ltimamente en la programacin de interfaces grficas de usuario, y es una buena manera de mostrar bloques de informacin similar que guardan una separacin en la pantalla. La primera funcin que se necesita saber, como probablemente se adivine, se usa para crear un nuevo control de fichas.
notebook = [Link]()
Una vez que se han creado las fichas, hay unos cuantos mtodos que manipulan el control. Vemoslos uno a uno. El primero que trataremos especifica cmo colocar los indicadores de pgina. Estos indicadores o "pestaas" como se las conoce, se pueden colocar de cuatro maneras: arriba, abajo, izquierda o derecha.
notebook.set_tab_pos(pos) pos
es el valor predeterminado.
Lo siguiente que trataremos ser cmo aadir pginas a las fichas. 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 fichas insertndolas al final (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 configuracin dentro de otro control contenedor, tal como una tabla.
El ltimo mtodo para aadir una pgina a las fichas contiene todas las propiedades de los otros dos, y adems permite especificar en qu posicin se insertar la pgina en las fichas.
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 especificar 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 fichas.
notebook.remove_page(page_num)
Este mtodo borra la pgina especificada por page_num de las fichas contenidas en la variable notebook. Para saber cul es la pgina actual de las fichas utiliza el mtodo:
page = notebook.get_current_page()
Los prximos dos mtodos son simples llamadas para mover la pgina hacia adelante o hacia atrs. Simplemente se utilizan en el control de fichas sobre el que se quiera operar.
notebook.next_page() notebook.prev_page()
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 aprev_page(), no pasa nada. Este mtodo fija la pgina "activa". Si se quiere que las fichas comiencen con la pgina 5 activa, se usar este mtodo. Si no se usa, el comportamiento predeterminado de las fichas 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 se tiene un gran nmero de pginas, y las pestaas no caben en la pgina. Permite desplazarse por las pestaas usando dos botones de flechas.
notebook.set_scrollable(scrollable)
(mostrar pestaas), show_border (mostrar border) y scrollable (desplazable) pueden ser TRUE o FALSE.
show_tabs
Ahora veamos un ejemplo. El programa [Link] crea una ventana con unas fichas y seis botones. Las fichas contienen 11 pginas, aadidas de tres formas diferentes, al final, en medio y al principio. Los botones 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 figura Figura 10.9, Ejemplo de Fichas muestra la ventana del programa: Figura 10.9. Ejemplo de Fichas
[Link](notebook, 0,6,0,1) [Link]() self.show_tabs = [Link] self.show_border = [Link] # Aadimos unas cuantas pginas a las fichas for i in range(5): bufferf = "Append Frame %d" % (i+1) bufferl = "Page %d" % (i+1) frame = [Link](bufferf) frame.set_border_width(10) frame.set_size_request(100, 75) [Link]() label = [Link](bufferf) [Link](label) [Link]() label = [Link](bufferl) notebook.append_page(frame, label) # Ahora aadimos una pgina en un punto determinado checkbutton = [Link]("Check me please!") checkbutton.set_size_request(100, 75) [Link] () label = [Link]("Add page") notebook.insert_page(checkbutton, label, 2) # Finalmente aadimos una pgina delante for i in range(5): bufferf = "Prepend Frame %d" % (i+1) bufferl = "PPage %d" % (i+1) frame = [Link](bufferf) frame.set_border_width(10) frame.set_size_request(100, 75) [Link]() label = [Link](bufferf) [Link](label) [Link]() label = [Link](bufferl) notebook.prepend_page(frame, label) # Establecer en qu pgina empezamos (pgina 4) notebook.set_current_page(3) # Creamos unos cuantos botones button = [Link]("close") [Link]("clicked", [Link]) [Link](button, 0,1,1,2)
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
[Link]() button = [Link]("next page") [Link]("clicked", lambda w: notebook.next_page()) [Link](button, 1,2,1,2) [Link]() button = [Link]("prev page") [Link]("clicked", lambda w: notebook.prev_page()) [Link](button, 2,3,1,2) [Link]() button = [Link]("tab position") [Link]("clicked", self.rotate_book, notebook) [Link](button, 3,4,1,2) [Link]() button = [Link]("tabs/border on/off") [Link]("clicked", self.tabsborder_book, notebook) [Link](button, 4,5,1,2) [Link]() button = [Link]("remove page") [Link]("clicked", self.remove_book, notebook) [Link](button, 5,6,1,2) [Link]() [Link]() [Link]() def main(): [Link]() return 0 if __name__ == "__main__": NotebookExample() main()
Espero que esto ayude en el camino para crear fichas en los programas PyGTK.
Un Plug encapsula una interfaz de usuario aportada por una aplicacin de forma que se puede embeber en la interfaz de otra aplicacin. La seal "embedded" alerta a la aplicacin embebida que ha sido embebida en la interfaz de usuario de la otra aplicacin. Un Plug se crea con la siguiente funcin:
plug = [Link](socket_id)
que crea un nuevo Plug y lo embebe en el Socket identificado por socket_id. Si socket_id es 0L, el elemento conectable queda "desconectado" y puede ser conectado ms tarde a un Socket utilizando el mtodo de Socket add_id(). El mtodo de Plug:
id = plug.get_id()
devuelve el identificador de ventana (window ID) de un Plug, que se puede usar para embeberlo en un Socket utilizando el mtodo de Socket add_id(). El programa de ejemplo [Link] ilustra el uso de un elemento conectable Plug:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #!/usr/bin/python import pygtk [Link]('2.0') import gtk,sys Wid = 0L if len([Link]) == 2: Wid = long([Link][1]) plug = [Link](Wid) print "Plug ID=", plug.get_id() def embed_event(widget): print "I (",widget,") have just been embedded!" [Link]("embedded", embed_event) entry = [Link]() entry.set_text("hello") def entry_point(widget): print "You've changed my text to '%s'" % widget.get_text() [Link]("changed", entry_point) [Link]("destroy", [Link])
26 27 28 29 30 31
donde windowID es el ID (identificador) de un Socket al que conectar el Plug. 10.13.2. Puntos de Conexin (Sockets) Un Socket proporciona el control que permite embeber un control incrustable Plug desde otra aplicacin a la propia interfaz de forma transparente. Una aplicacin crea un control Socket, pasa el ID de ventana de ese control a otra aplicacin, que luego crea un Plug utilizando ese ID de ventana como parmetro. Cualquier control contenido en el elemento Plug aparece dentro de la ventana de la primera aplicacin. El identificador (ID) de ventana del Socket se obtiene utilizando el mtodo de Socket get_id(). Antes de usar este mtodo el Socket debe estar realizado y aadido a su control padre. Nota Si se le pasa el ID de ventana del Socket a otro proceso que va a crear un elemento Plug en el Socket, es preciso asegurarse de que el control Socket no se va a destruir hasta que se crea el elemento Plug. Cuando se notifica a GTK+ que la ventana embebida ha sido destruda, entonces tambin se encarga de destruir el Socket. Por tanto, se debe prever la posibilidad de que los sockets se destruyan en cualquier momento mientras el bucle de eventos principal est en ejecucin. La destruccin de un Socket provocar tambin la destruccin de un Plug embebido en l. La comunicacin entre un Socket y un Plug se hace segn el protocolo XEmbed. Este protocolo tambin se ha implementado en otros toolkits como Qt, lo que permite el mismo nivel de integracin al integrar un control de Qt en GTK+ o viceversa.
El Socket debe estar contenido en una ventana raz antes de la invocacin del mtodo add_id():
socket.add_id(window_id)
que aade un cliente XEMBED, tal como un Plug, al Socket. El cliente puede estar en el mismo proceso o en uno diferente. Para embeber un Plug en un Socket se puede, bien crear el Plug con:
plug = [Link](0L)
y luego pasar el nmero devuelto por el mtodo de Plug get_id() al mtodo de Socket add_id():
socket.add_id(plug)
para obtener el identificador de ventana (ID) del socket, y luego crear el plug con:
plug = [Link](window_id)
El Socket debe haber sido aadido ya a una ventana raz antes de que se pueda hacer esta llamada. El programa de ejemplo [Link] ilustra el uso de un Socket:
1 2 3 4 5 6 7 8 #!/usr/bin/python import string import pygtk [Link]('2.0') import gtk,sys
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
window = [Link]() [Link]() socket = [Link]() [Link]() [Link](socket) print "Socket ID=", socket.get_id() [Link]("destroy", [Link]) def plugged_event(widget): print "I (",widget,") have just had a plug inserted!" [Link]("plug-added", plugged_event) if len([Link]) == 2: socket.add_id(long([Link][1])) [Link]()
Tabla de contenidos 11.1. Creacin Manual de Mens 11.2. Ejemplo de Men Manual 11.3. Uso de la Factoria de Elementos 11.4. Ejemplo de Factoria de Elementos - ItemFactory Hay dos formas de crear mens: la forma fcil y la dificil. Cada una tiene sus usos, pero normalmente se puede usar el Itemfactory (Factoria de Elementos) (la forma fcil). La forma "difcil" consiste en crear los mens usando llamadas directamente, mientras que de la forma fcil se hacen llamadas a GtkItemFactory. Esto ltimo 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 ms ventajoso de cara a la usabilidad. Por ejemplo, con Itemfactory, no es posible aadir imgenes o el carcter '/' a los mens.
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 sirve de contenedor para cada uno de los mens individuales.
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 = [Link]()
Esta funcin bastante autoexplicativa crea una nueva barra de mens. Se puede usar el mtodo [Link] add() para meter la barra de mens en una ventana, o los mtodos pack de [Link] para meterlo en una caja - igual que los botones.
menu = [Link]()
Esta funcin devuelve una referencia a un nuevo men; nunca se mostrar (con el mtodo show() ), es slo un contenedor para elementos de mens. Esto se aclarar ms cuando se vea el ejemplo que aparece 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 = [Link](label=None)
El parmetro label, si existe, se analizar buscando caracteres mnemnicos. Esta llamada se usa para crear los elementos de men que se van a visualizar. Debe recordarse la diferenciar entre un "men" como el que se crea con la funcin [Link]() y un "elemento de men" como el que se crea con [Link]() . El elemento de men ser en realidad un botn con una accin asociada, mientras que un men ser un contenedor que contiene elementos de men. Una vez se ha creado un elemento de men es preciso meterlo en un men. Esto se consigue con el mtodo append() . Para poder saber cundo el usuario selecciona un elemento, se necesita conectarlo a la seal "activate" de la forma habitual. Por tanto, si se quiere crear un men estndar Archivo, con las opciones Abrir, Guardar, y Salir, el cdigo sera algo asi como:
file_menu = [Link]() # Creamos open_item save_item quit_item # No necesitamos mostrar los mens
file_menu.append(open_item) file_menu.append(save_item) file_menu.append(quit_item) # Se conectan las funciones de retrollamada a la seal "activate" open_item.connect_object("activate", menuitem_response, "[Link]") save_item.connect_object("activate", menuitem_response, "[Link]") # se conecta el elemento quit a nuestra funcin de salida quit_item.connect_object ("activate", destroy, "[Link]") # Mostramos los elementos de men open_item.show() save_item.show() quit_item.show()
En este punto tenemos nuestro men. Ahora es necesario crear una barra de men y un elemento de men para la entrada Archivo, al que aadiremos nuestro men. El cdigo es el siguiente:
menu_bar = [Link]() [Link](menu_bar) menu_bar.show() file_item = [Link]("Archivo") file_item.show()
Ahora necesitamos asociar el men con file_item. Esto se hace con el mtodo:
menu_item.set_submenu(submenu)
Lo nico que nos queda es aadir el men a la barra de mens, lo cual se consigue con el mtodo:
menu_bar.append(child)
Si queremos el men justificado a la derecha en la barra de mens, como suelen ser 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 tenemos un resumen de los pasos necesarios para crear una barra de mens con mens en ella:
y y
y y y y
Se crea un nuevo men con [Link]() Se hacen varias llamadas a [Link](), una para cada elemento que se quiera tener en el men. Y se usa el mtodo append() para poner cada uno de estos elementos en el men. Se crea un elemento de men usando [Link](). Este ser la raiz del men, el texto que aparezca en l estar en la propia barra de mens. Se usa el mtodo set_submenu() para aadir el men al elemento raiz del men (el creado en el paso anterior). Se crea una nueva barra de mens con [Link](). Este paso se hace nicamente una vez al crear una serie de mens en una barra de mens. Se usa el mtodo append() para poner el men raiz en la barra de mens.
La creacin de un men emergente es prcticamente igual. 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. Se han de seguir estos pasos:
y
y y
y usar el evento para saber donde mostrar el men. En el manejador del evento, si el evento es una pulsacin de botn, se trata el evento como un evento de botn (realmente lo es) y se usa como en el cdigo de ejemplo para pasar informacin al mtodo popup() . Se enlaza el manejador del evento al control con:
widget.connect_object("event", handler, menu)
donde widget es el control al que se est conectando, handler es la funcin manejadora, y menu es un men creado con [Link](). Esto puede ser un
men que tambin est en una barra de mens, tal como se muestra en el cdigo de ejemplo.
24 # "test-menu". Obsrvese la llamada a gtk_menu_append. Aqu vamos 25 # aadiendo una lista de elementos de men a nuestro men. Normalmente tambin 26 # interceptaramos la seal "clicked" para cada uno de los elementos de men y 27 # se establecera una retrollamada para ellas, pero se omiten aqu para ahorrar espacio 28 for i in range(3): 29 # Copiar los nombres a buf 30 buf = "Test-undermenu - %d" % i 31 32 # Crear un nuevo elemento de men con nombre... 33 menu_items = [Link](buf) 34 35 # ...y lo aadimos al men 36 [Link](menu_items) 37 38 # Hacemos algo interesante cuando se selecciona el elemento de men 39 menu_items.connect("activate", self.menuitem_response, buf) 40 41 # Mostramos el control 42 menu_items.show() 43 44 # Este es el men raz, y ser la etiqueta mostrada en la barra de men 45 # No tendr un manejador de seal asociado, puesto que nicamente 46 # muestra el resto del men al pulsarlo. 47 root_menu = [Link]("Root Menu") 48 49 root_menu.show() 50 51 # Ahora especificamos que queremos que nuestro recien creado "menu" sea el 52 # men del men raz "root menu" 53 root_menu.set_submenu(menu) 54 55 # Una vbox para poner un men y un botn en l: 56 vbox = [Link]([Link], 0) 57 [Link](vbox) 58 [Link]() 59 60 # Creamos una barra de men para los mens, que aadimos a la ventana principal 61 menu_bar = [Link]() 62 vbox.pack_start(menu_bar, [Link], [Link], 2) 63 menu_bar.show() 64 65 # Creamos un botn al que aadir el men emergente 66 button = [Link]("press me") 67 button.connect_object("event", self.button_press, menu)
68 vbox.pack_end(button, [Link], [Link], 2) 69 [Link]() 70 71 # Y finalmente aadimos el elemento de men a la barra de men. Este es el 72 # elemento de men raz del que hemos estado hablando =) 73 menu_bar.append (root_menu) 74 75 # siempres mostramos la ventana como ltimo paso, de manera que se dibuja todo 76 # de una vez. 77 [Link]() 78 79 # Respondemos a una pulsacin de botn con un men pasado como control "widget" 80 # 81 # Ntese que el argumento "widget" es el men pasado, NO 82 # el botn que fue pulsado. 83 def button_press(self, widget, event): 84 if [Link] == [Link].BUTTON_PRESS: 85 [Link](None, None, None, [Link], [Link]) 86 # Notificamos al cdigo de llamada que hemos manejado este evento. 87 # La cola acaba aqu. 88 return [Link] 89 # Notificamos al cdigo de llamada que no manejamos este evento. La cola contina. 90 return [Link] 91 92 # Imprimimos una cadena cuando se selecciona un elemento de men 93 def menuitem_response(self, widget, string): 94 print "%s" % string 95 96 def main(): 97 [Link]() 98 return 0 99 100 if __name__ == "__main__": 101 MenuExample() 102 main()
Tambin se puede hacer un elemento de men insensible y, usando una tabla de atajos (aceleradores), conectar teclas a retrollamadas de mens.
21 # Item 5: El tipo de elemento, usado para definir el tipo al que pertenece el elemento 22 # Aqui estn los posibles valores 23 24 # NULL -> "<Item>" 25 # "" -> "<Item>" 26 # "<Title>" -> crear un elemento de ttulo 27 # "<Item>" -> crear un elemento simple 28 # "<CheckItem>" -> crear un elemento de activacin 29 # "<ToggleItem>" -> crear un botn biestado 30 # "<RadioItem>" -> crear un botn de exclusin mtua 31 # <path> -> ruta de un elemento de exclusin mtua 32 # "<Separator>" -> crear un separador 33 # "<Branch>" -> crear un contenedor de nuevos elementos 34 # "<LastBranch>" -> crear una rama justificada a la derecha 35 36 def get_main_menu(self, window): 37 accel_group = [Link]() 38 39 # Esta funcin inicializa la factora de elementos. 40 # Param 1: El tipo del men - puede ser MenuBar, Menu, 41 # u OptionMenu. 42 # Param 2: La ruta o camino del men. 43 # Param 3: Una referencia a un AccelGroup. La factoria de elementos establece la 44 # tabla de aceleradores (atajos) al generar los mens. 45 item_factory = [Link]([Link], "<main>", accel_group) 46 47 # Este mtodo genera los elementos de men. Pasa a la factora de elementos la lista 48 # de los elementos de men 49 item_factory.create_items(self.menu_items) 50 51 # Aadir el nuevo grupo de aceleradores a la ventana. 52 window.add_accel_group(accel_group) 53 54 # es necesario mantener una referencia a item_factory para evitar su destruccin 55 self.item_factory = item_factory 56 # Finalmente, se devuelve la barra de men creada por la factora de elementos. 57 return item_factory.get_widget("<main>") 58 59 def __init__(self): 60 self.menu_items = ( 61 ( "/_File", None, None, 0, "<Branch>" ), 62 ( "/File/_New", "<control>N", self.print_hello, 0,
None ), 63 ( "/File/_Open", "<control>O", self.print_hello, 0, None ), 64 ( "/File/_Save", "<control>S", self.print_hello, 0, None ), 65 ( "/File/Save _As", None, None, 0, None ), 66 ( "/File/sep1", None, None, 0, "<Separator>" ), 67 ( "/File/Quit", "<control>Q", [Link], 0, None ), 68 ( "/_Options", None, None, 0, "<Branch>" ), 69 ( "/Options/Test", None, None, 0, None ), 70 ( "/_Help", None, None, 0, "<LastBranch>" ), 71 ( "/_Help/About", None, None, 0, None ), 72 ) 73 window = [Link](gtk.WINDOW_TOPLEVEL) 74 [Link]("destroy", [Link], "WM destroy") 75 window.set_title("Item Factory") 76 window.set_size_request(300, 200) 77 78 main_vbox = [Link]([Link], 1) 79 main_vbox.set_border_width(1) 80 [Link](main_vbox) 81 main_vbox.show() 82 83 menubar = self.get_main_menu(window) 84 85 main_vbox.pack_start(menubar, [Link], [Link], 0) 86 [Link]() 87 [Link]() 88 89 def main(): 90 [Link]() 91 return 0 92 93 if __name__ == "__main__": 94 ItemFactoryExample() 95 main()
Por ahora esto es slo un ejemplo. Ms adelante aparecer una explicacin y muchos comentarios.
El control DrawingArea (rea de Dibujo) proporciona un lienzo en el que poder dibujar de forma sencilla haciendo uso de los mtodos de la clase [Link] ("dibujable"). Un controlDrawingArea en realidad encapsula un elemento del tipo [Link] (ventana), que es una subclase de [Link] (al igual que [Link]). Para crear un rea de Dibujo se utiliza la funcin:
drawing_area = [Link]()
Los elementos DrawingArea (rea de Dibujo) se crean inicialmente con un tamao de (0,0), por lo que es necesario usar el siguiente mtodo para poder hacer visible el rea de Dibujo (drawing_area) asignndole un ancho y una altura distintas de cero:
drawing_area.set_size_request(width, height)
Para dibujar en este control es necesario acceder a su dibujable ([Link]) asociado, en este caso una ventana ([Link]), utilizando su atributo window:
drawable = drawing_area.window
Nota Para poder acceder a la ventana ([Link]) asociada al rea de dibujo (DrawingArea) y poder dibujar en ella el rea de Dibujo debe haber sido instanciada (lo que da lugar a que genere una seal "realize").
clip_mask # mscara de recorte clip_x_origin # origen x del rectngulo de recorte clip_y_origin # origen y del rectngulo de recorte fill # relleno font # fuente foreground # color de frente (primer plano) function # funcin graphics_exposures # exposiciones grficas join_style # estilo de unin de lneas line_style # estilo de linea line_width # ancho de linea stipple # patrn de relleno sub_window # subventana tile # ttulo ts_x_origin # origen x ts_y_origin # origen y background foreground
(frente) especifica el [Link] que se usa para dibujar el color de primer plano. Para crear un [Link] que represente un color dado se emplea el mtodo alloc_color() de la clase [Link] (Mapa de Color). Previamente a la creacin de un color se debe disponer de un mapa de color asociado a un control (widget). Para ello se debe hacer uso del siguiente mtodo:
colormap = widget.get_colormap()
A la hora de especificar un [Link] tenemos varias opciones. Por un lado se puede indicar el color deseado utilizando una cadena de texto (tales como "red" (rojo), "orange" (naranja) o "navajo white" (blanco navajo) de entre las que se definen en el archivo [Link] de X Window; o, por otro lado, se puede indicar un triplete de nmeros enteros, situados dentro del rango de valores 0 a 65535, que indican la cantidad de rojo (red), verde (green) y azul (blue) cuya mezcla produce el color deseado. Adems se pueden especificar otras propiedades que especifican si el color es modificable (propiedad writeable), de manera que es posible modificar su valor despus pero no se puede compartir;o si se debe seleccionar el color ms parecido entre los disponibles cuando no sea posible representar el color exacto (propiedad best_match). El mtodo alloc_color() se define as:
color = colormap.alloc_color(red, green, blue, writeable=FALSE, best_match=TRUE) color = colormap.alloc_color(spec, writeable=FALSE, best_match=TRUE)
especifica el estilo con el que se dibujan los extremos de las lneas que no estn conectadas a otras lneas. Los diferentes estilos disponibles son:
cap_style CAP_NOT_LAST
igual que CAP_BUTT para lineas con ancho distinto de cero. En el caso de lneas de ancho cero no se dibuja el punto final de la linea. los extremos de las lineas se dibujan como cuadrados que se extienden hasta las coordenadas del punto final. los extremos de las lineas se dibujan como semicrculos de dimetro igual al grosor de la linea y cuyo centro se sita en el punto final. prolongan medio grosor ms all del punto final.
CAP_BUTT
CAP_ROUND
CAP_PROJECTING los extremos de las lineas son dibujados como cuadrados que se
especifica un mapa de pxeles ([Link]) que se usar para hacer el recorte del dibujo contenido en el rea de dibujo (drawing_area).
clip_mask
y clip_y_origin especifican los valores de las coordenadas x e y correspondientes al origen del rectngulo de recorte tomando como referencia la esquina superior izquierda del rea de dibujo (drawing_area).
clip_x_origin
especifica el estilo de relleno usado en el dibujo. Los estilos de relleno que se encuentran disponibles son:
fill SOLID TILED STIPPLED
dibuja utilizando el color de primer plano (foreground). dibuja usando un patrn en cuadrcula. dibuja usando un patrn de mapa de bits. Los pxeles correspondientes a los bits activados (a uno) del mapa de bits se dibujan usando el color de
primer plano (foregraund) y aquellos correspondientes a los bits que no estn activados se dejan intactos. dibuja usando un patrn de mapa de bits. Los pxeles correspondientes a los bits del mapa de bits que estn activados (a uno) se dibujan con el OPAQUE_STIPPLED color de primer plano; aquellos correspondientes a los bits que no estn activados se dibujan con el color de fondo.
es la [Link] (Fuente) que se usa cmo fuente predeterminada para dibujar texto.
font
Nota El uso del atributo font est obsoleto. especifica una funcin usada para combinar los valores de los bits de los pxeles de origen con los valores de los bits de los pxeles de destino y producir un pixel transformado. Los 16 posibles valores de este parmetro corresponden a las tablas de verdad posibles de tamao 2x2. Sin embargo, solamente algunos de estos valores tienen utilidad en la prctica. As, en el caso de imgenes a color es frecuentel el uso de COPY, XOR e INVERT y en el de mapas de bits tambin son habituales AND y OR. Los valores posibles de function son:
function COPY INVERT XOR CLEAR AND AND_REVERSE AND_INVERT NOOP OR EQUIV OR_REVERSE COPY_INVERT OR_INVERT NAND SET # # # # # # # # # # # # # # # Copiar Invertir O exclusivo Limpiar Y Y al revs Y invertida Nada O equivalencia O al revs Copiar invertido O invertido No-Y Fijar
especifica si las exposiciones grficas estn activadas (TRUE) o desactivadas (FALSE). Cuando graphics_exposures tiene el valor TRUE un fallo al copiar un pxel en una operacin de dibujo genera un evento expose y en el caso de que la copia tenga xito se generar un evento noexpose.
graphics_exposures
especifica el estilo de unin que se usa en los encuentros de lineas en ngulo. Los estilos disponibles son:
join_style JOIN_MITER los lados de cada linea se extienden para unirse en ngulo. JOIN_ROUND los lados de las dos lineas se unen con un arco de crculo. JOIN_BEVEL
los lados de las dos lineas se unen en chafln, una linea recta que forma el mismo ngulo con cada una de las lneas.
especifica el estilo con el que se dibuja una linea. Los estilos disponibles son:
line_style LINE_SOLID
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 LINE_DOUBLE_DASH fondo aplicado a la mscara del patrn si el estilo de relleno es STIPPLED.
line_width stipple
especifica el [Link] que se usar como patrn cuando el relleno est puesto a STIPPLED o a OPAQUE_STIPPLED. especifica el modo de dibujo de una ventana ([Link]) que tiene ventanas hijas ([Link]). Los valores posibles de este parmetro son:
sub_window CLIP_BY_CHILDREN INCLUDE_INFERIORS
slo se dibuja en la propia ventana pero no en sus ventanas hijas. dibuja en la ventana y en sus ventanas hijas.
especifica el [Link] que se usar para dibujo cuadriculado cuando el relleno (fill) est puesto a TILED.
tile
y ts_y_origin especifican las posiciones iniciales (el origen) de los mapas de bits de patrn y de dibujo cuadriculado.
ts_x_origin
Un Contexto Grfico nuevo se crea mediante una llamada al mtodo [Link] new_gc() :
gc = drawable.new_gc(foreground=None, background=None, font=None, 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 poder crear un nuevo Contexto Grfico usando este mtodo es preciso que el control (correspondiente a drawable) sea:
y y
una ventana ([Link]) ya realizada (realized), o bien: un mapa de pxeles ([Link]) asociado a una ventana ([Link]) ya realizada.
Los diversos atributos del Contexto Grfico tienen los valores por defecto si no se fijan en el mtodo new_gc(). Si se desea establecer el valor de los atributos de los contextos grficos mediante el mtodonew_gc() resulta muy prctico el uso de argumentos con nombre de Python. Tambin se pueden establecer los atributos individuales de un [Link] asisgnando valores a los atributos correspondientes. Estos son algunos ejemplos de ello:
gc.cap_style = CAP_BUTT gc.line_width = 10 [Link] = SOLD [Link] = micolor
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 de trazos que se usa cuando el parmetro de estilo de linea (line_style) es LINE_ON_OFF_DASH o LINE_DOUBLE_DASH se puede fijar haciendo uso del siguiente mtodo:
gc.set_dashes(offset, dash_list)
donde offset (desplazamiento) es el ndice del valor del trazo inicial en dash_list y dash_list (lista de trazos) es una lista o tupla que contiene los nmeros de pxeles que dibujar o saltar para formar los trazos. stos se dibujan empezando con el nmero de pxeles en la posicin de desplazamiento(offset); despus, el siguiente nmero de pxeles no se dibuja, y, luego, se dibuja el siguiente nmero de pxeles;; y as se contina recorriendo todos los nmeros de la lista de trazos y empezando otra vez cuando se llega a su final. Por ejemplo, si la lista de trazos es (2, 4, 8, 16) y el desplazamiento es 1, los trazos se dibujarn as: dibuja 4 pxeles, salta 8 pxeles, dibuja 16 pxeles, salta 2 pxeles, dibuja 4 pxeles, y as sucesivamente. Es posible hacer una copia de un [Link] existente utilizando el mtodo:
[Link](src_gc)
gc x1
es el Contexto Grfico.
es el Contexto Grfico.
es un valor booleano que indica si el rectngulo debe ser rellenado con el color de primer plano (valor TRUE) o no (valor FALSE).
filled x
e y son las coordenadas de la esquina superior izquierda del rectngulo. y height son el ancho y el alto del rectngulo.
width
es el Contexto Grfico.
es un valor booleano que indica si el arco debe ser rellenado con el color de primer plano (valor TRUE) o no (valor FALSE).
filled
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.
x
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 sesenta y cuatroavos de grado.
angle1
es el ngulo final del arco, relativo a angle1, en sesenta y cuatroavos de grado en el sentido de las agujas del reloj.
angle2 drawable.draw_polygon(gc, filled, points) # dibuja polgono
gc
es el Contexto Grfico.
es un valor booleano que especifica si el polgono debe ser rellenado con el color de primer plano o(valor TRUE) o no (valor FALSE).
filled
es una lista de los puntos que se van a dibujar como un polgono conectado, escrita como una lista de tuplas con las coordenadas, como por ejemplo: [ (0,0), (2,5), (3,7), (4,11) ].
points drawable.draw_string(font, gc, x, y, string) # dibuja cadena drawable.draw_text(font, gc, x, y, string) # dibuja texto font gc x
es el Contexto Grfico.
e y son las coordenadas del punto donde se empezar a dibujar la cadena, es decir, la lnea base izquierda.
string
Nota Ambos mtodos draw_string() y draw_text() estn obsoletos - en su lugar se debe usar un [Link] con el mtodo draw_layout() .
drawable.draw_layout(gc, x, y, layout) # dibuja disposicin gc x
es el Contexto Grfico.
e y son las coordenadas del punto desde el que se empieza a dibujar la disposicin.
layout
drawable.draw_drawable(gc, src, xsrc, ysrc, xdest, ydest, width, height) # dibuja dibujable gc
src
e ysrc son las coordenadas de la esquina superior izquierda del rectngulo en el dibujable de orgen.
xsrc
y height son el ancho y el alto del rea del dibujable de origen que ser copiada al dibujable (drawable). Si width o height es -1 entonces se usar el ancho o el alto total del dibujable.
width drawable.draw_image(gc, image, xsrc, ysrc, xdest, ydest, width, height) # dibuja imagen gc
image xsrc
e ysrc son las coordenadas de la esquina superior izquierda del rectngulo en el dibujable origen. e ydest son las coordenadas de la esquina superior izquierda del rectngulo en el rea de dibujo.
xdest
y height son el ancho y el alto del rea del dibujable origen que se copiar en el dibujable (drawable) destino. Si width o height es -1 entonces se usar el ancho o el alto total de la imagen.
width drawable.draw_points(gc, points) # dibuja puntos gc
es el Contexto Grfico.
es una lista o tupla de pares de coordenadas en tuplas, por ejemplo [ (0,0), (2,5), (3,7), (4,11) ], que representa la lista de los puntos que se deben dibujar.
points drawable.draw_segments(gc, segs) # dibuja segmentos gc
es el Contexto Grfico.
es una lista o tupla de tuplas que representan las coordenadas de los puntos iniciales y finales de los segmentos que se quiere dibujar, tal como: [ (0,0, 1,5), (2,5, 1,7), (3,7, 1,11), (4,11, 1,13) ] .
segs
es el Contexto Grfico.
es una lista o tupla de pares de coordenadas en tuplas, como por ejemplo [ (0,0), (2,5), (3,7), (4,11) ], que representa la lista de de los puntos que se van a conectar con lneas.
points 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 x
es el Contexto Grfico.
e y son las coordenadas de la esquina superior izquierda del rectngulo que bordea la imagen.
width dith
Para el mtodo draw_rgb_image() , rgb_buf es el conjunto de los datos de la imagen RGB codificado en una cadena como una secuencia de tripletes de pxeles RGB de 8 bits. Para el mtododraw_rgb_32_image() , buf es el conjunto de los datos de la imagen RGB codificado en una cadena como una secuencia de tripletes 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 imagen codificado en una cadena como pxeles de 8 bits. es el nmero de caracteres desde el principio de una fila hasta el principio de la siguiente en la imagen. rowstride normalmente tiene un valor por defecto de 3 * ancho (width) en el mtododraw_rgb_image() ; 4 * ancho (width)para el mtodo draw_rgb_32_image(); y el ancho (width) para el mtodo draw_gray_image() . Si rowstride es 0 entonces la linea se repetir un nmero de veces igual al alto.
rowstride
# Nunca se hace mezclado # Se hace mezclado cuando se usen 8 bits por pxel
El programa de ejemplo [Link] muestra el uso de la mayora de los mtodos de un rea de dibujo (DrawingArea). Tambin inserta el rea de dibujo (DrawingArea) en el interior de una ventana con barras de desplazamiento (ScrolledWindow) y aade los controles de desplazamiento horizontal y vertical (Ruler). La figura Figura 12.1, Ejemplo de rea de Dibujo muestra la ventana resultante: Figura 12.1. Ejemplo de rea de Dibujo
8 import operator 9 import time 10 import string 11 12 class DrawingAreaExample: 13 def __init__(self): 14 window = [Link](gtk.WINDOW_TOPLEVEL) 15 window.set_title("Ejemplo de rea de Dibujo") 16 [Link]("destroy", lambda w: gtk.main_quit()) 17 [Link] = [Link]() 18 [Link].set_size_request(400, 300) 19 [Link] = [Link].create_pango_layout("") 20 [Link] = [Link]() 21 [Link].add_with_viewport([Link]) 22 [Link] = [Link](2,2) 23 [Link] = [Link]() 24 [Link] = [Link]() 25 [Link].set_range(0, 400, 0, 400) 26 [Link].set_range(0, 300, 0, 300) 27 [Link]([Link], 1, 2, 0, 1, yoptions=0) 28 [Link]([Link], 0, 1, 1, 2, xoptions=0) 29 [Link]([Link], 1, 2, 1, 2) 30 [Link]([Link]) 31 [Link].set_events([Link].POINTER_MOTION_MASK | 32 [Link].POINTER_MOTION_HINT_MASK ) 33 [Link]("expose-event", self.area_expose_cb) 34 def motion_notify(ruler, event): 35 return [Link]("motion_notify_event", event) 36 [Link].connect_object("motion_notify_event", motion_notify, 37 [Link]) 38 [Link].connect_object("motion_notify_event", motion_notify, 39 [Link]) 40 [Link] = [Link].get_hadjustment() 41 [Link] = [Link].get_vadjustment() 42 def val_cb(adj, ruler, horiz): 43 if horiz: 44 span = [Link].get_allocation()[3] 45 else: 46 span = [Link].get_allocation()[2] 47 l,u,p,m = ruler.get_range() 48 v = [Link] 49 ruler.set_range(v, v+span, p, m) 50 while gtk.events_pending(): 51 gtk.main_iteration() 52 [Link]('value-changed', val_cb, [Link], True) 53 [Link]('value-changed', val_cb, [Link], False) 54 def size_allocate_cb(wid, allocation): 55 x, y, w, h = allocation 56 l,u,p,m = [Link].get_range() 57 m = max(m, w)
58 [Link].set_range(l, l+w, p, m) 59 l,u,p,m = [Link].get_range() 60 m = max(m, h) 61 [Link].set_range(l, l+h, p, m) 62 [Link]('size-allocate', size_allocate_cb) 63 [Link]() 64 [Link]() 65 [Link]() 66 [Link]() 67 [Link]() 68 [Link]() 69 70 def area_expose_cb(self, area, event): 71 [Link] = [Link].get_style() 72 [Link] = [Link].fg_gc[gtk.STATE_NORMAL] 73 self.draw_point(10,10) 74 self.draw_points(110, 10) 75 self.draw_line(210, 10) 76 self.draw_lines(310, 10) 77 self.draw_segments(10, 100) 78 self.draw_rectangles(110, 100) 79 self.draw_arcs(210, 100) 80 self.draw_pixmap(310, 100) 81 self.draw_polygon(10, 200) 82 self.draw_rgb_image(110, 200) 83 return [Link] 84 85 def draw_point(self, x, y): 86 [Link].draw_point([Link], x+30, y+30) 87 [Link].set_text("Punto") 88 [Link].draw_layout([Link], x+5, y+50, [Link]) 89 return 90 91 def draw_points(self, x, y): 92 points = [(x+10,y+10), (x+10,y), (x+40,y+30), 93 (x+30,y+10), (x+50,y+10)] 94 [Link].draw_points([Link], points) 95 [Link].set_text("Puntos") 96 [Link].draw_layout([Link], x+5, y+50, [Link]) 97 return 98 99 def draw_line(self, x, y): 100 [Link].draw_line([Link], x+10, y+10, x+20, y+30) 101 [Link].set_text("Lnea") 102 [Link].draw_layout([Link], x+5, y+50, [Link]) 103 return 104 105 def draw_lines(self, x, y): 106 points = [(x+10,y+10), (x+10,y), (x+40,y+30), 107 (x+30,y+10), (x+50,y+10)]
108 [Link].draw_lines([Link], points) 109 [Link].set_text("Lneas") 110 [Link].draw_layout([Link], x+5, y+50, [Link]) 111 return 112 113 def draw_segments(self, x, y): 114 segments = ((x+20,y+10, x+20,y+70), (x+60,y+10, x+60,y+70), 115 (x+10,y+30 , x+70,y+30), (x+10, y+50 , x+70, y+50)) 116 [Link].draw_segments([Link], segments) 117 [Link].set_text("Segmentos") 118 [Link].draw_layout([Link], x+5, y+80, [Link]) 119 return 120 121 def draw_rectangles(self, x, y): 122 [Link].draw_rectangle([Link], [Link], x, y, 80, 70) 123 [Link].draw_rectangle([Link], [Link], x+10, y+10, 20, 20) 124 [Link].draw_rectangle([Link], [Link], x+50, y+10, 20, 20) 125 [Link].draw_rectangle([Link], [Link], x+20, y+50, 40, 10) 126 [Link].set_text("Rectngulos") 127 [Link].draw_layout([Link], x+5, y+80, [Link]) 128 return 129 130 def draw_arcs(self, x, y): 131 [Link].draw_arc([Link], [Link], x+10, y, 70, 70, 132 0, 360*64) 133 [Link].draw_arc([Link], [Link], x+30, y+20, 10, 10, 134 0, 360*64) 135 [Link].draw_arc([Link], [Link], x+50, y+20, 10, 10, 136 0, 360*64) 137 [Link].draw_arc([Link], [Link], x+30, y+10, 30, 50, 138 210*64, 120*64) 139 [Link].set_text("Arcos") 140 [Link].draw_layout([Link], x+5, y+80, [Link]) 141 return 142 143 def draw_pixmap(self, x, y): 144 pixmap, mask = [Link].pixmap_create_from_xpm( 145 [Link], [Link][gtk.STATE_NORMAL], "[Link]") 146 147 [Link].draw_drawable([Link], pixmap, 0, 0,
x+15, y+25, 148 -1, -1) 149 [Link].set_text("Mapa de Pxeles") 150 [Link].draw_layout([Link], x+5, y+80, [Link]) 151 return 152 153 def draw_polygon(self, x, y): 154 points = [(x+10,y+60), (x+10,y+20), (x+40,y+70), 155 (x+30,y+30), (x+50,y+40)] 156 [Link].draw_polygon([Link], [Link], points) 157 [Link].set_text("Polgono") 158 [Link].draw_layout([Link], x+5, y+80, [Link]) 159 return 160 161 def draw_rgb_image(self, x, y): 162 b = 80*3*80*['\0'] 163 for i in range(80): 164 for j in range(80): 165 b[3*80*i+3*j] = chr(255-3*i) 166 b[3*80*i+3*j+1] = chr(255-3*abs(i-j)) 167 b[3*80*i+3*j+2] = chr(255-3*j) 168 buff = [Link](b, '') 169 [Link].draw_rgb_image([Link], x, y, 80, 80, 170 [Link].RGB_DITHER_NONE, buff, 80*3) 171 [Link].set_text("Imagen RGB") 172 [Link].draw_layout([Link], x+5, y+80, [Link]) 173 return 174 175 def main(): 176 [Link]() 177 return 0 178 179 if __name__ == "__main__": 180 DrawingAreaExample() 181 main()