En este tutorial aprenderá:
Algunos conceptos básicos de programación en C/GObject
Cómo escribir una aplicación GTK en C
Antes de empezar a programar, deberá configurar un proyecto nuevo en Anjuta. Esto creará todos los archivos que necesite para construir y ejecutar el código más adelante. También es útil para mantener todo ordenado.
Inicie Anjuta y pulse
Seleccione
Asegúrese de que
Pulse
#include <config.h>
#include <gtk/gtk.h>
C es un lenguaje más detallado, por lo que no se sorprenda de que el archivo contiene un gran cantidad de código. La mayor parte es código de plantilla. Carga una ventana (vacía) y se muestra. A continuación se ofrecen más detalles; omita esta lista si entiende los conceptos básicos:
Las tres líneas #include
en la parte superior incluyen las bibliotecas config
(útil para definiciones de construcción de autoconf), gtk
(interfaz de usuario) y gi18n
(internacionalización). Las funciones de estas bibliotecas se usan en el resto del código.
La función create_window
crea una ventana (vacía) nueva y conecta una señal para salir de la aplicación cuando se cierra esa ventana.
Conectar señales es como se define lo que pasa cuando pulsa un botón, o cuando ocurre algún otro evento. Aquí, se llama a la función destroy
(y se sale de la aplicación) cuando cierra la ventana.
La función main
se ejecuta de manera predeterminada cuando inicia una aplicación en C. Llama a unas pocas funciones que configuran y ejecutan la aplicación. La función gtk_main
inicia el bucle principal de GTK+, que ejecuta la interfaz de usuario y comienza a escuchar eventos (como pulsaciones del ratón y del teclado).
La definición condicional ENABLE_NLS
configura gettext
, que es un entorno de trabajo para traducir aplicaciones. Estas funciones especifican cómo deben manejar su aplicación las herramientas de traducción cuando las ejecuta.
Este código está listo para usarse, por lo que puede compilarlo pulsando
Pulse
Ahora se dará vida a la ventana vacía. GTK+ organiza la interfaz de usuario con varios GtkContainer
que pueden contener otros widgets e incluso otros contenedores. Aquí se usará el contenedor más sencillo disponible, una GtkBox
:
static GtkWidget*
create_window (void)
{
GtkWidget *window;
GtkWidget *button;
GtkWidget *image;
GtkWidget *box;
/* Set up the UI */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "image-viewer-c");
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
button = gtk_button_new_with_label (_("Open image"));
image = gtk_image_new ();
gtk_box_pack_start (GTK_BOX (box), image, TRUE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
gtk_container_add (GTK_CONTAINER (window), box);
/* Connect signals */
/* Show open dialog when opening a file */
g_signal_connect (button, "clicked", G_CALLBACK (on_open_image), image);
/* Exit when the window is closed */
g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
return window;
}
La primera línea crea los widgets que se quieren usar: un botón para abrir una imagen, el widget para ver la imagen y la caja que se usará como contenedor. Las macros como GTK_BOX
se usan para comprobaciones de tipos dinámicos y conversiones de tipos necesarias, ya que C no soporta orientación a objetos.
Las llamadas a gtk_box_pack_start
añaden los dos widgets a la caja y definen su comportamiento. La imagen se expandirá en cualquier espacio disponible, mientras que el botón será tan grande como se necesite. Se dará cuenta de que no se establecen tamaños explícitos de los widgets. Generalmente, en GTK+ no se necesita ya que hace que sea mucho más sencillo tener una distribución que se ve bien con diferentes tamaños de la ventana. A continuación, se añade la caja a la ventana.
Se debe definir qué sucede cuando el usuario pulsa el botón. GTK+ usa el concepto de señales. Cuando se pulsa el botón, emite la señal clicked, que se puede conectar a alguna acción. Esto se ha hecho usando el método g_signal_connect
, que indica a GTK+ que llame a la función on_image_open
cuando se pulsa el botón y que pase la imagen como un argumento adicional a la función. El retorno de la llamada se definirá en la siguiente sección.
La última g_signal_connect()
se asegura de que la aplicación finaliza al cerrar la ventana.
Como último paso, asegúrese de reemplazar la llamada gtk_widget_show
, en la función main()
, por gtk_widget_show_all()
, para mostrar todos los widgets que contiene la ventana.
Ahora se definirá el manejador de la señal para la señal clicked en el botón mencionado anteriormente. Añada este código antes del método create_window()
.
static void
on_open_image (GtkButton* button, gpointer user_data)
{
GtkWidget *image = GTK_WIDGET (user_data);
GtkWidget *toplevel = gtk_widget_get_toplevel (image);
GtkFileFilter *filter = gtk_file_filter_new ();
GtkWidget *dialog = gtk_file_chooser_dialog_new (_("Open image"),
GTK_WINDOW (toplevel),
GTK_FILE_CHOOSER_ACTION_OPEN,
GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
NULL);
gtk_file_filter_add_pixbuf_formats (filter);
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog),
filter);
switch (gtk_dialog_run (GTK_DIALOG (dialog)))
{
case GTK_RESPONSE_ACCEPT:
{
gchar *filename =
gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
gtk_image_set_from_file (GTK_IMAGE (image), filename);
break;
}
default:
break;
}
gtk_widget_destroy (dialog);
}
Esto es un poco más complicado que todo lo que se ha intentado hasta ahora, así que se puede desglosar:
El primer argumento de la señal es siempre el widget que envía la señal. Algunas veces se añaden otros argumentos relativos a la señal, pero clicked no tiene ninguno. Lo siguiente es el argumento user_data
, que es un puntero a los datos que se han pasado al conectar la señal. En este caso, es el objeto GtkImage
.
La siguiente línea interesante es en la que se crea el diálogo para elegir el archivo usando gtk_file_chooser_dialog_new
. La función toma el título del diálogo, la ventana padre del diálogo y varias opciones como el número de botones y sus valores correspondientes.
Note que se está usando nombres de botones del almacén de GTK, en lugar de escribir manualmente «Cancelar» o «Abrir». La ventaja de usar nombres del almacén es que las etiquetas de los botones ya estarán traducidas en el idioma del usuario.
Las dos líneas siguientes restringen el diálogo GdkPixbuf
(que incluye la mayoría de los formatos de imagen como PNG y JPEG) al filtro. Por último, se establece que este filtro sea el filtro del diálogo
gtk_dialog_run
muestra el diálogo gtk_dialog_run
devolverá el valor GTK_RESPONSE_ACCEPT
(devolvería GTK_RESPONSE_CANCEL
si el usuario pulsara switch
comprueba esto.
Asumiendo que el usuario pulsó file
de la «GtkImage» con el nombre del archivo de imagen seleccionado por el usuario. La «GtkImage» cargará y mostrará la imagen elegida.
Al final de la línea de este método, se destruye el diálogo
Todo el código debería estar listo para ejecutarse. Pulse
Si todavía no lo ha hecho, elija la aplicación
Si tiene problemas con este tutorial, compare su código con este código de referencia.
Aquí hay algunas ideas sobre cómo puede extender esta sencilla demostración:
Haga que el usuario selecciona una carpeta en vez de un archivo, y proporcione controles para moverse por todas las imágenes de una carpeta.
Aplicar filtros aleatorios y efectos a la imagen cuando se carga y permitir al usuario guardar la imagen modificada.
GEGL proporciona la capacidad de manipular imágenes de manera potente.
Permitir al usuario cargar imágenes desde recursos de red compartidos, escáneres y otras fuentes más complicadas.
Puede usar GIO para gestionar transferencias de archivos de red y similares, y GNOME Scan para gestionar el escaneado.