Попробуем коротко описать понятие виджета GTK. При изучении программирования на GTK необходимо понимать, что такое "программирование на Си в объектно-ориентированной манере". Речь идет не о объектном Си (языке программирования Objective C), а о об написании программ на "обычном" языке Си, но держа при этом написании в уме основные концепции ООП.
Объектно-ориентированный Си
- Объектно-ориентированное программирование - это всего лишь метод организации данных и кодов. Библиотеки GNOME и GTK+ написаны на С, и их API состоит только из вызовов функций С. Тем не менее, код написан в объектно-ориентироанном стиле. Объектная ориентация не является частью языка С и ее пришлось имитировать. Имеется несколько характеристик объектов, относящихся к GNOME и GTK+, самыми важными из которых следует считать инкапсуляцию, наследование и методы.
- Доступ к инкапсулированной информации может быть получен только посредством обращений к функциям, специально разработанным для этих целей. Эти функции называются методами.
- Код, описывающий объект, называтся классом. Класс, из которого образуется другой класс, называется базовым. Все классы изначально происходят из GtkObject. Каждая структура включает в виде первого элемента полную структуру своего базового класса.
- Для создания нового объекта используется метод. Все создающие объект функции имеют в своем имени слово new. Обычно функции, создающие какой-либо виджет (кнопку, чекбокс и т.п.), возвращает указатель на структуру GtkWidget, а не структуру кнопки или чекбокса. Это возможно благодаря полиморфизму. Полиморфизм означает, что любой объект может рассматриваться в качестве одного из своих базовых классов.
- Когда вызывается метод для работы с существующим объектом, адрес этого объекта передается как первый аргумент.
- Методы всех классов в иерархии вызываются при использовании специальных макросов приведения типов данных. Для каждого виджета в GNOME и GTK+ имеется макрос приведения типов данных. Эти макросы делают несколько больше, чем просто приведение типов: во время работы приложения удостоверяют правильность приведения типов.
Последовательность диспетчеризации событий.
- Происходит событие.
- Соответствующая информация отправляутся менеджеру окон.
- Менеджер окон имеет адрес очереди событий для каждого окна. Он преобразовывает полученные данные в стандартный для Х формат и ставит их в очередь, связанную с окном в которое послано событие.
- Главный цикл приложения использует низкоуровневую функцию системы Х для чтения событий из очереди. По идентификатору окна, присланному вместе с сообщением, программа определяет, какой из виджетов должен получить сигнал. Затем однп из функций GTK+ преобразует информацию в сигнал и передает его виджету.
- Для каждого виджета существует функция, которая получает все поступающие сигналы.
- Виджет просматривает список функций обратного вызова, которые связаны с определенным сигналом, и вызывает все эти функции.
Для создания сигнала можно применять функции g_signal_emit() g_signal_emit_by_name(). Соответствующие функции с префиксом gtk_ вместо g_ устарели и не рекомендуются для применения в "свежем" коде.Каждая функция обратного вызова имеет два общих параметра, но многие из функций имеют еще дополнительные параметры. Прототип самой простой функции обратного вызова выглядит так:
void cb(GtkWidget*, gpointer);
Если имеются дополнительные параметры, то они вставляются между двумя параметрами этого прототипа. Также кроме пустого типа могут возвращаться типы gint и boolean. На самом нижнем уровне создание события - это создание события Xevent. Xevent содержит тег, идентифицирующий окно, для которого это событие предназначено. Каждому событию соответствует своя структура. Каждая структура определена в виде двух частей. Первая - это собственно сама структура, а вторая - оператор typedef для этой структуры. Имена различаются только первым символом: имя структуры начинается символом подчеркивания.GdkEvent - это объединение нескольких структур событий. Чтобы облегчить задачу определения типа события и соответствующей ей структуры, первым полем во всех структурах является поле type. Для доступа к данным события напрямую можно выполнить приведение типа объединения к типу структуры. Какое именно приведение надовыполнить определяем из поля type.Информация о каждом событии содержится в структуре GSignalQuery. Ее поля заполняются с помощью функции g_signal_query().
typedef struct {
guint signal_id;
const gchar *signal_name;
GType itype;
GSignalFlags signal_flags;
GType return_type; /* mangled with G_SIGNAL_TYPE_STATIC_SCOPE flag */
guint n_params;
const GType *param_types; /* mangled with G_SIGNAL_TYPE_STATIC_SCOPE flag */
} GSignalQuery;
У каждого виджета есть внутренние установки, которые прикладная
программа может читать или записывать.Приложению необходим интерфейс для
обращения к этим установкам (аргументам) внутри указанного виджета. То
есть, чтобы прочитать или записать одно из этих значений, программа
должна знать имя виджета, имя переменной и тип данных этой переменной.
Итак, каждый аргумент имеет тип данных и права чтения/записи.
Большинство аргументов имеют права и чтения и записи.Есть два способа
установить значение аргументв внутри виджета.Есть фунции, закрепленные к
определенному аргументу, который можно изменять с помощью этой функции.
Соответственно есть фукция для чтения этого аргумента.Второй способ
заключается в использовании структуры GtkArg, у которой три поля: GtkType
- определяет тип данных, указательна строку, определяющую имя
аргумента, и объединение различных типов данных.Когда виджет рождается и
проходит свой путь от шаблона бит в памяти до графического объекта на
экране, то происходят процессы создания, реализации, преобразования и
отображения. При уничтожении виджета происходят: скрывание, уничтожение
соответствия, деактивизация и разрушения. Виджет может скрываться и
появляться вновь. При перемещении из одного окна в другое происходят
уничтожение реализации, а потом реализация.Указанным этапам
соответствуют такие функции:
*_new()У виджетов есть также до пяти так называемых стилей (состояний):
gtk_widget_destroy()
gtk_widget_unref()
gtk_widget_show()
gtk_widget_hide()
gtk_widget_map()
gtk_widget_unmap()
gtk_widget_realize()
gtk_widget_unrealize()
GTK_STATE_NORMALДля первого "философского" понимания, что такое виджет GTK - этого достаточно.
GTK_STATE_ACTIVE
GTK_STATE_PRELIGHT
GTK_STATE_SELECTED
GTK_STATE_INSENSITIVE