Blob Blame History Raw
<?xml version="1.0" encoding="utf-8"?>
<page xmlns="http://projectmallard.org/1.0/" xmlns:its="http://www.w3.org/2005/11/its" type="topic" id="image-viewer.vala" xml:lang="es">

  <info>
  <title type="text">Visor de imágenes (Vala)</title>
    <link type="guide" xref="vala#examples"/>

    <desc>Algo más que una sencilla aplicación «Hola mundo» en GTK+.</desc>

    <revision pkgversion="0.1" version="0.1" date="2011-03-18" status="review"/>
    <credit type="author">
      <name>Proyecto de documentación de GNOME</name>
      <email its:translate="no">gnome-doc-list@gnome.org</email>
    </credit>
    <credit type="author">
      <name>Johannes Schmid</name>
      <email its:translate="no">jhs@gnome.org</email>
    </credit>
    <credit type="author">
      <name>Philip Chimento</name>
      <email its:translate="no">philip.chimento@gmail.com</email>
    </credit>
    <credit type="editor">
     <name>Tiffany Antopolski</name>
     <email its:translate="no">tiffany.antopolski@gmail.com</email>
    </credit>
  <credit type="editor">
    <name>Marta Maria Casetti</name>
    <email its:translate="no">mmcasetti@gmail.com</email>
    <years>2013</years>
  </credit>
  
    <mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
      <mal:name>Daniel Mustieles</mal:name>
      <mal:email>daniel.mustieles@gmail.com</mal:email>
      <mal:years>2011 - 2017</mal:years>
    </mal:credit>
  
    <mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
      <mal:name>Nicolás Satragno</mal:name>
      <mal:email>nsatragno@gmail.com</mal:email>
      <mal:years>2012 - 2013</mal:years>
    </mal:credit>
  
    <mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
      <mal:name>Jorge González</mal:name>
      <mal:email>jorgegonz@svn.gnome.org</mal:email>
      <mal:years>2011</mal:years>
    </mal:credit>
  </info>

<title>Visor de imágenes</title>
<synopsis>
  <p>En este tutorial se va a crear un programa que abre un archivo de imagen y lo muestra. Aprenderá a:</p>
  <list type="numbered">
    <item><p>Cómo configurar un proyecto básico usando el <link xref="getting-ready">EID Anjuta</link>.</p></item>
    <item><p>Cómo escribir una <link href="http://developer.gnome.org/platform-overview/stable/gtk">aplicación de GTK+</link> en Vala</p></item>
    <item><p>Algunos conceptos básicos de programación en <link href="http://developer.gnome.org/gobject/stable/">GObject</link></p></item>

  </list>
  <p>Necesitará lo siguiente para poder seguir este tutorial:</p>
  <list>
    <item><p>Conocimiento básico del lenguaje de programación <link href="https://live.gnome.org/Vala/Tutorial">Vala</link>.</p></item>
    <item><p>Una copia instalada de <app>Anjuta</app>.</p></item>
    <item><p>Puede que la referencia de la API de <link href="http://valadoc.org/gtk+-3.0/">gtk+-3.0</link> le resulte útil, aunque no es necesaria para seguir el tutorial.</p></item>
  </list>
</synopsis>

<media type="image" mime="image/png" src="media/image-viewer.png"/>

<section id="anjuta">
  <title>Crear un proyecto en Anjuta</title>
  <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>
  <steps>
    <item>
      <p>Inicie <app>Anjuta</app> y pulse <gui>Crear un proyecto nuevo</gui> o <guiseq><gui>Archivo</gui><gui>Nuevo</gui><gui>Proyecto</gui></guiseq> para abrir el asistente de proyectos.</p>
    </item>
    <item>
      <p>En la pestaña <gui>Vala</gui> seleccione <gui>GTK+ (simple)</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>
   	</item>
    <item>
      <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.</p>
     <note><p>Aprenderá a usar el constructor de interfaces en el tutorial del <link xref="guitar-tuner.vala">afinador de guitarra</link>.</p></note>
    </item>
    <item>
      <p>Pulse <gui>Continuar</gui> y luego <gui>Aplicar</gui> y se creará el proyecto. Abra <file>src/visor-imagenes.vala</file> desde las pestañas <gui>Proyecto</gui> o <gui>Archivo</gui>. Verá el siguiente código:</p>
      <code mime="text/x-csharp">
using GLib;
using Gtk;

public class Main : Object
{

	public Main ()
	{
		Window window = new Window();
		window.set_title ("Hello World");
		window.show_all();
		window.destroy.connect(on_destroy);
	}

	public void on_destroy (Widget window)
	{
		Gtk.main_quit();
	}

	static int main (string[] args)
	{
		Gtk.init (ref args);
		var app = new Main ();

		Gtk.main ();

		return 0;
	}
}</code>
    </item>
  </steps>
</section>

