Содержание


Использование GtkBuilder

Comments

Как средство создания пользовательского интерфейса, GTK+ является не просто признанным инструментом, а, скорее, стандартом. Это в большей степени справедливо для рабочего стола gnome, однако и в окружении KDE можно встретить достаточно программ, которые используют эту библиотеку. Конечно, разделение на два больших лагеря не приносит сообществу много пользы, пользователь привыкает работать, скажем, в KDE, и gnome-приложения кажутся ему уже совсем непривычными – пользоваться ими он скорее всего не будет. Хотя и для KDE, и для gnome написано достаточно много хорошего софта.

Однако какой бы хорошей ни была библиотека GTK+, современные разработчики не желают тратить время на написание кода там, где все можно сделать несколькими движениями мыши. И здесь отличным средством повышения производительности является Glade. Рассматриваемые в статье вопросы касаются использования этого инструмента и соответствующего API.

Glade

Glade (или Glade Interface Designer) – это программа, предназначенная для визуального проектирования пользовательского интерфейса приложений GTK+. На данный момент активно разрабатываемой версией является третья. Можно немного рассказать об эволюции этого инструмента. Не так давно большой популярностью пользовалась версия 2. Кардинальным отличием от третьей ветки является то, что на выходе получался программный код, который затем компилировался в оконное приложение. Иными словами, Glade значительно упрощал набор этого кода. Начиная с третьей версии, на выходе получается xml-файл, который содержит описание интерфейса. Ранее была отдельная библиотека, содержащая необходимый API – libglade, однако затем она была признана устаревшей, и API перенесли в библиотеку GTK+. Также немного изменился формат файла, но принципы остались прежними.

Новый Glade умеет работать с обоими форматами, т.е. при создании нового файла вы указываете, с чем вы хотите работать: GtkBuilder (новый подход) или Libglade (признано устаревшим и к использованию не рекомендуется). Полное рассмотрение возможностей Glade выходит за рамки статьи, но несколько слов о нем скажем. Установить Glade можно командой apt-get install glade или ей подобной, важно, что мета-пакет будет называться glade.

Интерфейс достаточно простой и интуитивно понятный. Слева находятся различные наборы виджетов (всего около сотни). В центре – рабочая область. Нетрудно догадаться, что это как раз то место, где интерфейс программы приобретает свой облик. Для того, чтобы комфортно работать в Glade, пользователю неплохо было бы иметь представление о библиотеке GTK+. По крайней мере, тогда предназначение, скажем, контейнера Vertical Box будет для него очевидно. Немаловажным элементом интерфейса является панель Properties. Здесь задаются различные атрибуты виджета. Для каждого типа наборы этих атрибутов отличаются.

Что касается выходного файла, то это будет описание того, что вы видите в рабочей области в xml-разметке. Приведем пример такого файла:

Листинг 1. Пример описания интерфейса GtkBuilder.
<?xml version="1.0"?>
<interface>
  <requires lib="gtk+" version="2.16"/>
  <!-- interface-naming-policy project-wide -->
  <object class="GtkWindow" id="window1">
    <child>
      <object class="GtkVBox" id="vbox1">
        <property name="visible">True</property>
        <property name="orientation">vertical</property>
        <child>
          <object class="GtkImage" id="image1">
            <property name="visible">True</property>
            <property name="stock">gtk-missing-image</property>
          </object>
          <packing>
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <object class="GtkLabel" id="label1">
            <property name="visible">True</property>
            <property name="label" translatable="yes">label</property>
          </object>
          <packing>
            <property name="position">1</property>
          </packing>
        </child>
        <child>
          <object class="GtkButton" id="button1">
            <property name="label" translatable="yes">button</property>
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="receives_default">True</property>
            <signal name="clicked" handler="on_clicked"/>
          </object>
          <packing>
            <property name="position">2</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>

В этом файле описано одно окно с вертикальным контейнером внутри. В контейнере GtkVBox лежат GtkImage, GtkLabel и GtkButton. Все это объекты (структуры) библиотеки GTK+. Информацию по ним можно получить в справке.

Как можно видеть, понимание принципа работы GtkBuilder также не вызывает трудностей: организованный по определенным правилам xml-файл передается парсеру, затем на основании полученной информации делаются соответствующие вызовы из библиотеки GTK+. Все достаточно просто, объем кода уменьшается, проектирование «окошек и кнопочек» упрощается. Наверное, поэтому вопросы о целесообразности использования этого инструмента возникать не должны.

Для сравнения можно также привести код, который может получиться у glade версии 2:

