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.c" xml:lang="gl">

  <info>
    <title type="text">Image viewer (C)</title>
    <link type="guide" xref="c#examples"/>

    <desc>Un pouco máis que un simple aplicativo Gtk «Ola mundo».</desc>

    <revision pkgversion="0.1" version="0.1" date="2011-03-18" status="review"/>
    <credit type="author">
      <name>Proxecto 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="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>Fran Dieguez</mal:name>
      <mal:email>frandieguez@gnome.org</mal:email>
      <mal:years>2012-2013.</mal:years>
    </mal:credit>
  </info>

<title>Image viewer</title>

<synopsis>
  <p>Neste titorial aprenderá:</p>
  <list>
    <item><p>Algúns conceptos básicos de programación de C/GObject</p></item>
    <item><p>Como escribir un aplicativo GTK en C</p></item>
  </list>
</synopsis>

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

<section id="anjuta">
  <title>Cree un proxecto de Anjuta</title>
  <p>Antes de comezar a programar, deberá configurar un proxecto novo en Anjuta. Isto creará todos os ficheiros que precise para construír e executar o código máis adiante. Tamén é útil para manter todo ordenado.</p>
  <steps>
    <item>
    <p>Inicie Anjuta e prema <guiseq><gui>Ficheiro</gui><gui>Novo</gui><gui>Proxecto</gui></guiseq> para abrir o asistente de proxectos.</p>
    </item>
    <item>
    <p>Choose <gui>GTK+ (Simple)</gui> from the <gui>C</gui> tab, click <gui>Continue</gui>, and fill out your details on the next few pages. Use <file>image-viewer</file> as project name and directory.</p>
   	</item>
    <item>
    <p>Asegúrese que <gui>Usar GtkBuilder para a interface de usuario</gui> está desactivado xa que crearemos a UI manualmente neste titorial. Comprobe o titorial <link xref="guitar-tuner.c">Guitar-Tuner</link> se quere aprender como usar o construtor de interface.</p>
    </item>
    <item>
    <p>Prema <gui>Aplicar</gui> para crear o proxecto. Abra <file>src/main.c</file> desde as lapelas <gui>Proxecto</gui> ou <gui>Ficheiro</gui>. Debería ver algún código que comeza coas liñas:</p>
    <code mime="text/x-csrc"><![CDATA[
#include <config.h>
#include <gtk/gtk.h>]]></code>
    </item>
  </steps>
</section>

<section id="build">
  <title>Construír o código por primeira vez</title>
  <p>C is a rather verbose language, so don't be surprised that the file contains quite a lot of code. Most of it is template code. It loads an (empty) window and shows it. More details are given below; skip this list if you understand the basics:</p>

  <list>
  <item>
    <p>The three <code>#include</code> lines at the top include the <code>config</code> (useful autoconf build defines), <code>gtk</code> (user interface) and <code>gi18n</code> (internationalization) libraries. Functions from these libraries are used in the rest of the code.</p>
   </item>
   <item>
    <p>A función <code>create_window</code> crea unha xanela (baleira) nova e conecta un sinal para saír do aplicativo péchase esa xanela.</p>
    <p>Connecting signals is how you define what happens when you push a button, or when some other event happens. Here, the <code>destroy</code> function is called (and quits the app) when you close the window.</p>
   </item>
   <item>
    <p>The <code>main</code> function is run by default when you start a C application. It calls a few functions which set up and then run the application. The <code>gtk_main</code> function starts the GTK main loop, which runs the user interface and starts listening for events (like clicks and key presses).</p>
   </item>
   <item>
    <p>The <code>ENABLE_NLS</code> conditional definition sets up <code>gettext</code>, which is a framework for translating applications. These functions specify how translation tools should handle your app when you run them.</p>
   </item>
  </list>

  <p>This code is ready to be used, so you can compile it by clicking <guiseq><gui>Build</gui><gui>Build Project</gui></guiseq> (or press <keyseq><key>Shift</key><key>F7</key></keyseq>).</p>
  <p>Prema <gui>Executar</gui> na seguinte xanela que aparece para configurar a compilación de depuración. Só precisa facer isto unha vez para a primeira compilación.</p>
</section>

<section id="ui">
<title>Crear a interface de usuario</title>
<p>Now we will bring life into the empty window. GTK organizes the user interface
with <code>GtkContainer</code>s that can contain other widgets and even other containers. Here we
will use the simplest available container, a <code>GtkBox</code>:</p>
<code mime="text/x-csrc"><![CDATA[
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;
}
]]></code>
  <steps>
    <item>
    <p>The first lines create the widgets we want to use: a button for opening up an image, the image view widget itself and
    the box we will use as a container. The macros like <code>GTK_BOX</code> are used for dynamic type checking and casting
    which is needed as C doesn't support object-orientation out-of-the-box.</p>
    </item>
    <item>
    <p>The calls to <code>gtk_box_pack_start</code> add the two widgets to the box and define their behaviour. The image will
    expand into any available space while the button will just be as big as needed. You will notice that we don't set
    explicit sizes on the widgets. In GTK this is usually not needed as it makes it much easier to have a layout that
    looks good in different window sizes. Next, the box is added to the window.</p>
    </item>
    <item>
    <p>We need to define what happens when the user clicks on the button. GTK uses the concept of <em>signals</em>. When the button is clicked, it fires the <em>clicked</em> signal, which we can connect to some action. This is done using the <code>g_signal_connect</code>
    function which tells GTK to call the <code>on_image_open</code> function when the button is clicked and
    to pass the image as an additional argument to that function. We will define the <em>callback</em> in the next section.</p>
    </item>
    <item>
    <p>The last <code>g_signal_connect()</code> makes sure that the application exits when the window is closed.</p>
    </item>
    <item>
    <p>As a last step, make sure to replace the <code>gtk_widget_show</code> call in the <code>main()</code> function by
    <code>gtk_widget_show_all()</code> to show the window and all the widgets it contains.</p>
    </item>
  </steps>
</section>

<section id="image">
<title>Mostrar a imaxe</title>
<p>We will now define the signal handler for the <em>clicked</em> signal or the
button we mentioned before. Add this code before the <code>create_window()</code>
method.</p>
<code mime="text/x-csrc"><![CDATA[
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);
}
]]></code>
  <p>This is a bit more complicated than anything we've attempted so far, so let's break it down:</p>
  <list>
    <item><p>The first argument of the signal is always the widget that sent the signal. Sometimes
    other arguments related to the signal come after that, but <em>clicked</em> doesn't have any. Next is
    the <code>user_data</code> argument which is a pointer to the data we passed when connecting the signal.
    In this case it is our <code>GtkImage</code> object.</p>
    </item>
    <item>
      <p>The next interesting line is where the dialog for choosing the file is created using
      <code>gtk_file_chooser_dialog_new</code>. The function takes the title of the dialog, the
      parent window of the dialog and several options like the number of buttons and their corresponding
      values.</p>
    <p>Notice that we are using <em>stock</em> button names from Gtk, instead of manually typing "Cancel" or "Open". The advantage of using stock names is that the button labels will already be translated into the user's language.</p>
    </item>
    <item>
    <p>The next two lines restrict the <gui>Open</gui> dialog to only display files which can be opened by GtkImage. A filter object is created first; we then add all kinds of files supported by <code>GdkPixbuf</code> (which includes most image formats like PNG and JPEG) to the filter. Finally, we set this filter to be the <gui>Open</gui> dialog's filter.</p>
    </item>
    <item>
    <p><code>gtk_dialog_run</code> displays the <gui>Open</gui> dialog. The dialog will wait for the user to choose an image; when they do, <code>gtk_dialog_run</code> will return the value <code>GTK_RESPONSE_ACCEPT</code> (it would return <code>GTK_RESPONSE_CANCEL</code> if the user clicked <gui>Cancel</gui>). The <code>switch</code> statement tests for this.</p>
    </item>
    <item><p>Assuming that the user did click <gui>Open</gui>, the next line sets the <code>file</code> property of the GtkImage to the filename of the image selected by the user. The GtkImage will then load and display the chosen image.</p>
    </item>
    <item>
    <p>In the final line of this method, we destroy the <gui>Open</gui> dialog because we don't need it any more.
    Destroying automatically hides the dialog.</p>
    </item>
  </list>
