gulong g_signal_connect(gpointer *object, const gchar *name,
GCallback func, gpointer user_data);
Следует отметить, что для связывания функций обратного вызова нет ограничений. Вы можете иметь много сигналов, связанных с одной и той же функцией обратного вызова, и много функций обратного вызова, связанных с единственным сигналом.
В документации по API GTK+ можно найти подробное описание сигналов, порождаемых каждым виджетом.
До появления GTK+ 2 для связывания функций обратного вызова применялась функция gtk_signal_connect. Она была заменена функцией g_signal_connect и не должна применяться во вновь разрабатываемом программном коде.
Вы опробуете функцию g_signal_connect в упражнении 16.2.
В программе gtk2.c вставьте в свое окно кнопку и свяжите сигнал clicked (щелчок мышью по кнопке) с вашей функцией обратного вызова для вывода короткого сообщения:
#include <gtk/gtk.h>
#include <stdio.h>
static int count = 0;
void button_clicked(GtkWidget *button, gpointer data) {
printf("%s pressed %d time(s) \n", (char *)data, ++count);
}
int main(int argc, char* argv[]) {
GtkWidget *window;
GtkWidget *button;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
button = gtk_button_new_with_label("Hello World!");
gtk_container_add(GTK_CONTAINER(window), button);
g_signal_connect(GTK_OBJECT(button), "clicked",
GTK_SIGNAL_FUNC(button_clicked), "Button 1");
gtk_widget_show(button);
gtk_widget_show(window);
gtk_main();
return 0;
}
Введите исходный текст программы и сохраните его в файле с именем gtk2.c. Откомпилируйте и скомпонуйте программу аналогично программе gtk1.с из предыдущего упражнения. Запустив ее, вы получите окно с кнопкой. При каждом щелчке кнопки мышью будет выводиться короткое сообщение (рис. 16.5).
Рис. 16.5
Как это работает
Вы добавили два новых элемента в программу gtk2.c: виджет GtkButton и функцию обратного вызова. GtkButton — это виджет простой кнопки, которая может содержать текст, в нашем случае "Hello World", и порождает сигнал, названный clicked, каждый раз, когда кнопку щелкают мышью.
Функция обратного вызова button_clicked связана с сигналом clicked виджета кнопки с помощью функции g_signal_connect:
g_signal_connect(GTK_OBJECT(app), "clicked",
GTK_SIGNAL_FUNC(button_clicked), "Button 1");
Обратите внимание на то, что имя кнопки — "Button 1" — передается в функцию обратного вызова как данные пользователя.
Весь остальной добавленный программный код касается виджета кнопки, создаваемой так же, как окно — вызовом функции gtk_button_new_with_label — функция gtk_widget_show делает ее видимой.
Для расположения кнопки в окне вызывается функция gtk_container_add. Эта простая функция помещает GtkWidget внутрь объекта GtkContainer и принимает контейнер и виджет как аргументы:
void gtk_container_add(GtkContainer* container, GtkWidget *widget);
Как вы уже знаете, GtkWindow — потомок или дочерний объект объекта GtkContainer. поэтому вы можете привести тип вашего объекта-окна к типу GtkContainer с помощью макроса GTK_CONTAINER:
gtk_container_add(GTK_CONTAINER(window), button);
Функция gtk_container_add прекрасно подходит для расположения в окне одиночного виджета, но гораздо чаще вам потребуется для создания хорошего интерфейса размещать несколько виджетов в разных частях окна. У комплекта GTK+ есть специальные виджеты как раз для этой цели, именуемые виджетами упаковочных контейнеров,
Виджеты упаковочных контейнеров
Компоновка GUI исключительно важна для удобства применения интерфейса, и добиться наилучшей компоновки труднее всего. Реальная трудность в размещении виджетов заключается в том, что вы не можете полагаться на наличие у всех пользователей одинаковых размеров окон, тем, шрифтов и цветовых схем. То, что может быть отличным интерфейсом для одной системы, в другой системе может оказаться просто нечитаемым.
Для создания GUI, который выглядит одинаково во всех системах, вам необходимо избегать размещения виджетов на основе абсолютных координат и использовать более гибкую систему компоновки. У GTK+ есть для этой цели виджеты контейнеров. Виджеты-контейнеры позволяют управлять компоновкой виджетов в окнах вашего приложения. Виджеты упаковочных контейнеров (box) представляют очень удобный тип виджета-контейнера. GTK+ предлагает множество виджетов-контейнеров других типов, описанных в интерактивной документации к GTK+.
Виджеты упаковочных контейнеров — невидимые виджеты, задача которых — хранить другие виджеты и управлять их компоновкой или схемой размещения. Для управления размером отдельных виджетов, содержащихся в виджете упаковочного контейнера, вы задаете правила вместо координат. Поскольку виджеты упаковочных контейнеров могут содержать любые объекты GtkWidget и объект GtkBox сам является объектом типа GtkWidget, для создания сложных компоновок можно формировать виджеты упаковочных контейнеров, вложенные один в другой.
У типа GtkBox существуют два основных подкласса:
□ GtkHBox — однострочный горизонтальный упаковочный контейнер;
□ GtkVBox — одностолбцовый вертикальный упаковочный контейнер.
После создания упаковочных контейнеров следует задать два параметра: homogeneous и spacing:
GtkWidget* gtk_hbox_new(gboolean homogeneous, gint spacing);
GtkWidget* gtk_vbox_new(gboolean homogeneous, gint spacing);