In this tutorial, we're going to write a very simple GTK application that loads and displays an image file. You will learn how to:
Write a basic GTK user interface in Python
Deal with events by connecting signals to signal handlers
Lay out GTK user interfaces using containers
Load and display image files
You'll need the following to be able to follow this tutorial:
An installed copy of the Anjuta IDE
Basic knowledge of the python programming language
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.
Inicieu l'Anjuta i feu clic a
Choose
Be sure to disable
Feu clic a
Let's see what a very basic Gtk application looks like in Python:
Let's take a look at what's happening:
The first line imports the Gtk namespace (that is, it includes the Gtk library). The libraries are provided by GObject Introspection (gi), which provides language bindings for many GNOME libraries.
In the __init__
method of the GUI
class creates an
(empty) Gtk.Window
, sets its title and then connects a signal to quit the application
once the window is closed. That's pretty simple overall, more on signals later.
Next, destroy
is defined which just quits the application. It is called
by the destroy
signal connected above.
The rest of the file does initialisation for Gtk and displays the GUI.
This code is ready to run, so try it using
Signals are one of the key concepts in Gtk programming. Whenever something happens to an object, it emits a signal; for example, when a button is clicked it gives off the clicked
signal. If you want your program to do something when that event occurs, you must connect a function (a "signal handler") to that signal. Here's an example:
The last two lines create a Gtk.Button
called b
and connect its clicked
signal to the button_clicked
function, which is defined above. Every time the button is clicked, the code in the button_clicked
function will be executed. It just prints a message here.
Widgets (controls, such as buttons and labels) can be arranged in the window by making use of containers. You can organize the layout by mixing different types of containers, like boxes and grids.
A Gtk.Window
is itself a type of container, but you can only put one widget directly into it. We would like to have two widgets, an image and a button, so we must put a "higher-capacity" container inside the window to hold the other widgets. A number of container types are available, but we will use a Gtk.Box
here. A Gtk.Box
can hold several widgets, organized horizontally or vertically. You can do more complicated layouts by putting several boxes inside another box and so on.
There is a graphical user interface designer called
Let's add the box and widgets to the window. Insert the following code into the __init__
method, immediately after the window.connect_after
line:
The first line creates a Gtk.Box
called box
and the following lines set two of its properties: the orientation
is set to vertical (so the widgets are arranged in a column), and the spacing
between the widgets is set to 5 pixels. The next line then adds the newly-created Gtk.Box
to the window.
So far the window only contains an empty Gtk.Box
, and if you run the program now you will see no changes at all (the Gtk.Box
is a transparent container, so you can't see that it's there).
To add some widgets to the Gtk.Box
, insert the following code directly below the window.add (box)
line:
The first line creates a new Gtk.Image
called image
, which will be used to display an image file.
As we need that later on in the signal handler, we will define it as a class-wide variable. You need to add image = 0
to the beginning of the GUI
class. Then, the image widget is added (packed) into the box
container using GtkBox's pack_start
method.
pack_start
takes 4 arguments: the widget that is to be added to the GtkBox (child
); whether the Gtk.Box
should grow larger when the new widget is added (expand
); whether the new widget should take up all of the extra space created if the Gtk.Box
gets bigger (fill
); and how much space there should be, in pixels, between the widget and its neighbors inside the Gtk.Box
(padding
).
Gtk containers (and widgets) dynamically expand to fill the available space, if you let them. You don't position widgets by giving them a precise x,y-coordinate location in the window; rather, they are positioned relative to one another. This makes handling window resizing much easier, and widgets should automatically take a sensible size in most situations.
Also note how the widgets are organized in a hierarchy. Once packed in the Gtk.Box
, the Gtk.Image
is considered a child of the Gtk.Box
. This allows you to treat all of the children of a widget as a group; for example, you could hide the Gtk.Box
, which would also hide all of its children at the same time.
Now insert these two lines, below the two you just added:
These lines are similar to the first two, but this time they create a Gtk.Button
and add it to box
. Notice that we are setting the expand
argument (the second one) to False
here, whereas it was set to True
for the Gtk.Image
. This will cause the image to take up all available space and the button to take only the space it needs. When you maximize the window, the button size will remain the same, but the image size will increase, taking up all of the rest of the window.
clicked
signalWhen the user clicks on the
The first step is to connect the clicked
signal of the button to a signal handler function, which we call on_open_clicked
. Put this code immediately after the button = Gtk.Button()
line where the button was created:
This will connect the clicked
signal to on_open_clicked
method that we will define
below.
Now we can create the on_open_clicked
method. Insert the following into the GUI
class code block, after the __init__
method:
This is a bit more complicated than anything we've attempted so far, so let's break it down:
The line beginning with dialog
creates an SAVE
if the intention was to save a file; and transient_for
, which sets the parent window of the dialog.
The next two lines add add_button
method is the (integer) value that is returned when the button is pressed: 0 for
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.
set_default_response
determines the button that will be activated if the user double-clicks a file or presses
The next three lines restrict the Gtk.Image
. A filter object is created first; we then add all kinds of files supported by 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 value (it would return if the user clicked if
statement tests for this.
Assuming that the user did click file
property of the Gtk.Image
to the filename of the image selected by the user. The Gtk.Image
will then load and display the chosen image.
In the final line of this method, we destroy the
All of the code you need should now be in place, so try running the code. That should be it; a fully-functioning image viewer (and a whistlestop tour of Python and Gtk) in not much time at all!
Si teniu algun problema amb el programa d'aprenentatge, compareu el codi amb el codi de referència.
Here are some ideas for how you can extend this simple demonstration:
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.