Листинг 2. Сгенерированный Glade 2 код.
/*
 * DO NOT EDIT THIS FILE - it is generated by Glade.
 */

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>

#include <gdk/gdkkeysyms.h>
#include <gtk/gtk.h>

#include "callbacks.h"
#include "interface.h"
#include "support.h"

#define GLADE_HOOKUP_OBJECT(component,widget,name) \
  g_object_set_data_full (G_OBJECT (component), name, \
    gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref)

#define GLADE_HOOKUP_OBJECT_NO_REF(component,widget,name) \
  g_object_set_data (G_OBJECT (component), name, widget)

GtkWidget*
create_window1 (void)
{
  GtkWidget *window1;
  ...
  //созание интерфейса(много кода)
  ...
  return window1;
}

GtkWidget*
create_aboutdialog1 (void)
{
  GtkWidget *aboutdialog1;
    ...
  //созание интерфейса
  ...
  return aboutdialog1;
}

GtkBuilder в действии

Как известно, лучше всего изучать что-либо на конкретных примерах, чем мы и займемся. В качестве примера приведем приложение, которое умеет по нажатию на кнопку показывать слово "Hello", отображать информацию о себе и завершаться по нажатию на соответствующие кнопки. Интерфейс создан в Glade 3.6.7 в формате GtkBuilder. Вы можете воспользоваться готовым файлом example1.glade, но тут есть некоторые тонкости при работе с сигналами. Их следует обозначить, поскольку при создании собственных программ пользователь может столкнуться с нерабочими обработчиками событий.

Итак, виджеты могут реагировать на различные «раздражители внешней среды», например, кнопка может нажиматься или поле ввода приобретать/терять фокус и т.д. Чтобы отлавливать эти события в программе, программист пишет функции, называемые обработчиками. В Glade имя обработчика задается на панели Properties, во вкладке Signals. Имена событий достаточно "говорящие", т.е. например, понятно, что сигнал clicked обозначает нажатие на кнопку. Следующим в строке параметром задается обработчик – это просто имя callback-функции. Сигнатура у этой функции следующая: void <func_name>(GtkObject *object, gpointer user_data). Технически это выглядит следующим образом: в коде мы описываем функцию (с соответствующей сигнатурой), а в Glade просто указываем имя данной функции. После этого она будет вызываться по наступлению события, на которое мы ее "повесили". Только чтобы все работало, компоновщику необходимо передать параметр --export-dynamic.

Посмотрим на код приложения:

Листинг 3. Демонстрация GtkBuilder.
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <gtk/gtk.h>

GtkBuilder *builder;
GtkWidget  *window;
GtkWidget  *aboutdialog;
GtkWidget  *label;

void on_window_destroy (GtkObject *object, gpointer user_data)
{
    gtk_main_quit();
}

void on_click_about (GtkObject *object, gpointer user_data)
{
    gtk_widget_show_all (aboutdialog);
}

void on_close_about (GtkObject *object, gpointer user_data)
{
    gtk_widget_hide_all (aboutdialog);
}

void on_say_hello (GtkObject *object, gpointer user_data)
{
    gtk_label_set_text (label, "Hello!!!");
}


int main (int argc, char *argv[])
{

    gtk_init (&argc, &argv);

    builder = gtk_builder_new ();
    gtk_builder_add_from_file (builder, "example1.glade", NULL);

    gtk_builder_connect_signals (builder, NULL);

    window = GTK_WIDGET (gtk_builder_get_object (builder, "window1"));
    aboutdialog = GTK_WIDGET (gtk_builder_get_object (builder, "aboutdialog1"));
    label = GTK_WIDGET (gtk_builder_get_object (builder, "label2"));
    

    g_object_unref (G_OBJECT (builder));

    gtk_widget_show_all (window);
                   
    gtk_main ();

    return 0;
}

Собрать приложение и посмотреть на него можно, выполнив следующие действия:

  1. Сохраняем вышеприведенный код в файл под именем example1.c
  2. Помещаем этот файл и example1.glade в одну папку
  3. Находясь в этой папке, даем команду: gcc -Wall -export-dynamic -g example1.c -o example1 `pkg-config --cflags gtk+-2.0` `pkg-config --libs gtk+-2.0`
  4. Теперь, если все прошло успешно, запускаем нашу программу: ./example1.

Ошибки могут возникнуть из-за отсутствия в системе необходимых заголовочных файлов. В этом случае остается только отыскать эти файлы в нужных пакетах и доустановить их.

Теперь смотрим на функцию main(). Сперва вызывается функция gtk_init(); с этого начинается любое gtk-приложение. Далее, посредством вызова gtk_builder_new(void), создается структура GtkBuilder.

