среда, 21 августа 2013 г.

Понятие виджетов GNOME/GTK+

Попробуем коротко описать понятие виджета GTK. При изучении программирования на GTK необходимо понимать, что такое "программирование на Си в объектно-ориентированной манере". Речь идет не о объектном Си (языке программирования Objective C), а о об написании программ на "обычном" языке Си, но держа при этом написании в уме основные концепции ООП.

Объектно-ориентированный Си

  • Объектно-ориентированное программирование - это всего лишь метод организации данных и кодов. Библиотеки GNOME и GTK+ написаны на С, и их API состоит только из вызовов функций С. Тем не менее, код написан в объектно-ориентироанном стиле. Объектная ориентация не является частью языка С и ее пришлось имитировать. Имеется несколько характеристик объектов, относящихся к GNOME и GTK+, самыми важными из которых следует считать инкапсуляцию, наследование и методы.
  • Доступ к инкапсулированной информации может быть получен только посредством обращений к функциям, специально разработанным для этих целей. Эти функции называются методами.
  • Код, описывающий объект, называтся классом. Класс, из которого образуется другой класс, называется базовым. Все классы изначально происходят из GtkObject. Каждая структура включает в виде первого элемента полную структуру своего базового класса.
  • Для создания нового объекта используется метод. Все создающие объект функции имеют в своем имени слово new. Обычно функции, создающие  какой-либо виджет (кнопку, чекбокс и т.п.), возвращает указатель на структуру GtkWidget, а не структуру кнопки или чекбокса. Это возможно благодаря полиморфизму. Полиморфизм означает, что любой объект может рассматриваться в качестве одного из своих базовых классов.
  • Когда вызывается метод для работы с существующим объектом, адрес этого объекта передается как первый аргумент.
  • Методы всех классов в иерархии вызываются при использовании специальных макросов приведения типов данных. Для каждого виджета в GNOME и GTK+ имеется макрос приведения типов данных. Эти макросы делают несколько больше, чем просто приведение типов: во время работы приложения удостоверяют правильность приведения типов.
При программировании на  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_STATE_ACTIVE
GTK_STATE_PRELIGHT
GTK_STATE_SELECTED
GTK_STATE_INSENSITIVE
Для первого "философского" понимания, что такое виджет GTK - этого достаточно.

Комментариев нет: