<?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="sv">

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

    <desc>Lite mer än ett enkelt ”Hej världen”-program i Gtk.</desc>

    <revision pkgversion="0.1" version="0.1" date="2011-03-18" status="review"/>
    <credit type="author">
      <name>Dokumentationsprojekt för 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>Sebastian Rasmussen</mal:name>
      <mal:email>sebras@gmail.com</mal:email>
      <mal:years>2019</mal:years>
    </mal:credit>
  
    <mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
      <mal:name>Anders Jonsson</mal:name>
      <mal:email>anders.jonsson@norsjovallen.se</mal:email>
      <mal:years>2021</mal:years>
    </mal:credit>
  </info>

<title>Bildvisare</title>

<synopsis>
  <p>I denna handledning kommer du lära dig:</p>
  <list>
    <item><p>Några grundläggande koncept i C/GObject-programmering</p></item>
    <item><p>Hur du skriver ett Gtk-program i C</p></item>
  </list>
</synopsis>

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

<section id="anjuta">
  <title>Skapa ett projekt i Anjuta</title>
  <p>Innan du börjar koda kommer du behöva konfigurera ett nytt projekt i Anjuta. Detta kommer skapa alla filer som du behöver för att bygga och köra koden senare. Det är också användbart för att hålla allting samlat.</p>
  <steps>
    <item>
    <p>Starta Anjuta och klicka på <guiseq><gui>Arkiv</gui><gui>Ny</gui><gui>Projekt</gui></guiseq> för att öppna projektguiden.</p>
    </item>
    <item>
    <p>Välj <gui>GTK+ (enkel)</gui> från fliken <gui>C</gui>, klicka på <gui>Fortsätt</gui>, och fyll i dina detaljer på de nästkommande sidorna. Använd <file>image-viewer</file> som projektnamn och katalog.</p>
   	</item>
    <item>
    <p>Säkerställ att <gui>Använd GtkBuilder för användargränssnitt</gui> är inaktiverat då vi kommer skapa användargränssnittet manuellt i denna handledning. Se handledningen <link xref="guitar-tuner.c">Gitarrstämmare</link> om du vill lära dig hur du använder gränssnittsbyggaren.</p>
    </item>
    <item>
    <p>Klicka på <gui>Verkställ</gui> så kommer projektet skapas åt dig. Öppna <file>src/main.c</file> från flikarna <gui>Projekt</gui> eller <gui>Filer</gui>. Du bör se kod som börjar med raderna:</p>
    <code mime="text/x-csrc">
#include &lt;config.h&gt;
#include &lt;gtk/gtk.h&gt;</code>
    </item>
  </steps>
</section>

<section id="build">
  <title>Bygg koden för första gången</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>Funktionen <code>create_window</code> skapar ett nytt (tomt) fönster och ansluter en signal för att avsluta programmet då det fönstret stängs.</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>Denna kod är klar att användas, så du kan kompilera den genom att klicka på <guiseq><gui>Bygg</gui><gui>Bygg projekt</gui></guiseq> (eller trycka <keyseq><key>Skift</key><key>F7</key></keyseq>).</p>
  <p>Press <gui>Execute</gui> on the next window that appears to configure a debug build. You only need to do this once, for the first build.</p>
</section>

<section id="ui">
<title>Skapa användargränssnittet</title>
<p>Nu kommer vi blåsa liv i det tomma fönstret. GTK organiserar användargränssnittet med behållare av typ <code>GtkContainer</code> som kan innehålla andra komponenter och till och med andra behållare. Här kommer vi använda den enklaste tillgängliga behållaren, en <code>GtkBox</code>:</p>
<code mime="text/x-csrc">
static GtkWidget*
create_window (void)
{
	GtkWidget *window;
	GtkWidget *button;
	GtkWidget *image;
	GtkWidget *box;

	/* Konfigurera användargränssnittet */
	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 (_("Öppna bild"));
	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);

	/* Anslut signaler */

	/* Visa öppna-dialog då en fil öppnas */
	g_signal_connect (button, "clicked", G_CALLBACK (on_open_image), image);

	/* Avsluta då fönstret stängs */
	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>Den sista <code>g_signal_connect()</code> säkerställer att programmet avslutas när fönstret stängs.</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>Visa bilden</title>
<p>Vi kommer nu definiera signalhanteraren för <em>clicked</em>-signalen eller knappen vi nämnde tidigare. Lägg till denna kod före <code>create_window()</code>-metoden.</p>
<code mime="text/x-csrc">
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 (_("Öppna bild"),
	                                                 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>Det här är lite mer komplicerat än något som vi försökt så här långt, så låt oss dela upp det:</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>Observera att vi använder <em>standard</em>knappnamn från Gtk, istället för att manuellt skriva in ”Avbryt” eller ”Öppna”. Fördelen med att använda standardnamn är att knappetiketterna redan kommer vara översatta till användarens språk.</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>Bygg och kör programmet</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>If you haven't already done so, choose the <file>Debug/src/image-viewer</file> application in the dialog that appears. Finally, hit <gui>Run</gui> and enjoy!</p>
</section>

<section id="impl">
 <title>Referensimplementation</title>
 <p>Om du stöter på problem med handledningen kan du jämföra din kod med denna <link href="image-viewer/image-viewer.c">referenskod</link>.</p>
</section>

<section id="next">
  <title>Nästa steg</title>
  <p>Här är några idéer på hur du kan utöka denna enkla demonstration:</p>
  <list>
   <item>
   <p>Låt användaren välja en katalog snarare än en fil, och tillhandahåll kontroller för att gå igenom alla bilderna i en katalog.</p>
   </item>
   <item>
   <p>Tillämpa slumpmässiga filter och effekter till bilden då den läses in och låt användaren spara den ändrade bilden.</p>
   <p><link href="http://www.gegl.org/api.html">GEGL</link> har kraftfulla bildmanipuleringsförmågor.</p>
   </item>
   <item>
   <p>Allow the user to load images from network shares, scanners, and other more complicated sources.</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>