К вновь созданному объекту (технически правильнее будет написать «структуре», но в век объектно-ориентированного программирования для многих так будет привычнее) необходимо указать на описание интерфейса приложения. Сделать это можно двумя функциями: guint gtk_builder_add_from_file (GtkBuilder *builder, const gchar *filename, GError **error) и guint gtk_builder_add_from_string (GtkBuilder *builder, const gchar *buffer, gsize length, GError **error). Из имен функций можно понять, что первая из них принимает на вход имя файла, а вторая – строку, в которой содержится xml-разметка. Разумеется, первый вариант удобнее, т.к. позволяет без дополнительных манипуляций работать с Glade-файлами. Как именно работать с функцией gtk_builder_add_from_file можно посмотреть в исходном коде приложения. Все достаточно тривиально: первым параметром передается структура GtkBuilder, вторым – имя файла (абсолютный или относительный путь к нему) и третьим – структура GError, в которой может храниться описание возможной ошибки.

Структура GError выглядит следующим образом:

struct GError {
  GQuark       domain;
  gint         code;
  gchar       *message;
};

Хороший тон программирования предполагает, что разработчик после вызова соответствующей функции должен проверить наличие случившейся ошибки и корректным образом эту ситуацию обработать. В нашем же случае для простоты мы передаем NULL (при этом информация об ошибках возвращаться не будет).

Далее мы видим вызов очень важной функции: gtk_builder_connect_signals (builder, NULL). Она отвечает за соединение всех сигналов с их обработчиками, а именно теми функциями, которые мы указали при создании интерфейса в Glade. Первый параметр в вызове этой функции вам уже знаком, а второй – это данные, которые будут переданы в обработчик. Из сигнатуры, которая была приведена выше, void <func_name>(GtkObject *object, gpointer user_data) видно, что эти данные будут доступны под именем user_data. Более продвинутый вариант этой функции void gtk_builder_connect_signals_full (GtkBuilder *builder, GtkBuilderConnectFunc func, gpointer user_data) позволяет передавать различным обработчикам различные параметры. Ее использование несколько сложнее, но представление об этом процессе можно получить, взглянув на описание структуры GtkBuilderConnectFunc:

void (*GtkBuilderConnectFunc)(GtkBuilder *builder,
          GObject *object,
          const gchar *signal_name,
          const gchar *handler_name,
          GObject *connect_object,
          GConnectFlags flags,
          gpointer user_data);

Наиболее интересные параметры здесь — signal_name и handler_name, которые соответственно задают событие и имя функции, которая на это событие будет реагировать. За более детальными разъяснениями отправляю вас к справке.

И вот мы подошли к gtk_builder_get_object(GtkBuilder *builder, const gchar *name). Наверное, вызов этой функции можно назвать чертой, которая отделяет работу с Glade и программирование в чистом GTK+. Эта функция возвращает объект GObject. Имя этого объекта задается в Glade, в нашем примере это "window1 и "aboutdialog1" (варианты по умолчанию). При помощи макроса GTK_WIDGET результат приводится к GtkWidget.

Вот, собственно, и все. Далее от разработчика требуется умение работать с библиотекой GTK+ как таковой. В оставшейся части кода мы освобождаем память, занимаемую GtkBuilder(g_object_unref (G_OBJECT (builder))), отрисовываем все элементы на форме (gtk_widget_show_all (window)) и запускаем gtk-приложение на выполнение(gtk_main()). Думаю, return 0 объяснять не нужно.

Заключение

В статье были рассмотрены основные принципы работы с GtkBuilder. Надо отметить значительно более удобный подход, представленный в Glade 3 по сравнению со второй версией. Отказ от libglade также можно назвать оправданным. Как минимум, уменьшается количество библиотек. Но хотя libglade и признана устаревшей, переписывать старые приложения никто не заставляет.

Также читатель должен заметить, что GtkBuilder упрощает разработку оконных приложений лишь до определенного уровня: разбираться в библиотеке GTK+ все равно нужно достаточно неплохо. Впрочем, примерно до этого уровня упрощают разработку все среды подобные Visual Studio или Delphi. Glade остается только объединить подходы используемые во второй и в третьей версиях: большую часть кода, которую мы написали в нашем демонстрационном приложении, можно было бы сгенерировать автоматически.


Ресурсы для скачивания


Похожие темы


Комментарии

Войдите или зарегистрируйтесь для того чтобы оставлять комментарии или подписаться на них.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Linux, Open source
ArticleID=754864
ArticleTitle=Использование GtkBuilder
publish-date=08302011