Conceptos básicos de GTK+, Parte 2: Cómo utilizar GTK+
Este artículo supone que el lector está familiarizado con los conceptos básicos orientados a objetos, como clases, objetos, métodos y herencia. Aunque no es necesario saber programar en C, sí se requiere un conocimiento básico de la sintaxis del lenguaje C. Anatomía de una aplicación GTK+ en C. Considero que es mejor discutir el código usando ejemplos. Para este artículo, estoy usando una aplicación corta escrita en C llamada Hello World. Aunque es breve (y en gran medida inútil como aplicación), el código de esta aplicación demuestra algunos de los conceptos más interesantes que probablemente encontrará al programar en GTK+ (consulte el Listado 1).
Listado 1. Código GTK+ para la aplicación Hello World #include
Los widgets están organizados en una jerarquía que le permite a GTK+ saber cómo mostrarlos en la pantalla. Se conectan dos controladores de señales: uno para salir de la aplicación cuando el usuario cierra la ventana y otro para modificar el mensaje de bienvenida que se muestra cuando el usuario hace clic en el botón. Con la ventana mostrada en pantalla, la aplicación llama a gtk_main(), activando el bucle principal. El bucle principal se ejecuta hasta que el usuario cierra la ventana y llama a gtk_main_quit(). Inicialice las siguientes líneas para inicializar el soporte para GTK+ e i18n: Listado 2. Inicialice el soporte para GTK+ e i18n int main (int argc, char *argv[]) { GtkWidget* window, *button, *label, *vbox (GETTEXT_PACKAGE, LOCALEDIR; ) ; bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); gtk_init(&argc, &argv); (Si no es un programador de C, todo lo que necesita saber es que esta es la función donde comienza la ejecución de la aplicación). La siguiente línea contiene la declaración de varios punteros a los tipos GtkWidget. GTK+ es un conjunto de herramientas orientado a objetos. Por lo tanto, utiliza conceptos comunes orientados a objetos (como la herencia) para implementar diferentes componentes. Como lenguaje, C carece de soporte integrado para la orientación a objetos. GTK+ supera esta deficiencia mediante el uso de algunos trucos inteligentes y algunas propiedades útiles requeridas por el estándar C. En este esquema, los objetos están representados por punteros, y GtkWidget es el tipo básico en la jerarquía GTK+, llamado clase de la cual se derivan otras clases. Entonces, declaré la variable como GtkWidget*. Las siguientes tres líneas son las llamadas que se deben incluir al inicio del programa para obtener soporte para la interfaz de internacionalización. Tenga en cuenta que en una aplicación real, LOCALEDIR y GETEXT_PACKAGE no se declararían manualmente. El sistema de compilación manejará estas declaraciones. Sin embargo, en este sencillo ejemplo, la declaración ayuda a aclarar lo que se necesita. La última línea llama a gtk_init(). Antes de realizar otras llamadas GTK+, se debe llamar a esta función, pasándole los parámetros utilizados por el programa que llama. Si esta llamada falla, recibirá múltiples mensajes de error de varios subsistemas que no tienen posibilidad de inicializarse correctamente. Estas cuatro líneas de creación de un componente llaman a diferentes funciones _new() respectivamente: Listado 3. Llaman a diferentes funciones _new() window = gtk_window_new (GTK_WINDOW_TOPLEVEL button = gtk_button_new_with_label (_("Hello World")); )); vbox = gtk_vbox_new(FALSE, 0); Advertencia sobre TOPLEVEL Después de ver el parámetro TOPLEVEL de gtk_window_new, es posible que se pregunte si existen otros tipos de ventanas posibles. En realidad, lo hay. Sin embargo, la necesidad de tipos distintos de TOPLEVEL es rara. Además, para utilizar los diferentes tipos, debes tener un buen conocimiento de cómo interactúa GTK+ con el sistema de ventanas. Entonces, la regla es simple: use siempre el parámetro TOPLEVEL. Como puedes imaginar, estas funciones crean nuevos widgets. Entonces, son los constructores del objeto que representa el componente. En C++, los constructores están marcados de una manera especial y llamados con una sintaxis especial. Sin embargo, debido a que C no admite la orientación a objetos, no se diferencian de las funciones ordinarias. Solo el _new() agregado al final del nombre de la función indica que estas funciones son en realidad constructores.
La estipulación es que cada constructor en el espacio de nombres gtk_* devuelve un puntero a un GtkWidget. De esta forma, al declarar una variable de este tipo, el resultado de la llamada al constructor se puede asignar directamente a la variable correspondiente. Si observa los constructores individuales, puede ver que aceptan diferentes parámetros, correspondientes al tipo de widget que crean. Específicamente, gtk_window_new (GTK_WINDOW_TOPLEVEL) crea una nueva ventana TOPLEVEL; es decir, un widget que corresponde a lo que el usuario ve como una ventana, con una barra de título, un botón de cierre u otros elementos agregados por el sistema de ventanas. Las llamadas a los constructores de etiquetas y botones hacen el trabajo esperado. Sin embargo, tenga en cuenta los guiones bajos y corchetes (_()) alrededor de la cadena pasada al botón. Esta macro llama a la rutina gettext() y es esencial para las transiciones de interfaz. (Consulte Recursos para obtener más información sobre gettext). Gtk_vbox_new(FALSE, 0) de aspecto extraño Crea un cuadro vertical (VBox). Aunque este widget no corresponde a ningún píxel visible en la pantalla, juega un papel importante en el diseño de control de GTK+, como verá en breve. Determinar el diseño Estas tres líneas determinan el diseño del widget: gtk_container_add(GTK_CONTAINER (ventana), vbox); gtk_container_add(GTK_CONTAINER (vbox), etiqueta); gtk_container_add(GTK_CONTAINER (vbox), botón); de tipo llamada GtkContainer. Si observa la referencia de la interfaz de programación de aplicaciones (API), puede ver que GtkContainer hereda de GtkWidget y todos sus métodos aceptan un GtkContainer* como primer parámetro. Por tanto, GtkContainer* es la instancia del objeto sobre la que opera el método. Debido a que las variables son de tipo GtkWidget* y el compilador de C no admite la herencia orientada a objetos, es necesario convencer al compilador de que es seguro pasar estas variables a funciones que requieren un GtkContainer*. La macro GTK_CONTAINER() hace esto implementando una conversión de tipo a una versión de tipo seguro de GtkContainer. Seguridad de tipos significa que la macro verifica que la operación especificada se pueda realizar de forma segura en el tipo especificado antes de realizar la conversión de tipos. Se proporciona una advertencia si la macro no puede realizar la operación especificada. Debido a que GTK+ utiliza un modelo de diseño de caja, no es necesario especificar explícitamente dónde se debe colocar un widget en la pantalla. En su lugar, especifique en qué otro widget se coloca el widget. En la aplicación Hello World, cada llamada al método gtk_container_add() le dice a la aplicación que tome el primer argumento (o widget principal) y coloque el segundo argumento (o widget secundario) dentro del widget principal. El widget VBox utilizado en este ejemplo es un widget de diseño que organiza los widgets secundarios verticalmente. De esta manera, cuando colocas una etiqueta y un botón dentro de ella, el resultado es que el botón aparece debajo de la etiqueta. Esto es todo lo que hay que hacer. Si alguna vez ha cambiado el tamaño o el tamaño de los widgets manualmente usando el posicionamiento absoluto (el modelo utilizado en algunos kits de herramientas, como Win32), le alegrará saber que en GTK+ todo esto se hace automáticamente. Conexión de señales y bucle principal Después de crear y organizar sus widgets, es hora de agregarles algo de lógica. GTK+, como la mayoría de los kits de herramientas GUI, es un marco basado en eventos. Entonces, está organizado alrededor del bucle principal. El bucle principal opera en un ciclo continuo de verificación, asignación y suspensión. Cuando ocurre un evento, el objeto correspondiente a este evento envía una señal para notificar al bucle principal que el evento ha ocurrido. Luego, el bucle principal consulta su propia tabla de mapeo interna entre señales y controladores, también llamadas devoluciones de llamada, y llama al controlador para la señal especificada registrada en el objeto especificado.
En el código Hello World, el registro de devolución de llamada se ve así: Listado 4. Registro de devolución de llamada g_signal_connect(G_OBJECT (ventana), "delete-event", G_CALLBACK(cb_delete), NULL); G_CALLBACK(cb_button_click), etiqueta); tenga en cuenta que en GTK+, conéctese a las señales. La primera línea conecta la función cb_delete a la señal de evento de eliminación del objeto de ventana. De manera similar, la segunda línea conecta la función cb_button_click a la señal de clic del objeto de botón. Tenga en cuenta la etiqueta del cuarto parámetro en la segunda llamada de conexión. Más adelante verás cómo se utiliza esto en la función cb_button_click. Aquí está la función cb_delete, que sale de la aplicación cuando el usuario cierra la ventana: static gboolean cb_delete(GtkWidget *window, gpointer data) { gtk_main_quit(); return FALSE } modificador estático En C, la palabra clave estática se utiliza para vincular funciones; Internamente, esto significa que una función estática no es visible fuera del archivo fuente en el que está declarada. A menos que necesite utilizar devoluciones de llamada en más de un archivo, declare siempre las devoluciones de llamada utilizando la palabra clave estática. Con este enfoque, evita saturar el espacio de nombres limitado de nombres de funciones disponibles. Debido a que las funciones estáticas están confinadas a un archivo, los nombres de las funciones se pueden reutilizar de forma segura. Esta función acepta un GtkWidget* y un puntero de datos no especificado (gpointer es un tipo equivalente a void*), porque cada devolución de llamada de "delete-event" debe ajustarse a este prototipo. Sin embargo, esta función no requiere estos parámetros, por lo que se ignoran. Llama a la rutina gtk_main_quit() para salir del bucle principal. Además, la función devuelve un valor booleano porque el prototipo de devolución de llamada de la señal de eliminación de evento definida para GtkWidget especifica un valor de retorno booleano. Un valor booleano que determina la acción que realiza GTK+. Si devuelve VERDADERO, se considera que el evento ha sido manejado y no se llama al controlador predeterminado (que elimina el widget del sistema de ventanas). Esta función a veces es útil, por ejemplo, si desea mostrar un mensaje, solicitar datos que aún no se han guardado y evitar que la ventana se cierre según la respuesta del usuario. Aquí está la función cb_button_click, que modifica el mensaje de bienvenida que se muestra cuando el usuario hace clic en el botón: Listado 5. Función cb_button_click static void cb_button_click(GtkButton *button, gpointer data) { GtkWidget *label = GTK_WIDGET(data); NULL ); gtk_label_set_text(GTK_LABEL (label), select_greeting()); } Como puede ver, esta función es similar a la función cb_delete, excepto que no devuelve nada y acepta GtkButton* en lugar de GtkWidget. El código convierte datos en un puntero a GtkLabel. ¿Recuerda el parámetro de etiqueta en el registro de devolución de llamada? Ahora, cada vez que se llama a la devolución de llamada, el puntero de datos contendrá un puntero a esa etiqueta. El parámetro de datos se puede utilizar siempre que sea necesario pasar información adicional a la devolución de llamada. De manera similar, si necesita acceder al objeto que emite la señal, usa el primer parámetro, que es el botón en esta devolución de llamada específica.
Después de obtener el puntero a la etiqueta, el código usa la macro g_assert para determinar si la etiqueta es igual a NULL. La macro g_assert es una macro de utilidad de Glib (una biblioteca útil de tipos C y rutinas utilizadas por GTK+) que aborta el programa si se cumple la condición que se le pasa; en este caso, la condición es que la etiqueta sea igual a NULL. Debido a que una etiqueta igual a NULL significa que el programador cometió un error, esto garantiza que los errores se detecten antes de que el código entre en producción. Mostrar la ventana Después de conectar la devolución de llamada, la función gtk_widget_show_all() hace que la ventana, es decir, todos los widgets, se muestren en la pantalla (consulte la Figura 1). Figura 1. Aplicación Hello World, ejecutándose en polaco y japonés. Activación del bucle principal Una vez que todo está en su lugar y se muestra, la función gtk_main() activa el bucle principal. El bucle principal entra en un bucle infinito, esperando eventos y llamando devoluciones de llamada hasta que alguien cierra la ventana y llama a gtk_main_quit(). NOTA: Si aún tiene preguntas sobre el código, consulte el código fuente adjunto. Es exactamente el mismo código presentado en el artículo, pero cada línea incluye comentarios detallados. Compilación y ejecución Para compilar este programa, necesita un compilador de C y los archivos de desarrollo (encabezados y bibliotecas) para GTK+. Para obtener información sobre cómo obtener estos artículos, consulte Recursos. Después de instalar los archivos, descomprima el código fuente, ingrese al directorio donde se descomprimirá el código fuente y ejecute make: $ tar -xzf gtk_hello.tgz $ cd gtk_hello $ make Nota: si está ejecutando Microsoft?0?3 Windows ?0? 3. No ejecute make, abra Microsoft Visual Studio?6?4.NET y ejecute el proyecto "hello". Volver arriba GTK+ en otros lenguajes de programación GTK+ se puede utilizar en múltiples lenguajes de programación. Para hacer esto, necesita usar enlace. Un enlace es un paquete especial para un idioma determinado que expone la API GTK+ de una manera apropiada para ese idioma. Por ejemplo, convertí la aplicación Hello World a Python y C#. Para ejecutar GTK+ en estos lenguajes, necesita PyGTK y Gtk# además de Python y Mono/.NET respectivamente (ver Recursos). Hello World en PyGTK El Listado 6 muestra el código convertido a una aplicación Hello World en Python.
Listado 6. Aplicación Hola Mundo en PyGTK import pygtk pygtk.require('2.0') import gtk import saludos aleatorios = ["Hola Mundo", "Witaj ?wiecie", "世界に日は"] def elegir_saludo (saluda): return saluda[random.randint (0, len(saluda) - 1)] def cb_clicked(botón, etiqueta): label.set_text(elegir_saludo(saludos)) ventana = gtk.Window () vbox = gtk.VBox () botón = gtk .Button("Hola mundo") etiqueta = gtk.Label (elegir_saludo (saludos)) window.add(vbox) vbox.add(label) vbox.pack_start(button, False, False) window.connect("eliminar-evento" , lambda a,b: gtk.main_quit()) button.connect("clicked", cb_clicked, label) window.show_all() gtk.main() Debido al código Python compacto, esta versión de la aplicación es más pequeña que su La contraparte C es aún más corta. Aparte de eso, parece similar. Tenga en cuenta que el código se convirtió para utilizar modismos de Python, pero la API sigue siendo la misma. Hola Mundo en Gtk# El código de la aplicación Hola Mundo en Gtk# es un poco más largo que la versión C porque C# requiere declaraciones largas. Por lo tanto, no he incluido aquí el código fuente completo. El código fuente se incluye en la descarga adjunta. Aquí hay un vistazo rápido a la conversión conceptual principal de C a C#: clase GtkHello: Gtk.Window { En lugar de crear y configurar una nueva ventana, ahora coloque la clase Gtk.Window en una subclase y mueva todo el código de configuración al constructor. . Este enfoque no es específico de Gtk#. De hecho, este método se utiliza a menudo en programas C cuando se requieren varias copias de una ventana. Sin embargo, es tan fácil crear subclases en C# que hacerlo incluso para una instancia tiene sentido, especialmente si se considera que C# requiere que se declare al menos una clase. this.DeleteEvent += new DeleteEventHandler(DeleteCB); Los nombres también se han modificado ligeramente para ajustarse mejor a las convenciones de nomenclatura de C#. Listado 7. Señales GTK+ convertidas en conceptos idiomáticos de eventos de C# private void DeleteCB (object o, DeleteEventArgs args) { Application.Quit (); args.RetVal = true } Debido a la forma en que se construyen los eventos de C#, los controladores de eventos de eliminación El prototipo; es ligeramente diferente. En lugar de devolver verdadero desde la devolución de llamada, pasa el valor de retorno a través de args.RetVal. gtk_main() y gtk_main_quit() se reemplazan por Application.Run() y Application.Quit() respectivamente.
Volver arriba Herramientas útiles Al desarrollar con GTK+, existen varias herramientas que pueden hacerle la vida más fácil. Algunas de las herramientas más conocidas son Glade, Libglade y Devhelp. Glade y LibgladeGlade es un creador de interfaces: un programa que crea aplicaciones gráficamente sin tener que compilarlas manualmente a partir del código fuente. Más importante es el segundo componente: Libglade. Como sugiere el nombre, Libglade admite la lectura del formato de lenguaje de marcado extensible (XML) y Glade usa XML para guardar descripciones de la interfaz de usuario. Usando Libglade, puedes construir la interfaz de tu aplicación directamente a partir de esta descripción, sin ningún código. La Figura 2 muestra una aplicación Libglade simple que contiene varios componentes. Figura 2. Aplicación Libglade simple El Listado 8 muestra el código fuente completo de la aplicación Libglade que se muestra en la Figura 2. Listado 8. Código fuente para la aplicación Libglade #include
Finalmente, GTK+ se verá desde una perspectiva más amplia: como un proyecto con una comunidad activa que ayuda a crear aplicaciones que sirvan mejor a los usuarios. Volver arriba Descargar Descripción Nombre Tamaño Método de descarga Código fuente codeos-gtk2_hello.zip18KBHTTP Para obtener información sobre los métodos de descarga Recursos Para aprender, puede ver el texto original en inglés de este artículo en el sitio global de desarrolladorWorks. Lea todos los artículos de la serie "Conceptos básicos de GTK+" de DeveloperWorks. GNU Gettext es una biblioteca para traducción en tiempo de ejecución de aplicaciones. Libglade Reference Manual es una biblioteca para crear dinámicamente interfaces GTK+. Visite GTK+ para obtener más información sobre el kit de herramientas. La documentación completa de la API GTK+ es importante para todos los desarrolladores. La Guía oficial para desarrolladores de GNOME 2 de Matthias Warkus (No Starch Press, 2004) proporciona una introducción a GNOME 2, incluida la programación con GTK+. Visite la zona de código abierto de DeveloperWorks para obtener información detallada sobre procedimientos, herramientas y actualizaciones de proyectos que le ayudarán a desarrollar con tecnologías de código abierto y utilizarlas con productos IBM. Obtenga productos y tecnologías Obtenga Gtk#, los enlaces GTK+ para el entorno Microsoft .NET. Obtenga los archivos comprimidos del código fuente oficial para GTK+. Visite PyGTK, el sitio oficial de enlaces GTK+ para Python. Gazpacho es un editor mejorado para archivos de descripción de Glade UI, escrito en PyGTK. Devhelp es un navegador de documentación orientado al programador para GNOME. Consulte GNOME, un escritorio centrado en aplicaciones creado con GTK+. Pruebe Xfce, un escritorio rápido y fácil de usar también desarrollado con GTK+. Visite Gnomefiles y obtenga más de 1000 aplicaciones creadas con GTK+. Transforme su próximo proyecto de desarrollo de código abierto con el software de prueba de IBM, disponible como descarga o en DVD. Discusión Obtenga soporte y haga preguntas sobre el desarrollo de software con GTK+ en las listas de correo de GTK+. Únase a la comunidad de DeveloperWorks participando en los blogs de DeveloperWorks. Acerca del autor Maciej Katafiasz es un estudiante de posgrado en informática que ha estado trabajando con tecnologías de código abierto desde la escuela secundaria. Ha sido usuario del escritorio GNOME desde GNOME 1.0, y tan pronto como se lanzó la versión 2.0, se enamoró de él y descubrió que GTK+ le permitía desarrollar el escritorio de su elección. Cerrar [x] Ayuda para denunciar abuso Informar abuso ¡Gracias! Este contenido ha sido marcado para la atención de los administradores. Cerrar [x] Ayuda para denunciar abuso Informar abuso Error al enviar el informe de abuso. Inténtelo de nuevo más tarde. Cerrando [x]developerWorks: Inicie sesión en IBM ID: ¿Necesita una ID de IBM? ¿Olvidó su ID de IBM? Contraseña: ¿Olvidaste tu contraseña? Cambie su contraseña Manténgase conectado. Al hacer clic en Enviar, acepta los términos y condiciones de DeveloperWorks. Términos de uso Cuando inicia sesión por primera vez en DeveloperWorks, se crea un perfil para usted. La información que elija hacer pública en su perfil de desarrolladorWorks será visible públicamente para otros, pero puede modificar la visibilidad de esta información en cualquier momento. Su nombre (a menos que elija ocultarlos) y su apodo aparecerán con el contenido que publique en desarrolladorWorks. Toda la información enviada se mantiene segura. Cerrar [x] Seleccione su apodo: cuando inicie sesión por primera vez en desarrolladorWorks, se creará un perfil para usted y deberá especificar un apodo.
Su apodo aparecerá con el contenido que publique en desarrolladorWorks. La longitud del apodo puede tener entre 3 y 31 caracteres. Su apodo debe ser único dentro de la comunidad de DeveloperWorks y, por razones de privacidad, no puede ser su dirección de correo electrónico. Apodo: (Longitud entre 3 y 31 caracteres) Al hacer clic en Enviar, acepta los términos y condiciones de DeveloperWorks. Términos de uso. Toda la información enviada se mantiene segura. Califica este artículo y comenta volver arriba