In diesem Tutorial lernen Sie, wie:
Some basic concepts of C/GObject programming
Schreiben einer Gtk-Anwendung in C
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 Anjuta and click
Choose
Make sure that
Click
#include <config.h>
#include <gtk/gtk.h>
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:
The three #include
lines at the top include the config
(useful autoconf build defines), gtk
(user interface) and gi18n
(internationalization) libraries. Functions from these libraries are used in the rest of the code.
The create_window
function 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 main
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 gtk_main
function starts the GTK main loop, which runs the user interface and starts listening for events (like clicks and key presses).
The ENABLE_NLS
conditional definition sets up gettext
, which is a framework for translating applications. These functions specify how translation tools should handle your app when you run them.
This code is ready to be used, so you can compile it by clicking
Press
Now we will bring life into the empty window. GTK organizes the user interface
with GtkContainer
s that can contain other widgets and even other containers. Here we
will use the simplest available container, a GtkBox
:
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;
}
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 GTK_BOX
are used for dynamic type checking and casting
which is needed as C doesn't support object-orientation out-of-the-box.
The calls to gtk_box_pack_start
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.
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. This is done using the g_signal_connect
function which tells GTK to call the on_image_open
function when the button is clicked and
to pass the image as an additional argument to that function. We will define the callback in the next section.
The last g_signal_connect()
makes sure that the application exits when the window is closed.
As a last step, make sure to replace the gtk_widget_show
call in the main()
function by
gtk_widget_show_all()
to show the window and all the widgets it contains.
We will now define the signal handler for the clicked signal or the
button we mentioned before. Add this code before the create_window()
method.
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);
}
This is a bit more complicated than anything we've attempted so far, so let's break it down:
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 clicked doesn't have any. Next is
the user_data
argument which is a pointer to the data we passed when connecting the signal.
In this case it is our GtkImage
object.
The next interesting line is where the dialog for choosing the file is created using
gtk_file_chooser_dialog_new
. 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.
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 GdkPixbuf
(which includes most image formats like PNG and JPEG) to the filter. Finally, we set this filter to be the
gtk_dialog_run
displays the gtk_dialog_run
will return the value GTK_RESPONSE_ACCEPT
(it would return GTK_RESPONSE_CANCEL
if the user clicked switch
statement tests for this.
Assuming that the user did click file
property of the GtkImage to the filename of the image selected by the user. The GtkImage will then load and display the chosen image.
In the final line of this method, we destroy the
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:
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.