In this tutorial you will create an application which opens and displays an image file. You will learn:
How to set up a basic project using the Anjuta IDE.
How to write a Gtk application in Vala
Some basic concepts of GObject programming
You'll need the following to be able to follow this tutorial:
Basic knowledge of the Vala programming language.
An installed copy of
You may find the gtk+-3.0 API Reference useful, although it is not necessary to follow the tutorial.
Before you start coding, you'll need to set up a new project in Anjuta. This will create all of the files you need to build and run the code later on. It's also useful for keeping everything together.
Start
From the
Make sure that
You will learn how to use the interface builder in the Guitar-Tuner tutorial.
Click
The code loads an (empty) window from the user interface description file and shows it. More details are given below; skip this list if you understand the basics:
The two using
lines at the top import namespaces so we don't have to name them explicitly.
The constructor of the Main
class creates a new (empty) window and connects a signal to exit the application when that window is closed.
Connecting signals is how you define what happens when you push a button, or when some other event happens.
Here, the destroy
function is called (and quits the app) when you close the window.
The static main
function is run by default when you start a Vala application.
It calls a few functions which create the Main
class, set up and then run the application.
The Gtk.main
function starts the GTK main loop, which runs the user interface and starts listening for events (like clicks and key presses).
This code is ready to be used, so you can compile it by clicking
Change the
Now we will bring life into the empty window.
GTK organizes the user interface with Gtk.Container
s that can contain other widgets and even other containers.
Here we will use the simplest available container, a Gtk.Box
.
Add the following lines to the top of the Main
class:
Now replace the current constructor with the one below:
The first two lines are the parts of the GUI that we will need to access from more than one method. We declare them up here so that they are accessible throughout the class instead of only in the method where they are created.
The first lines of the constructor create the empty window. 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.
The calls to pack_start
add the two widgets to the box and define their behaviour.
The image will expand into any available space whereas 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.
We need to define what happens when the user clicks on the button. GTK uses the concept of signals.
When the button is clicked, it fires the clicked
signal, which we can connect to some action (defined in a callback method).
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.
We will define the callback in the next section.
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.
The last connect
call makes sure that the application exits when the window is closed.
The code generated by Anjuta called an on_destroy
callback method which called Gtk.main_quit
, but just connecting our signal to main_quit
directly is easier. You can delete the on_destroy
method.
We will now define the signal handler for the clicked
signal for the
button we mentioned before.
Add this code after the constructor:
This is a bit complicated, so let's break it down:
A signal handler is a type of callback method that is called when a signal is emitted. Here the terms are used interchangeably.
The first argument of the callback method is always the widget that sent the signal. Sometimes other arguments related to the signal come after that, but clicked doesn't have any.
In this case the button
sent the clicked
signal, which is connected to the on_open_image
callback method:
The on_open_image
method takes the button that emitted the signal as an argument:
The next interesting line is where the dialog for choosing the file is created.
FileChooserDialog
'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.
Notice that we are using stock 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.
The next two lines restrict the Gdk.Pixbuf
(which includes most image formats like PNG and JPEG) to the filter.
Finally, we set this filter to be the
dialog.run
displays the dialog.run
will return the ResponseType value ResponseType.ACCEPT
(it would return ResponseType.CANCEL
if the user clicked switch
statement tests for this.
Assuming that the user did click GtkImage
widget to load and display the selected image.
In the final line of this method, we destroy the
Destroying automatically hides the dialog.
All of the code should now be ready to go.
Click
If you haven't already done so, choose the
If you run into problems with the tutorial, compare your code with this reference code.
Here are some ideas for how you can extend this simple demonstration:
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.
Have the user select a directory rather than a file, and provide controls to cycle through all of the images in a directory.
Apply random filters and effects to the image when it is loaded and allow the user to save the modified image.
GEGL provides powerful image manipulation capabilities.
Allow the user to load images from network shares, scanners, and other more complicated sources.
You can use GIO to handle network file transfers and the like, and GNOME Scan to handle scanning.