Programación en el entorno GNOME |
---|
Tabla de contenidos
GTK+ es la librería gráfica (toolkit) sobre la que se sustenta todo el interfaz gráfico de GNOME. Es una librería que contiene todo lo necesario para el desarrollo de interfaces gráficas, permitiendo la posibilidad de crear todo tipo de widgets, desde los más básicos, como botones, etiquetas, cajas de texto, hasta cosas más complejas como selectores de ficheros, colores, fuentes, cajas de texto multilínea con soporte para todo tipo de efectos sobre el texto, etc.
En términos de ingeniería del software, un widget es un componente software visible y personalizable. Visible porque está pensado para ser usado en los interfaces gráficos de los programas, y personalizable porque el programador puede cambiar muchas de sus propiedades. De esta forma se logra una gran reutilización del software, un objetivo prioritario en ingeniería del software. Los widgtes se combinan para construir los interfaces gráficos de usuario. El programador los adapta según sus necesidades sin tener que escribir más código que el necesario para definir los nuevos valores de las propiedades de los widgets.
La librería GTK+ sigue el modelo de programación orientado a objetos. La jerarquía de objetos comienza en GObject de la librería Glib del que hereda GtkObject. Todos los widgets heredan de la clase de objetos GtkWidget, que a su vez hereda directamente de GtkObject. La clase GtkWidget contiene las propiedades comunes a todos los widgets; cada widget particular le añade sus propias propiedades.
Los widgets se definen mediante punteros a una estructura GtkWidget. En GTK+, los widgets presentan una relación padre/hijo entre sí. Las aplicaciones suelen tener un widget "ventana" de nivel superior que no tiene padre, pero aparte de él, todos los widgets que se usen en una aplicación deberán tener un widget padre. Al widget padre se le denomina contenedor. El proceso de creacción de un widget consta de dos pasos: el de creación propiamente dicho y el de visualización. La función de creación de un widget tiene un nombre que sigue el esquema gtk_nombre_new donde "nombre" debe sustituirse por el nombre del widget que se desea crear. La función gtk_widget_show hará visible el widget creado.
La función de creación de un widget gtk_nombre_new devuelve un puntero a un objeto de tipo GtkWidget y no un puntero a un widget del tipo creado. Por ejemplo, la función gtk_button_new devuelve un puntero a un objeto de GtkWidget y no una referencia a un botón. Esta referencia puede convertirse a una referencia a un objeto GtkButton mediante la macro GTK_BUTTON, si se desea utilizar en lugares donde se requieran objetos botones. Aunque sería posible pasar en esos casos la referencia genérica, el compilador se quejará si se hace así posibilitando un control de tipos de objetos. Todo widget tiene una macro de conversión de una referencia genérica a una referencia al tipo propio. Eso sí, la macro únicamente funcionará correctamente si el widget referenciado fue creado con la función de creación del tipo apropiado, lo que incluye el propio tipo del widget o un descendiente.
El interfaz gráfico de una aplicación se construye combinando diferentes widgets (ventanas, cuadros combinados, cuadros de texto, botones, ...) y se establecen diversas retrollamadas (callbacks) para estos widgets, de esta forma se obtiene el procesamiento requerido por el programa a medida que se producen ciertas señales que a su vez provocan las retrollamadas. Las señales se producen por diversos sucesos como oprimir el boton de un ratón que se encuentra sobre un widget botón, pasar el cursor por encima de un widget u oprimir una tecla.
GTK+ utiliza GDK para visualizar los widgets. GDK es una interfaz de programación (API) de aplicaciones que se situa por encima de la API gráfica nativa como Xlib o Win32. De esta forma portando GDK pueden utilizarse las aplicaciones construidas con GTK+ en otras plataformas.
El conjunto de "widgets" básicos incluye todos los que nos podríamos esperar de una librería como GTK, es decir, botones, etiquetas, marcos, barras de tareas y de menús, ventanas, cajas de diálogo, etc. Todos y cada uno de ellos, implementado como una clase (es decir, un objeto derivado de GObject, aunque indirectamente, pues todos los "widgets" están basados en la clase GtkWidget), permiten una personalización bastante amplia, lo cual nos permite desarrollar nuestros interfaces de usuario al más mínimo detalle.
Cada clase en GTK ofrece una función _new que nos permite crear una instancia de esa clase. Así, por ejemplo, tenemos las siguientes funciones:
GtkWidget *gtk_list_new (void); GtkWidget *gtk_toolbar_new (GtkOrientation orientation, GtkToolbarStyle style); GtkWidget *gtk_button_new (void); GtkWidget *gtk_button_new_with_label (const gchar *label); ...
Una vez que hemos creado una instancia de una clase GTK, podemos alterar su aspecto/comportamiento mediante las funciones disponibles para esa clase, así como las funciones disponibles en las clases de las que, directa o indirectamente, hereda la primera clase.
Esto último, tratar a una clase como otra, se consigue mediante macros de conversión. Así, por ejemplo, la clase GtkCheckButton, que deriva de GtkToggleButton puede ser tratada de la siguiente forma:
GtkWidget *check_button; check_button = gtk_check_button_new_with_label("un check button"); ... if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(check_button))) { /* el "check button" está activado */ ... }
Como se ve en este ejemplo, primero creamos una instancia de la clase GtkCheckButton mediante la función gtk_check_button_new_with_label, para luego comprobar si está activo mediante la función gtk_toggle_button_get_active. Esto se debe a que, como coméntabamos anteriormente, la clase GtkCheckButton hereda de la clase GtkToggleButton y, por tanto, podemos usar todas las funciones de esta última clase con cualquier objeto de la clase GtkCheckButton.
Este mecanismo de herencia es el equivalente a la herencia en los lenguajes orientados a objetos, en los que no es necesaria la conversión de los objetos, sino que es posible acceder a los métodos/propiedades del objeto directamente. Así, para entenderlo mejor, veamos el equivalente, en C++, del ejemplo anterior.
Gtk::CheckButton check_button = new Gtk::CheckButton("un check button"); ... if (check_button->get_active()) { ... }
<< Referencias | Bucle de ejecución y eventos >> |