1<?xml version="1.0" encoding="utf-8"?>
2<page xmlns="http://projectmallard.org/1.0/" xmlns:its="http://www.w3.org/2005/11/its" type="topic" id="image-viewer.c" xml:lang="es">
3
4  <info>
5    <title type="text">Visor de imágenes (C)</title>
6    <link type="guide" xref="c#examples"/>
7
8    <desc>Algo más que una sencilla aplicación «Hola mundo» en GTK.</desc>
9
10    <revision pkgversion="0.1" version="0.1" date="2011-03-18" status="review"/>
11    <credit type="author">
12      <name>Proyecto de documentación de GNOME</name>
13      <email its:translate="no">gnome-doc-list@gnome.org</email>
14    </credit>
15    <credit type="author">
16      <name>Johannes Schmid</name>
17      <email its:translate="no">jhs@gnome.org</email>
18    </credit>
19    <credit type="editor">
20      <name>Marta Maria Casetti</name>
21      <email its:translate="no">mmcasetti@gmail.com</email>
22      <years>2013</years>
23    </credit>
24
25    <mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
26      <mal:name>Daniel Mustieles</mal:name>
27      <mal:email>daniel.mustieles@gmail.com</mal:email>
28      <mal:years>2011 - 2020</mal:years>
29    </mal:credit>
30
31    <mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
32      <mal:name>Nicolás Satragno</mal:name>
33      <mal:email>nsatragno@gmail.com</mal:email>
34      <mal:years>2012 - 2013</mal:years>
35    </mal:credit>
36
37    <mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
38      <mal:name>Jorge González</mal:name>
39      <mal:email>jorgegonz@svn.gnome.org</mal:email>
40      <mal:years>2011</mal:years>
41    </mal:credit>
42  </info>
43
44<title>Visor de imágenes</title>
45
46<synopsis>
47  <p>En este tutorial aprenderá:</p>
48  <list>
49    <item><p>Algunos conceptos básicos de programación en C/GObject</p></item>
50    <item><p>Cómo escribir una aplicación GTK en C</p></item>
51  </list>
52</synopsis>
53
54<media type="image" mime="image/png" src="media/image-viewer.png"/>
55
56<section id="anjuta">
57  <title>Crear un proyecto en Anjuta</title>
58  <p>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.</p>
59  <steps>
60    <item>
61    <p>Inicie Anjuta y pulse <guiseq><gui>Archivo</gui><gui>Nuevo</gui><gui>Proyecto</gui></guiseq> para abrir el asistente de proyectos.</p>
62    </item>
63    <item>
64    <p>Seleccione <gui>GTK+ (simple)</gui> en la pestaña <gui>C</gui>, pulse <gui>Continuar</gui>, y rellene los detalles en las siguientes páginas. Use <file>visor-imagenes</file> como nombre del proyecto y de la carpeta.</p>
65   	</item>
66    <item>
67    <p>Asegúrese de que <gui>Usar GtkBuilder para la interfaz del usuario</gui> está desactivado, ya que, en este tutorial, la IU se creará manualmente. Revise el tutorial del <link xref="guitar-tuner.c">afinador de guitarra</link> si quiere aprender a usar el constructor de interfaces.</p>
68    </item>
69    <item>
70    <p>Pulse <gui>Aplicar</gui> y se creará el proyecto. Abra <file>src/main.c</file> desde las pestañas <gui>Proyecto</gui> o <gui>Archivo</gui>. Debería ver algo de código que comience con las líneas:</p>
71    <code mime="text/x-csrc">
72#include &lt;config.h&gt;
73#include &lt;gtk/gtk.h&gt;</code>
74    </item>
75  </steps>
76</section>
77
78<section id="build">
79  <title>Construir el código por primera vez</title>
80  <p>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:</p>
81
82  <list>
83  <item>
84    <p>Las tres líneas <code>#include</code> en la parte superior incluyen las bibliotecas <code>config</code> (útil para definiciones de construcción de autoconf), <code>gtk</code> (interfaz de usuario) y <code>gi18n</code> (internacionalización). Las funciones de estas bibliotecas se usan en el resto del código.</p>
85   </item>
86   <item>
87    <p>La función <code>create_window</code> crea una ventana (vacía) nueva y conecta una señal para salir de la aplicación cuando se cierra esa ventana.</p>
88    <p>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 <code>destroy</code> (y se sale de la aplicación) cuando cierra la ventana.</p>
89   </item>
90   <item>
91    <p>La función <code>main</code> 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 <code>gtk_main</code> 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).</p>
92   </item>
93   <item>
94    <p>La definición condicional <code>ENABLE_NLS</code> configura <code>gettext</code>, 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.</p>
95   </item>
96  </list>
97
98  <p>Este código está listo para usarse, por lo que puede compilarlo pulsando <guiseq><gui>Construir</gui><gui>Construir proyecto</gui></guiseq> (o pulsando <keyseq><key>Mayús</key><key>F7</key></keyseq>).</p>
99  <p>Pulse <gui>Ejecutar</gui> en la siguiente ventana que aparece para configurar una construcción de depuración. Esto sólo necesita hacer una vez para la primera construcción.</p>
100</section>
101
102<section id="ui">
103<title>Crear la interfaz de usuario</title>
104<p>Ahora se dará vida a la ventana vacía. GTK+ organiza la interfaz de usuario con varios <code>GtkContainer</code> que pueden contener otros widgets e incluso otros contenedores. Aquí se usará el contenedor más sencillo disponible, una <code>GtkBox</code>:</p>
105<code mime="text/x-csrc">
106static GtkWidget*
107create_window (void)
108{
109	GtkWidget *window;
110	GtkWidget *button;
111	GtkWidget *image;
112	GtkWidget *box;
113
114	/* Set up the UI */
115	window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
116	gtk_window_set_title (GTK_WINDOW (window), "image-viewer-c");
117
118	box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
119	button = gtk_button_new_with_label (_("Open image"));
120	image = gtk_image_new ();
121
122	gtk_box_pack_start (GTK_BOX (box), image, TRUE, TRUE, 0);
123	gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
124
125	gtk_container_add (GTK_CONTAINER (window), box);
126
127	/* Connect signals */
128
129	/* Show open dialog when opening a file */
130	g_signal_connect (button, "clicked", G_CALLBACK (on_open_image), image);
131
132	/* Exit when the window is closed */
133	g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
134
135	return window;
136}
137</code>
138  <steps>
139    <item>
140    <p>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 <code>GTK_BOX</code> se usan para comprobaciones de tipos dinámicos y conversiones de tipos necesarias, ya que C no soporta orientación a objetos.</p>
141    </item>
142    <item>
143    <p>Las llamadas a <code>gtk_box_pack_start</code> 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.</p>
144    </item>
145    <item>
146    <p>Se debe definir qué sucede cuando el usuario pulsa el botón. GTK+ usa el concepto de <em>señales</em>. Cuando se pulsa el botón, emite la señal <em>clicked</em>, que se puede conectar a alguna acción. Esto se ha hecho usando el método <code>g_signal_connect</code>, que indica a GTK+ que llame a la función <code>on_image_open</code> cuando se pulsa el botón y que pase la imagen como un argumento adicional a la función. El <em>retorno de la llamada</em> se definirá en la siguiente sección.</p>
147    </item>
148    <item>
149    <p>La última <code>g_signal_connect()</code> se asegura de que la aplicación finaliza al cerrar la ventana.</p>
150    </item>
151    <item>
152    <p>Como último paso, asegúrese de reemplazar la llamada <code>gtk_widget_show</code>, en la función <code>main()</code>, por <code>gtk_widget_show_all()</code>, para mostrar todos los widgets que contiene la ventana.</p>
153    </item>
154  </steps>
155</section>
156
157<section id="image">
158<title>Mostrar la imagen</title>
159<p>Ahora se definirá el gestor de la señal para la señal <em>clicked</em> en el botón mencionado anteriormente. Añada este código antes del método <code>create_window()</code>.</p>
160<code mime="text/x-csrc">
161static void
162on_open_image (GtkButton* button, gpointer user_data)
163{
164	GtkWidget *image = GTK_WIDGET (user_data);
165	GtkWidget *toplevel = gtk_widget_get_toplevel (image);
166	GtkFileFilter *filter = gtk_file_filter_new ();
167	GtkWidget *dialog = gtk_file_chooser_dialog_new (_("Open image"),
168	                                                 GTK_WINDOW (toplevel),
169	                                                 GTK_FILE_CHOOSER_ACTION_OPEN,
170	                                                 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
171	                                                 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
172	                                                 NULL);
173
174	gtk_file_filter_add_pixbuf_formats (filter);
175	gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog),
176	                             filter);
177
178	switch (gtk_dialog_run (GTK_DIALOG (dialog)))
179	{
180		case GTK_RESPONSE_ACCEPT:
181		{
182			gchar *filename =
183				gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
184			gtk_image_set_from_file (GTK_IMAGE (image), filename);
185			break;
186		}
187		default:
188			break;
189	}
190	gtk_widget_destroy (dialog);
191}
192</code>
193  <p>Esto es un poco más complicado que todo lo que se ha intentado hasta ahora, así que se puede desglosar:</p>
194  <list>
195    <item><p>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 <em>clicked</em> no tiene ninguno. Lo siguiente es el argumento <code>user_data</code>, que es un puntero a los datos que se han pasado al conectar la señal. En este caso, es el objeto <code>GtkImage</code>.</p>
196    </item>
197    <item>
198      <p>La siguiente línea interesante es en la que se crea el diálogo para elegir el archivo usando <code>gtk_file_chooser_dialog_new</code>. 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.</p>
199    <p>Note que se está usando nombres de botones del <em>almacén</em> 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.</p>
200    </item>
201    <item>
202    <p>Las dos líneas siguientes restringen el diálogo <gui>Abrir</gui> para que sólo muestre archivos que se puedan abrir con «GtkImage». Primero se crea un objeto de filtro; luego se añaden los tipos de archivos soportados por el <code>GdkPixbuf</code> (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 <gui>Abrir</gui>.</p>
203    </item>
204    <item>
205    <p><code>gtk_dialog_run</code> muestra el diálogo <gui>Abrir</gui>. El diálogo esperará a que el usuario elija una imagen; cuando lo haga, <code>gtk_dialog_run</code> devolverá el valor <code>GTK_RESPONSE_ACCEPT</code> (devolvería <code>GTK_RESPONSE_CANCEL</code> si el usuario pulsara <gui>Cancelar</gui>). La sentencia <code>switch</code> comprueba esto.</p>
206    </item>
207    <item><p>Asumiendo que el usuario pulsó <gui>Abrir</gui>, la siguiente línea establece la propiedad <code>file</code> de la «GtkImage» con el nombre del archivo de imagen seleccionado por el usuario. La «GtkImage» cargará y mostrará la imagen elegida.</p>
208    </item>
209    <item>
210    <p>Al final de la línea de este método, se destruye el diálogo <gui>Abrir</gui> porque ya no se necesita más. El diálogo se oculta automáticamente al destruirlo.</p>
211    </item>
212  </list>
213</section>
214
215<section id="run">
216  <title>Construir y ejecutar la aplicación</title>
217  <p>Todo el código debería estar listo para ejecutarse. Pulse <guiseq><gui>Construir</gui><gui>Construir proyecto</gui></guiseq> para construir todo otra vez y pulse <guiseq><gui>Ejecutar</gui><gui>Ejecutar</gui></guiseq> para iniciar la aplicación.</p>
218  <p>Si todavía no lo ha hecho, elija la aplicación <file>Debug/src/visor-imagenes</file> en el diálogo que aparece. Finalmente, pulse <gui>Ejecutar</gui> y disfrute.</p>
219</section>
220
221<section id="impl">
222 <title>Implementación de referencia</title>
223 <p>Si tiene problemas con este tutorial, compare su código con este <link href="image-viewer/image-viewer.c">código de referencia</link>.</p>
224</section>
225
226<section id="next">
227  <title>Siguientes pasos</title>
228  <p>Aquí hay algunas ideas sobre cómo puede extender esta sencilla demostración:</p>
229  <list>
230   <item>
231   <p>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.</p>
232   </item>
233   <item>
234   <p>Aplicar filtros aleatorios y efectos a la imagen cuando se carga y permitir al usuario guardar la imagen modificada.</p>
235   <p><link href="http://www.gegl.org/api.html">GEGL</link> proporciona la capacidad de manipular imágenes de manera potente.</p>
236   </item>
237   <item>
238   <p>Permitir al usuario cargar imágenes desde recursos de red compartidos, escáneres y otras fuentes más complicadas.</p>
239   <p>Puede usar <link href="http://library.gnome.org/devel/gio/unstable/">GIO</link> para gestionar transferencias de archivos de red y similares, y <link href="http://library.gnome.org/devel/gnome-scan/unstable/">GNOME Scan</link> para gestionar el escaneado.</p>
240   </item>
241  </list>
242</section>
243
244
245</page>
246