</section>

<section id="run">
  <title>Construír e executar o aplicativo</title>
  <p>All of the code should now be ready to go. Click <guiseq><gui>Build</gui><gui>Build Project</gui></guiseq> to build everything again, and then <guiseq><gui>Run</gui><gui>Execute</gui></guiseq> to start the application.</p>
  <p>Se non o fixo aínda, seleccione o aplicativo <file>Debug/src/image-viewer</file> no diálogo que aparece. Finalmente, prema <gui>Executar</gui> e desfrute!</p>
</section>

<section id="impl">
 <title>Implementación de referencia</title>
 <p>If you run into problems with the tutorial, compare your code with this <link href="image-viewer/image-viewer.c">reference code</link>.</p>
</section>

<section id="next">
  <title>Seguintes pasos</title>
  <p>Aquí hai algunhas ideas sobre como pode estender esta sinxela demostración:</p>
  <list>
   <item>
   <p>Have the user select a directory rather than a file, and provide controls to cycle through all of the images in a directory.</p>
   </item>
   <item>
   <p>Aplicar filtros aleatorios e efectos á imaxe cando se carga e permitir ao usuario gardar a imaxe modificada.</p>
   <p><link href="http://www.gegl.org/api.html">GEGL</link> fornece capacidades moi potentes de manipulación de imaxes.</p>
   </item>
   <item>
   <p>Permitir ao usuario cargar imaxes desde recursos de rede compartidos, escáneres e outras fontes máis complicadas.</p>
   <p>You can use <link href="http://library.gnome.org/devel/gio/unstable/">GIO</link> to handle network file transfers and the like, and <link href="http://library.gnome.org/devel/gnome-scan/unstable/">GNOME Scan</link> to handle scanning.</p>
   </item>
  </list>
</section>


</page>