<section id="build">
  <title>Construir el código por primera vez</title>
  <p>El código carga una ventana (vacía) desde el archivo de descripción de interfaz de usuario y la muestra. Se ofrecen más detalles a continuación; omita esta lista si entiende los conceptos básicos:</p>

  <list>
    <item>
      <p>Las dos líneas <code>using</code> importan espacios de nombres, por lo que no hay que nombrarlas explícitamente.</p>
    </item>
    <item>
      <p>El constructor de la clase <code>Main</code> crea una ventana (vacía) nueva y conecta una <link href="https://live.gnome.org/Vala/SignalsAndCallbacks">señal</link> para salir de la aplicación cuando se cierra esa ventana.</p>
      <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>
    </item>
    <item>
      <p>La función <code>static main</code> se ejecuta de manera predeterminada cuando inicia una aplicación en Vala. Llama a algunas funciones que crean la clase <code>Main</code> y configuran y ejecutan la aplicación. La función <link href="http://valadoc.org/gtk+-3.0/Gtk.main.html"><code>Gtk.main</code></link> inicia el <link href="http://en.wikipedia.org/wiki/Event_loop">bucle principal</link> de GTK+, que ejecuta la interfaz de usuario y empieza a escuchar eventos (como pulsaciones del ratón y del teclado).</p>
    </item>
  </list>

  <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>
  <p>Cambie la <gui>Configuración</gui> a <gui>Predeterminada</gui> y pulse <gui>Ejecutar</gui> para configurar la carpeta de construcción. Sólo necesita hacer esto una vez, para la primera construcción.</p>
</section>

<section id="ui">
  <title>Crear la interfaz de usuario</title>
  <p>Ahora se dará vida a la ventana vacía. GTK+ organiza la interfaz de usuario con varios <link href="http://www.valadoc.org/gtk+-2.0/Gtk.Container.html"><code>Gtk.Container</code></link> que pueden contener otros widgets e incluso otros contenedores. Aquí se usará el contenedor más sencillo disponible, una <link href="http://unstable.valadoc.org/gtk+-2.0/Gtk.Box.html"><code>Gtk.Box</code></link>.</p>

<p>Añada las siguientes líneas a la parte superior de la clase <code>Main</code>:</p>
  <code mime="text/x-csharp">
private Window window;
private Image image;
</code>

<p>Ahora reemplace el constructor actual con el siguiente:</p>
<code mime="text/x-csharp">

public Main () {

	window = new Window ();
	window.set_title ("Image Viewer in Vala");

	// Set up the UI
	var box = new Box (Orientation.VERTICAL, 5);
	var button = new Button.with_label ("Open image");
	image = new Image ();

	box.pack_start (image, true, true, 0);
	box.pack_start (button, false, false, 0);
	window.add (box);

	// Show open dialog when opening a file
	button.clicked.connect (on_open_image);

	window.show_all ();
	window.destroy.connect (main_quit);
}
</code>
  <steps>
    <item>
      <p>Las dos primeras líneas son partes de la IGU a las que se debe acceder desde más de un método. Se declaran aquí, por lo que son accesibles mediante la clase en vez de serlo solamente en el método en el que se crearon.</p>
    </item>
    <item>
      <p>Las primeras líneas del constructor crean la ventana vacía. Las siguientes líneas crean los widgets que se quieren usar: un botón para abrir una imagen, el widget de la vista de la imagen en sí y la caja que se usará como contenedor.</p>
    </item>
    <item>
      <p>Las llamadas a <link href="http://unstable.valadoc.org/gtk+-2.0/Gtk.Box.pack_start.html"><code>pack_start</code></link> 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>
    </item>
    <item>
      <p>Se debe definir qué pasa cuando el usuario pulsa en el botón. GTK+ usa el concepto de <em>señales</em>.</p>
      <p>Cuando se pulsa el <link href="http://valadoc.org/gtk+-3.0/Gtk.Button.html">botón</link> se emite la señal <link href="http://valadoc.org/gtk+-3.0/Gtk.Button.clicked.html"><code>clicked</code></link>, que se puede conectar a alguna acción (definida en un método de un <link href="https://live.gnome.org/Vala/SignalsAndCallbacks">retorno de la llamada</link>).</p>
      <p>Esto se hace usando el método <code>connect</code> de la señal <code>clicked</code> de los botones, que en este caso indica a GTK+ que llame al método del retorno de la llamada <code>on_image_open</code> (todavía no definida) cuando se pulsa el botón. El <em>retorno de la llamada</em> se definirá en la siguiente sección.</p>
      <p>En el retorno de la llamada, se debe acceder a los widgets <code>window</code> y <code>image</code> que es por lo que se definen como miembros privados en la parte superior de la clase.</p>
    </item>
    <item>
      <p>La última llamada a <code>connect</code> asegura que la aplicación termina cuando se cierra la ventana. El código generado por Anjuta llamaba a un método <code>on_destroy</code> que llamaba a <link href="http://www.valadoc.org/gtk+-2.0/Gtk.main_quit.html"><code>Gtk.main_quit</code></link>, pero simplemente conectando la señal <code>main_quit</code> directamente es más fácil. Puede eliminar el método <code>on_destroy</code>.</p>
    </item>
  </steps>
</section>

<section id="image">
  <title>Mostrar la imagen</title>
  <p>Ahora se definirá el manejador de la señal <em>clicked</em> para el botón mencionado anteriormente. Añada este código después del constructor.</p>
  <code mime="text/x-csharp">
