|
Packit |
1470ea |
|
|
Packit |
1470ea |
<page xmlns="http://projectmallard.org/1.0/" xmlns:its="http://www.w3.org/2005/11/its" type="topic" id="image-viewer.vala" xml:lang="ca">
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<info>
|
|
Packit |
1470ea |
<title type="text">Image viewer (Vala)</title>
|
|
Packit |
1470ea |
<link type="guide" xref="vala#examples"/>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<desc>A little bit more than a simple "Hello world" GTK+ application.</desc>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<revision pkgversion="0.1" version="0.1" date="2011-03-18" status="review"/>
|
|
Packit |
1470ea |
<credit type="author">
|
|
Packit |
1470ea |
<name>Projecte de documentació del GNOME</name>
|
|
Packit |
1470ea |
<email its:translate="no">gnome-doc-list@gnome.org</email>
|
|
Packit |
1470ea |
</credit>
|
|
Packit |
1470ea |
<credit type="author">
|
|
Packit |
1470ea |
<name>Johannes Schmid</name>
|
|
Packit |
1470ea |
<email its:translate="no">jhs@gnome.org</email>
|
|
Packit |
1470ea |
</credit>
|
|
Packit |
1470ea |
<credit type="author">
|
|
Packit |
1470ea |
<name>Philip Chimento</name>
|
|
Packit |
1470ea |
<email its:translate="no">philip.chimento@gmail.com</email>
|
|
Packit |
1470ea |
</credit>
|
|
Packit |
1470ea |
<credit type="editor">
|
|
Packit |
1470ea |
<name>Tiffany Antopolski</name>
|
|
Packit |
1470ea |
<email its:translate="no">tiffany.antopolski@gmail.com</email>
|
|
Packit |
1470ea |
</credit>
|
|
Packit |
1470ea |
<credit type="editor">
|
|
Packit |
1470ea |
<name>Marta Maria Casetti</name>
|
|
Packit |
1470ea |
<email its:translate="no">mmcasetti@gmail.com</email>
|
|
Packit |
1470ea |
<years>2013</years>
|
|
Packit |
1470ea |
</credit>
|
|
Packit |
1470ea |
</info>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<title>Image viewer</title>
|
|
Packit |
1470ea |
<synopsis>
|
|
Packit |
1470ea |
In this tutorial you will create an application which opens and displays an image file. You will learn:
|
|
Packit |
1470ea |
<list type="numbered">
|
|
Packit |
1470ea |
<item>How to set up a basic project using the <link xref="getting-ready">Anjuta IDE</link>. </item>
|
|
Packit |
1470ea |
<item>How to write a <link href="http://developer.gnome.org/platform-overview/stable/gtk">Gtk application</link> in Vala </item>
|
|
Packit |
1470ea |
<item>Some basic concepts of <link href="http://developer.gnome.org/gobject/stable/">GObject</link> programming </item>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
</list>
|
|
Packit |
1470ea |
You'll need the following to be able to follow this tutorial:
|
|
Packit |
1470ea |
<list>
|
|
Packit |
1470ea |
<item>Basic knowledge of the <link href="https://live.gnome.org/Vala/Tutorial">Vala</link> programming language. </item>
|
|
Packit |
1470ea |
<item>An installed copy of <app>Anjuta</app>. </item>
|
|
Packit |
1470ea |
<item>You may find the <link href="http://valadoc.org/gtk+-3.0/">gtk+-3.0</link> API Reference useful, although it is not necessary to follow the tutorial. </item>
|
|
Packit |
1470ea |
</list>
|
|
Packit |
1470ea |
</synopsis>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<media type="image" mime="image/png" src="media/image-viewer.png"/>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="anjuta">
|
|
Packit |
1470ea |
<title>Creació d'un projecte a l'Anjuta</title>
|
|
Packit |
1470ea |
Abans de començar a programar, heu de crear un projecte nou a l'Anjuta. L'Anjuta crearà tots els fitxers necessaris per, més endavant, construir i executar el codi. És molt útil per així mantenir-ho tot junt.
|
|
Packit |
1470ea |
<steps>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Start <app>Anjuta</app> and click <gui>Create a new project</gui> or <guiseq><gui>File</gui><gui>New</gui><gui>Project</gui></guiseq> to open the project wizard.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
From the <gui>Vala</gui> tab choose <gui>GTK+ (Simple)</gui>, click <gui>Continue</gui>, and fill out your details on the next page.
|
|
Packit |
1470ea |
Use <file>image-viewer</file> as project name and directory.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Make sure that <gui>Use GtkBuilder for user interface</gui> is unchecked as we will create the UI manually in this tutorial.
|
|
Packit |
1470ea |
<note>
|
|
Packit |
1470ea |
You will learn how to use the interface builder in the <link xref="guitar-tuner.vala">Guitar-Tuner</link> tutorial.</note>
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Click <gui>Continue</gui> then <gui>Apply</gui> and the project will be created for you.
|
|
Packit |
1470ea |
Open <file>src/image_viewer.vala</file> from the <gui>Project</gui> or <gui>File</gui> tabs.
|
|
Packit |
1470ea |
You will see this code:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
using GLib;
|
|
Packit |
1470ea |
using Gtk;
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
public class Main : Object
|
|
Packit |
1470ea |
{
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
public Main ()
|
|
Packit |
1470ea |
{
|
|
Packit |
1470ea |
Window window = new Window();
|
|
Packit |
1470ea |
window.set_title ("Hello World");
|
|
Packit |
1470ea |
window.show_all();
|
|
Packit |
1470ea |
window.destroy.connect(on_destroy);
|
|
Packit |
1470ea |
}
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
public void on_destroy (Widget window)
|
|
Packit |
1470ea |
{
|
|
Packit |
1470ea |
Gtk.main_quit();
|
|
Packit |
1470ea |
}
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
static int main (string[] args)
|
|
Packit |
1470ea |
{
|
|
Packit |
1470ea |
Gtk.init (ref args);
|
|
Packit |
1470ea |
var app = new Main ();
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Gtk.main ();
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
return 0;
|
|
Packit |
1470ea |
}
|
|
Packit |
1470ea |
}]]>
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
</steps>
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="build">
|
|
Packit |
1470ea |
<title>Build the code for the first time</title>
|
|
Packit |
1470ea |
The code loads an (empty) window from the user interface description file and shows it.
|
|
Packit |
1470ea |
More details are given below; skip this list if you understand the basics:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<list>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
The two using lines at the top import namespaces so we don't have to name them explicitly.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
The constructor of the Main class creates a new (empty) window and connects a <link href="https://live.gnome.org/Vala/SignalsAndCallbacks">signal</link> to exit the application when that window is closed.
|
|
Packit |
1470ea |
Connecting signals is how you define what happens when you push a button, or when some other event happens.
|
|
Packit |
1470ea |
Here, the destroy function is called (and quits the app) when you close the window.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
The static main function is run by default when you start a Vala application.
|
|
Packit |
1470ea |
It calls a few functions which create the Main class, set up and then run the application.
|
|
Packit |
1470ea |
The <link href="http://valadoc.org/gtk+-3.0/Gtk.main.html">Gtk.main </link> function starts the GTK <link href="http://en.wikipedia.org/wiki/Event_loop">main loop</link>, which runs the user interface and starts listening for events (like clicks and key presses).
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
</list>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
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>).
|
|
Packit |
1470ea |
Change the <gui>Configuration</gui> to <gui>Default</gui> and then press <gui>Execute</gui> to configure the build directory.
|
|
Packit |
1470ea |
You only need to do this once, for the first build.
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="ui">
|
|
Packit |
1470ea |
<title>Creating the user interface</title>
|
|
Packit |
1470ea |
Now we will bring life into the empty window.
|
|
Packit |
1470ea |
GTK organizes the user interface with <link href="http://www.valadoc.org/gtk+-2.0/Gtk.Container.html">Gtk.Container </link>s that can contain other widgets and even other containers.
|
|
Packit |
1470ea |
Here we will use the simplest available container, a <link href="http://unstable.valadoc.org/gtk+-2.0/Gtk.Box.html">Gtk.Box </link>.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Add the following lines to the top of the Main class:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
private Window window;
|
|
Packit |
1470ea |
private Image image;
|
|
Packit |
1470ea |
]]>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Now replace the current constructor with the one below:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
public Main () {
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
window = new Window ();
|
|
Packit |
1470ea |
window.set_title ("Image Viewer in Vala");
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
// Set up the UI
|
|
Packit |
1470ea |
var box = new Box (Orientation.VERTICAL, 5);
|
|
Packit |
1470ea |
var button = new Button.with_label ("Open image");
|
|
Packit |
1470ea |
image = new Image ();
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
box.pack_start (image, true, true, 0);
|
|
Packit |
1470ea |
box.pack_start (button, false, false, 0);
|
|
Packit |
1470ea |
window.add (box);
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
// Show open dialog when opening a file
|
|
Packit |
1470ea |
button.clicked.connect (on_open_image);
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
window.show_all ();
|
|
Packit |
1470ea |
window.destroy.connect (main_quit);
|
|
Packit |
1470ea |
}
|
|
Packit |
1470ea |
]]>
|
|
Packit |
1470ea |
<steps>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
The first two lines are the parts of the GUI that we will need to access from more than one method.
|
|
Packit |
1470ea |
We declare them up here so that they are accessible throughout the class instead of only in the method where they are created.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
The first lines of the constructor create the empty window.
|
|
Packit |
1470ea |
The next 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.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
The calls to <link href="http://unstable.valadoc.org/gtk+-2.0/Gtk.Box.pack_start.html">pack_start </link> add the two widgets to the box and define their behaviour.
|
|
Packit |
1470ea |
The image will expand into any available space whereas the button will just be as big as needed.
|
|
Packit |
1470ea |
You will notice that we don't set explicit sizes on the widgets.
|
|
Packit |
1470ea |
In GTK this is usually not needed as it makes it much easier to have a layout that looks good in different window sizes.
|
|
Packit |
1470ea |
Next, the box is added to the window.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
We need to define what happens when the user clicks on the button. GTK uses the concept of signals.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
When the <link href="http://valadoc.org/gtk+-3.0/Gtk.Button.html">button</link> is clicked, it fires the <link href="http://valadoc.org/gtk+-3.0/Gtk.Button.clicked.html">clicked </link> signal, which we can connect to some action (defined in a <link href="https://live.gnome.org/Vala/SignalsAndCallbacks">callback</link> method).
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
This is done using the connect method of the button's clicked signal, which in this case tells GTK to call the (yet undefined) on_image_open callback method when the button is clicked.
|
|
Packit |
1470ea |
We will define the callback in the next section.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
In the callback, we need to access the window and image widgets, which is why we defined them as private members at the top of our class.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
The last connect call makes sure that the application exits when the window is closed.
|
|
Packit |
1470ea |
The code generated by Anjuta called an on_destroy callback method which called <link href="http://www.valadoc.org/gtk+-2.0/Gtk.main_quit.html">Gtk.main_quit </link>, but just connecting our signal to main_quit directly is easier. You can delete the on_destroy method.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
</steps>
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="image">
|
|
Packit |
1470ea |
<title>Showing the image</title>
|
|
Packit |
1470ea |
We will now define the signal handler for the clicked signal for the
|
|
Packit |
1470ea |
button we mentioned before.
|
|
Packit |
1470ea |
Add this code after the constructor:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
public void on_open_image (Button self) {
|
|
Packit |
1470ea |
var filter = new FileFilter ();
|
|
Packit |
1470ea |
var dialog = new FileChooserDialog ("Open image",
|
|
Packit |
1470ea |
window,
|
|
Packit |
1470ea |
FileChooserAction.OPEN,
|
|
Packit |
1470ea |
Stock.OK, ResponseType.ACCEPT,
|
|
Packit |
1470ea |
Stock.CANCEL, ResponseType.CANCEL);
|
|
Packit |
1470ea |
filter.add_pixbuf_formats ();
|
|
Packit |
1470ea |
dialog.add_filter (filter);
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
switch (dialog.run ())
|
|
Packit |
1470ea |
{
|
|
Packit |
1470ea |
case ResponseType.ACCEPT:
|
|
Packit |
1470ea |
var filename = dialog.get_filename ();
|
|
Packit |
1470ea |
image.set_from_file (filename);
|
|
Packit |
1470ea |
break;
|
|
Packit |
1470ea |
default:
|
|
Packit |
1470ea |
break;
|
|
Packit |
1470ea |
}
|
|
Packit |
1470ea |
dialog.destroy ();
|
|
Packit |
1470ea |
}
|
|
Packit |
1470ea |
]]>
|
|
Packit |
1470ea |
This is a bit complicated, so let's break it down:
|
|
Packit |
1470ea |
<note>A signal handler is a type of callback method that is called when a signal is emitted. Here the terms are used interchangeably. </note>
|
|
Packit |
1470ea |
<list>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
The first argument of the callback method is always the widget that sent the signal.
|
|
Packit |
1470ea |
Sometimes other arguments related to the signal come after that, but clicked doesn't have any.
|
|
Packit |
1470ea |
In this case the button sent the clicked signal, which is connected to the on_open_image callback method:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
button.clicked.connect (on_open_image);
|
|
Packit |
1470ea |
]]>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
The on_open_image method takes the button that emitted the signal as an argument:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
public void on_open_image (Button self)
|
|
Packit |
1470ea |
]]>
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
The next interesting line is where the dialog for choosing the file is created.
|
|
Packit |
1470ea |
<link href="http://www.valadoc.org/gtk+-3.0/Gtk.FileChooserDialog.html">FileChooserDialog </link>'s constructor takes the title of the dialog, the parent window of the dialog and several options like the number of buttons and their corresponding values.
|
|
Packit |
1470ea |
Notice that we are using <link href="http://unstable.valadoc.org/gtk+-3.0/Gtk.Stock.html">stock</link> button names from Gtk, instead of manually typing "Cancel" or "Open".
|
|
Packit |
1470ea |
The advantage of using stock names is that the button labels will already be translated into the user's language.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
The next two lines restrict the <gui>Open</gui> dialog to only display files which can be opened by GtkImage. GtkImage is a widget which displays an image.
|
|
Packit |
1470ea |
A filter object is created first; we then add all kinds of files supported by <link href="http://www.valadoc.org/gdk-pixbuf-2.0/Gdk.Pixbuf.html">Gdk.Pixbuf </link> (which includes most image formats like PNG and JPEG) to the filter.
|
|
Packit |
1470ea |
Finally, we set this filter to be the <gui>Open</gui> dialog's filter.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
<link href="http://www.valadoc.org/gtk+-3.0/Gtk.Dialog.run.html">dialog.run </link> displays the <gui>Open</gui> dialog.
|
|
Packit |
1470ea |
The dialog will wait for the user to choose an image; when they do, dialog.run will return the <link href="http://www.valadoc.org/gtk+-3.0/Gtk.ResponseType.html">ResponseType</link> value ResponseType.ACCEPT (it would return ResponseType.CANCEL if the user clicked <gui>Cancel</gui>).
|
|
Packit |
1470ea |
The switch statement tests for this.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Assuming that the user did click <gui>Open</gui>, the next lines get the filename of the image selected by the user, and tell the GtkImage widget to load and display the selected image.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
In the final line of this method, we destroy the <gui>Open</gui> dialog because we don't need it any more.
|
|
Packit |
1470ea |
Destroying automatically hides the dialog.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
</list>
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="run">
|
|
Packit |
1470ea |
<title>Muntatge i execució de l'aplicació</title>
|
|
Packit |
1470ea |
All of the code should now be ready to go.
|
|
Packit |
1470ea |
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.
|
|
Packit |
1470ea |
If you haven't already done so, choose the <file>src/image-viewer</file> application in the dialog that appears.
|
|
Packit |
1470ea |
Finally, hit <gui>Run</gui> and enjoy!
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="impl">
|
|
Packit |
1470ea |
<title>Implementació de referència</title>
|
|
Packit |
1470ea |
If you run into problems with the tutorial, compare your code with this <link href="image-viewer/image-viewer.vala">reference code</link>.
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="next">
|
|
Packit |
1470ea |
<title>Next steps</title>
|
|
Packit |
1470ea |
Here are some ideas for how you can extend this simple demonstration:
|
|
Packit |
1470ea |
<list>
|
|
Packit |
1470ea |
<item>Set it up so that when the window opens it is of a specific size to start off with. For example, 200 X 200 pixels. </item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Have the user select a directory rather than a file, and provide controls to cycle through all of the images in a directory.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Apply random filters and effects to the image when it is loaded and allow the user to save the modified image.
|
|
Packit |
1470ea |
<link href="http://www.gegl.org/api.html">GEGL</link> provides powerful image manipulation capabilities.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Allow the user to load images from network shares, scanners, and other more complicated sources.
|
|
Packit |
1470ea |
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.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
</list>
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
</page>
|