public void on_open_image (Button self) {
	var filter = new FileFilter ();
	var dialog = new FileChooserDialog ("Open image",
	                                    window,
	                                    FileChooserAction.OPEN,
	                                    Stock.OK,     ResponseType.ACCEPT,
	                                    Stock.CANCEL, ResponseType.CANCEL);
	filter.add_pixbuf_formats ();
	dialog.add_filter (filter);

	switch (dialog.run ())
	{
		case ResponseType.ACCEPT:
			var filename = dialog.get_filename ();
			image.set_from_file (filename);
			break;
		default:
			break;
	}
	dialog.destroy ();
}
</code>
  <p>Esto es un poco más complicado, así que se puede desglosar:</p>
  <note><p>Un manejador de señal es un tipo de método de retorno de la llamada al que se llama cuando se emite la señal. Aquí se usan los términos intercambiados.</p></note>
  <list>
    <item>
      <p>El primer argumento del método del retorno de la llamada es siempre el widget que envía la señal. A veces hay otros argumentos relativos a la señal que vienen después, pero <em>clicked</em> no tiene ninguno.</p>
      <p>En este caso, el <code>button</code> envía la señal <code>clicked</code>, que se conecta al método del retorno de la llamada <code>on_open_image</code>:</p>
<code mime="text/x-csharp">
        button.clicked.connect (on_open_image);
</code>

  <p>El método <code>on_open_image</code> toma como argumento el botón que ha emitido la señal:</p>
 <code mime="text/x-csharp">
        public void on_open_image (Button self)
</code>
    </item>
    <item>
      <p>La siguiente línea interesante es en la que se crea el diálogo para elegir el archivo. El constructor de  <link href="http://www.valadoc.org/gtk+-3.0/Gtk.FileChooserDialog.html"><code>FileChooserDialog</code></link> 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>
      <p>Tenga en cuenta que se está usando nombres de botones del <link href="http://unstable.valadoc.org/gtk+-3.0/Gtk.Stock.html"><em>almacén</em></link> 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>
    </item>
    <item>
      <p>Las dos líneas siguientes restringen el diálogo <gui>Abrir</gui> para que sólo muestre archivos que se puedan abrir con <code>GtkImage</code>. GtkImage es un widget que muestra una imagen. Primero se crea un objeto; luego se añaden los tipos de archivos soportados por el <link href="http://www.valadoc.org/gdk-pixbuf-2.0/Gdk.Pixbuf.html"><code>Gdk.Pixbuf</code></link> (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>
    </item>
    <item>
      <p><link href="http://www.valadoc.org/gtk+-3.0/Gtk.Dialog.run.html"><code>dialog.run</code></link> muestra el diálogo <gui>Abrir</gui>. El diálogo esperará a que el usuario seleccione una imagen; cuando lo haga, <code>dialog.run</code> devolverá el valor <code>ResponseType.ACCEPT</code> de <link href="http://www.valadoc.org/gtk+-3.0/Gtk.ResponseType.html">ResponseType</link> (devolvería <code>ResponseType.CANCEL</code> si el usuario pulsara <gui>Cancel</gui>). La sentencia <code>switch</code> comprueba esto.</p>
    </item>
    <item>
      <p>Asumiendo que el usuario pulsó <gui>Abrir</gui>, las siguientes líneas obtienen el nombre de archivo de la imagen seleccionada por el usuario e indican al widget <code>GtkImage</code> que cargue y muestre la imagen elegida.</p>
    </item>
    <item>
      <p>En la última línea de este método se destruye el diálogo <gui>Abrir</gui> porque ya no se necesita.</p>
      <p>Al destruir se oculta el diálogo automáticamente.</p>
    </item>
  </list>
</section>

<section id="run">
  <title>Construir y ejecutar la aplicación</title>
  <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>
  <p>Si todavía no lo ha hecho, elija la aplicación <file>src/visor-imagenes</file> en el diálogo que aparece. Finalmente, pulse <gui>Ejecutar</gui> y disfrute.</p>
</section>

<section id="impl">
  <title>Implementación de referencia</title>
  <p>Si tiene problemas con este tutorial, compare su código con este <link href="image-viewer/image-viewer.vala">código de referencia</link>.</p>
</section>

<section id="next">
  <title>Siguientes pasos</title>
  <p>Aquí hay algunas ideas sobre cómo puede extender esta sencilla demostración:</p>
  <list>
  <item><p>Configúrela de tal manera que la ventana se abra con un tamaño determinado. Por ejemplo, 200x200 píxeles.</p></item>
   <item>
     <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>
   </item>
   <item>
     <p>Aplicar filtros aleatorios y efectos a la imagen cuando se carga y permitir al usuario guardar la imagen modificada.</p>
     <p><link href="http://www.gegl.org/api.html">GEGL</link> proporciona la capacidad de manipular imágenes de manera potente.</p>
   </item>
   <item>
     <p>Permitir al usuario cargar imágenes desde recursos de red compartidos, escáneres y otras fuentes más complicadas.</p>
     <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>
   </item>
  </list>
</section>

</page>