gtk sharp что это

Введение

GTK+ (сокращение от GIMP ToolKit) — кроссплатформенная библиотека элементов интерфейса. Наряду с Qt является одной из двух наиболее популярных на сегодняшний день библиотек для X Window System.
Будучи изначально частью графического редактора GIMP, она развилась в отдельный проект и приобрела заметную популярность. GTK+ — свободное ПО, распространяемое на условиях GNU LGPL, позволяющей создавать как свободное, так и проприетарное программное обеспечение с использованием библиотеки. GTK+ является официальной библиотекой для создания графического интерфейса проекта GNU.

Глава 1. Основы GTK+

Начало

Исходный код GTK содержит все примеры приведенные в данном руководстве, а также Makefiles для упрощенной компиляции.

Для начала мы рассмотрим пример самой простой программы на GTK. Эта программа создает окно размером 200×200 pixel и не совершает никаких действий кроме как выход после ввода соответствующей команды shell.

Вы можете скомпилировать программу используя компилятор gcc:

О возможных вариантах компиляции объясняется ниже в Компиляция Hello World.

Все программы будут конечно включать заголовочный файл gtk/gtk.h, который объявляет переменные, функции, структуры, и т.д. использующиеся в вашей GTK программе.

вызов функции gtk_init(gint *argc, gchar ***argv) которая используется во всех GTK программах. Она создает установки визуальной и цветовой карты, а также запускает процесс вызова функции gdk_init(gint *argc, gchar ***argv). Эта функция инициализирует библиотеки для использования, устанавливает по умолчанию обработчики сигналов, и проверяет аргументы командной строки вашей программы, производя поиск одного из следующих:

Проходя по списку происходит поиск объявленных аргументов вашей программы для дальнейшего разбора или игнорирования. Так создаётся ряд стандартных аргументов для всех GTK программ.

Следующие две строчки кода выводят на дисплей окно программы.

Аргумент GTK_WINDOW_TOPLEVEL определяет специфику расположения и оформления окна в менеджере окон. Чтобы не создавалось окно размером 0x0, по умолчанию принят размер 200×200 для всех дочерних окон, вы также можете манипулировать этими значениями.

Функция gtk_widget_show() позволяет GTK понять какие параметры мы установили для виджетов и правильно отобразить их.

Последняя строка вводит в главный цикл GTK процесса (main processing loop).

gtk_main() ещё один вызов который используется в любой программе GTK. Когда программа доходит до этого вызова, GTK начинает ожидать X события (такого как нажатие кнопки мыши или клавиатуры), прерывания, или файлового ввода вывода. Однако в нашем простом примере никаких событий не ожидается.

Hello World в GTK

Еще одна программа в виде окна с кнопкой. Это классический «hello world» с использованием GTK.

Компиляция Hello World

Для компиляции воспользуйтесь командой:

Обратите внимание что данный тип команды существенен для компиляции.

Библиотеки которые обычно нужны для связки (linked):

Xlib library (-lX11) используется GDK.

Теория Сигналов и Обратных вызовов

В версии 2.0, система сигналов перемещена из GTK в GLib, поэтому функции и типы в этой секции имеют приставку «g_» а не «gtk_». Сдесь не говорится о расширениях системы сигналов GLib 2.0 по сравнению с системой сигналов GTK 1.2.

Такой контроль выполняется с использованием идеи сигналов (idea of «signals»). (Учтите что эта система сигналов не тоже самое что система сигналов Unix, хотя используется идентичная терминология). Когда происходит событие, такое как нажатие кнопки мыши, виджет создаёт («emitted») сигнал соответствующий нажатию. Так GTK выполняет большинство своих действий. Есть сигналы которые наследуют все виджеты, например сигнал закрытия («destroy»), а есть специфические сигналы, например сигнал кнопки переключения («toggled»).

Чтобы заставить кнопку работать, нужно настроить обработчик сигналов, который при возникновении события запустит функцию.
Это делается так:

Функция определенная в третьем аргументе должна иметь общую форму:

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

Другой вызов использованный в примере helloworld:

g_signal_connect_swapped() тоже самое, что g_signal_connect() только в качестве единственного аргумента используется указатель на GTK объект. Для использования этой функции вызова сигнала, обратный вызов должен иметь форму

где объектом обычно является виджет. Обычно обратный вызов не устанавливается для g_signal_connect_swapped(). Они обычно используются в вызовах GTK функций которые принимают как единственный аргумент сигнал виджета или объект, что и показано в примере helloworld.

Наличие двух функций вызова сигналов объясняется необходимостью обратным вызовам иметь разное количество аргументов. Многие функции в библиотеке GTK принимают только указатель GtkWidget как единственный аргумент, таким образом используя g_signal_connect_swapped() в ваших функциях, вам могут понадобится расширенные данные обратных вызовов.

События

В дополнение к механизму сигналов, описанному выше, есть ряд событий, которые отражают механизм событий X. Обратные вызовы также могут быть связаны с событиями. Вот эти события:

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

GdkEvent это C объединение(union) структур, тип которых зависит от выбранного события. Для того чтобы понять какое событие произошло каждая из возможных альтернатив имеет свой тип, который отражает произошедшее событие. Многие компоненты структуры событий зависят от типа события. Возможные варианты типов событий:

Так, для ассоциации функции обратного вызова с событием можно использовать следующее:

Это предполагает что кнопка(button) это кнопка виджета (Button widget). Когда курсор находится на кнопке и кнопка мыши нажата, то вызывается функция button_press_callback(). Эта функция может быть объявлена так:

Читайте также:  microsoft office 2021 что нового

Обратите внимание, что мы можем объявить второй аргумент как тип GdkEventButton, поскольку мы знаем, какое событие произойдет для той функции, которая будет вызвана.

Значение возвращенное функцией указывает механизму обработки событий GTK о дальнейших действиях. Возвращенное TRUE указывает на прекращение дальнейшего выполнения события. Возвращенное FALSE продолжает нормальное выполнение события. Для более подробной информации смотрите секцию Advanced Event and Signal Handling.

Детально типы данных GdkEvent, рассматриваются в GDK Event Types.

GDK selection и drag-and-drop APIs также создают множество событий которые отражены сигналами GTK. Смотрите Signals on the source widget и Signals on the destination widget для детального изучения функций обратного вызова сигналов:

Пошаговое изучение Hello World

Теперь рассмотрим теорию на примере программы helloworld.

Начнем с функции обратного вызова которая вызывается при нажатии на кнопку («clicked»). Мы игнорируем и виджеты и данные в этом примере, но не трудно понять что они делают. В следующем примере мы будем использовать данные аргументов для определения того, какая кнопка была нажата.

Следующий обратный вызов (callback) является специальным. «delete_event» происходит когда оконный менеджер сообщает об этом событии программе. Мы можем выбирать что сделать с этим событием. Проигнорировать его, создавая своего рода ответ, или просто выйти из программы.

Значение которое вы возвращаете в данном обратном вызове (callback) сообщает GTK какое действие выполнить. Возвращая TRUE, мы сообщаем что не хотим создать сигнал «закрыть» («destroy»), продолжая выполнение нашей программы. Возвращая FALSE, мы создаем сигнал «закрыть» («destroy»), который будет выполнен обработчиком сигналов.

Вот другая функция обратного вызова которая сообщает программе о выходе calling gtk_main_quit(). Когда контроль переходит к ней, она сообщает GTK о том, что нужно прекратить выполнение gtk_main.

Как вы знаете, все программы имеют функцию main(), GTK программы тоже не являются исключением.

Следующие строки объявляют указатели на структуры имеющих тип GtkWidget. Они используются для создания окна и кнопки.

И снова наш gtk_init(), как и прежде инициализирует набор инструментов, и разбирает найденные аргументы командной строки. Любой аргумент не входящий в список допустимых для gtk_init() передаётся для дальнейшего разбора вашей программой.

Создание нового окна, достаточно прямолинейно. Память распределяется для указателя GtkWidget *window таким образом указатель становится структурой. Окно создается, но оно не будет показано на дисплее пока мы не вызовем gtk_widget_show(window) функцию в нашей программе.

Вот два примера вызова обработчика сигналов для объекта, в данном случае окна. Здесь перехватываются сигнал «delete_event» и «destroy». Первый создается когда мы ипользуем менеджер окон для закрытия окна (window), или когда мы используем в окне объект который вызывает gtk_widget_destroy(). Второй создается когда, в обработчик «delete_event», возвращается FALSE. Макросы G_OBJECT и G_CALLBACK проводят преобразование типов, а также делают код более удобочитаемым.

Следующая функция используется для установки атрибутов объекта контейнер. Это окно имеет внутренний контур в 10 pixels в который не входит не один виджет. Есть и другие похожие функции которые будут рассмотрены в секции Setting Widget Attributes

И снова макрос GTK_CONTAINER для преобразования типа.

Этот вызов создаёт новую кнопку. Выделяет память для новой структуры GtkWidget, инициализирует и создаёт указатель на кнопку. Она будет иметь ярлык «Hello World».

Теперь мы попробуем заставить кнопку выполнить что-нибудь полезное. Когда обработчик сигналов получает сигнал «clicked», то вызывается функция hello(). Данные игнорируются, таким образом обратным вызовом функции hello() будет NULL. Очевидно, что сигнал «clicked» возникает при нажатии кнопки мыши.

Можно также использовать эту кнопку для выхода из программы. Это иллюстрирует что сигнал «destroy» может быть вызван, как менеджером окон, так и нашей программой.

Вы можете иметь сколько нужно функций обратного вызова (callback functions), все они будут выполнены после вызова. Поскольку функция gtk_widget_destroy() принимает только указатель GtkWidget *widget как аргумент, мы используем здесь функцию g_signal_connect_swapped() вместо straight g_signal_connect().

Упаковочные вызовы обсуждаются позже в Packing Widgets. Здесь просто сообщается GTK, что кнопка должна размещаться внутри окна в момент отображения. Заметьте, что контейнер GTK может содержать только один виджет. Есть другие виджеты, которые обсуждаются позже, разработанные для многократного размещения виджетов.

Теперь мы настроили всё необходимое. Нужно чтобы GTK мог показать все окно, кнопки с прикрепленными обработчиками сигналов и другие виджеты. Для того, чтобы всё окно отображалось сразу со всеми виджетами, его нужно вызывать для отображения последним, иначе при сложных интерфейсах может возникнуть эффект прорисовки виджетов на фоне пустого окна.

И конечно мы запускаем функцию gtk_main() которая ожидает событий X server и при возникновении таковых запускает соответствующие виджеты.

И заключительный вызов после gtk_quit().

Теперь когда мы нажимаем на кнопку мыши, виджет GTK button создаёт сигнал «clicked». Эту информацию можно использовать для настройки обработчика сигнала таким образом, чтобы он запускал функции соответственно вашего выбора. В нашем примере при создании сигнала «clicked», запускается функция hello() с пустым аргументом NULL, а затем вызывает следующего обработчика сигналов, который запускает функцию gtk_widget_destroy() с аргументами для закрытия основного окна программы. Она создаёт сигнал «destroy», который вызывает функцию обратного вызова destroy() для простого выхода из GTK программы.

Читайте также:  с каким гарниром приготовить утку

Другой вариант, использовать менеджер окон для закрытия программы при помощи события «delete_event». Если в обработчик события «delete_event», возвратить TRUE, то ничего не произойдет и окно останется открытым. Возвращенное FALSE заставит GTK создать сигнал «destroy» и выйти из GTK программы.

Типы данных

Вы наверное заметили некоторые моменты в предыдущих примерах, требующие объяснения. В системе GLib существуют собственные типы данных такие, как gint, gchar и т.д. эти типы являются аналогами типов в языке программирования С. Это сделано для преодоления зависимости от платформы при выполнении расчетов.

Хорошим примером является «gint32» который определяет тип целого числа размером 32 bit на любой платформе, например 64 bit alpha, или 32 bit i386. Определения типов являются интуитивными и прямолинейными. Они все определены в glib/glib.h (который включен в gtk.h).

Вы также заметили использование GtkWidget когда функция обращается к GtkObject. GTK имеет объектно ориентированный дизайн с использованием виджетов (widget) как объектов (object).

Подробнее об обработчиках сигналов

Вот вариант объявления функции g_signal_connect().

Обратите внимание, возвращаемое значение имеет тип gulong? Это ярлык идентификации вашей функции обратного вызова. Как упоминалось выше, вы можете вызывать любое количество сигналов на объект и все они будут созданы в порядке очереди прикрепления.

Данный ярлык, позволяет вам удалять сигнал при использовании:

При прохождении виджета вы можете отключить обработчик, вернув в функцию (signal_connect functions) пустое значение.

Вы также можете временно отключать обработчики сигналов из родственных функций g_signal_handler_block() и g_signal_handler_unblock().

Обновленный Hello World

Давайте рассмотрим helloworld с улучшенными примерами обратных вызовов. Это приблизит нас к следующей теме, упаковочные виджеты (packing widgets).

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

Упаковочные виджеты (Packing Widgets)

При создании графических интерфейсов необходимо размещать большое кол-во виджетов внутри диалоговых окон. Первый пример helloworld имел только один виджет, поэтому мы могли использовать вызов gtk_container_add() для размещения его внутри окна. Когда вам понадобится размещать в окне больше одного виджета, нужно будет каким-то образом контролировать их расположение. Для этого и нужны упаковочные контейнеры.

Теория упаковочных контейнеров (Packing Boxes)

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

Для создания нового горизонтального контейнера используется вызов gtk_hbox_new(), а для вертикального gtk_vbox_new(). Функции gtk_box_pack_start() и gtk_box_pack_end() используются для размещения объектов внутри этих контейнеров. Функция gtk_box_pack_start() размещает объекты сверху вниз в вертикальных контейнерах и слева на право в горизонтальных, а функция. gtk_box_pack_end() соответственно снизу вверх и справа на лево. Эти функции позволяют нам использовать правое или левое, а также верхнее или нижнее выравнивание виджетов и даже смешанное для достижения необходимого результата. В большинстве примеров мы используем gtk_box_pack_start(). Любой объект или виджет может выступать в роли контейнера. Кнопка фактически тоже является контейнером, но мы размещаем в ней только надпись для обозначения.

При использовании этих вызовов, GTK узнаёт где размещаются ваши виджеты и может автоматически регулировать размер, а также выполнять другие полезные действия. Есть и другие методы упаковки ваших виджетов, если вы думаете что данный метод даёт слишком мало гибкости при создании и размещении виджетов.

Детально о контейнерах

Поначалу из за гибкости упаковок в GTK можно запутаться. Существующие варианты не всегда являются очевидными. Однако в общей сложности существует пять различных стилей упаковки, в которых нам нужно разобраться.

Каждая линия содержит горизонтальный контейнер (hbox) который содержит кнопки. Вызов gtk_box_pack упаковывает кнопки в контейнер hbox. Каждая кнопка упакованная в hbox имеет одинаковые аргументы для функции gtk_box_pack_start().

Вот объявление gtk_box_pack_start() функции.

Расширяющие аргументы в gtk_box_pack_start() и gtk_box_pack_end() контролируют размер пространства которое занимает контейнер или виджет в контейнере, если (TRUE) то заполняется всё доступное пространство; или (FALSE), тогда контейнер сжимается до уровня необходимого для вмещения виджетов. Установка расширения в FALSE оправдана при правом и левом выравнивании виджетов. Иначе они растянутся на всю ширину контейнера, а такой же эффект можно получить при использовании gtk_box_pack_start() или gtk_box_pack_end().

Аргумент заполнения в функции gtk_box_pack контролирует, выделено ли дополнительное место для расширения объектов (TRUE), или как дополнительное пространство для объекта (FALSE). Это имеет смысл, только если расширяющий аргумент равен TRUE.

Новый контейнер создаётся примерно так:

Аргумент homogeneous в gtk_hbox_new() (и некоторые для gtk_vbox_new()) контролирует равноценность размеров объектов в контейнерах (т.е., одинаковую ширину в hbox, или одинаковую высоту в vbox). Если он установлен, то расширяющий аргумент всегда включен в шаблон функции gtk_box_pack().

Свободное пространство добавляется перед объектами и вокруг них. Следующий пример объясняет это:

Демонстрационная программа упаковки

Краткий обзор виджетов

Основные действия для создания GTK виджетов:

Читайте также:  при получении какого сообщения сигнализации dss1 вызывающий абонент услышит сигнал кпв

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

Установка атрибутов виджетов.

Упаковка виджетов в контейнер, используя соответствующий запрос, типа gtk_container_add() или gtk_box_pack_start().

Вывод виджета на экран gtk_widget_show().

gtk_widget_show() позволяет GTK выводить виджеты согласно установленным атрибутам. Для скрытия виджетов можно использовать gtk_widget_hide. Порядок вывода виджетов на экран не важен, но лучше выводить основное окно последним чтобы все виджеты в окне отображались одновременно, а не появлялись по мере их формирования. Дочерние виджеты не отображаются до тех пор, пока не показано основное для них окно с помощью функции gtk_widget_show().

Преобразование типов

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

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

Здесь кнопка преобразуется в объект, и выполняется преобразование указателя функции в обратный вызов.

Многие виджеты являются контейнерами. Если вы посмотрите в иерархии классов ниже, то заметите, что много виджетов происходят из контейнерного класса. Любой из этих виджетов может использоваться с макросом GTK_CONTAINER, чтобы передать их в функции, которые запрашивают контейнеры.

К сожалению невозможно рассказать о всех макросах в данном руководстве, поэтому я рекомендую вам изучить заголовочные файлы GTK (header files) или GTK API reference manual. Это может быть очень познавательно. Фактически можно понять как работают виджеты изучая декларации функций.

Иерархия виджетов

Иерархическое дерево виджетов. (Вспомогательные классы и неподдерживаемые виджеты были пропущены.)

Вне оконные виджеты

Виджеты не асоциированные с окнами. Когда вы хотите перехватить событие, вы должны использовать виджет EventBox. Подробности в разделе EventBox widget.

Обычные кнопки

Вы уже много раз видели процесс создания виджетов. Это довольно просто. Есть несколько способов создавать кнопки. Вы можете использовать gtk_button_new_with_label() или gtk_button_new_with_mnemonic() чтобы создать кнопку с ярлыком, или используйте gtk_button_new_from_stock (), чтобы создать кнопку, содержащую изображение и текст. Или gtk_button_new(), чтобы создать чистую кнопку, в которую вы сможете упаковать ярлык или pixmap(картинку). Для этого нужно создать контейнер, упаковать в этот контейнер необходимый объект используя gtk_box_pack_start(), и с помощью gtk_container_add() упаковать контейнер в кнопку.

Вот пример мспользования gtk_button_new(), для создания кнопки с изображением и текстом внутри. Я отделил код создания контейнера от остального, вы можете поступать также в своих программах. Дальше в этом руководстве будут приведены ещё примеры использования изображений.

Функция xpm_label_box() может быть использована для упаковки изображений и надписей в любой виджет способный выступать в роли контейнера.

Виджет кнопка, имеет следующие сигналы:

Переключатель (Toggle Buttons)

Переключатели являются основой для контроль-кнопок (check buttons) и для радио-кнопок (radio buttons), поэтому многие вызовы используемые для переключателей действительны и для них. Об этом чуть позже.

Как вы понимаете, они создаются тождественно нормальным кнопкам. В первой строке создается переключатель а в следующих двух, надпись(ярлык) которая в него упаковывается.

Изменить состояние переключателя и его дочерних виджетов контроль-кнопки или радио-кнопки можно используя функцию:

Заметьте, при использовании функции gtk_toggle_button_set_active(), состояние изменяется и кнопка производит сигналы «clicked» и «toggled».

Это возвращает текущее состояние кнопки переключателя как значение (boolean) TRUE/FALSE.

Контроль-кнопка или «флажок» (Check Buttons)

Контроль-кнопки наследуют большинство функций и свойств переключателей, но имеют немного другой вид. Они имеют вид небольшой области для отметки с текстом справа. Они чаще всего используются для включения или выключения опций программы.

Для создания используется функция подобная созданию переключателя:

Функция gtk_check_button_new_with_label() создаёт контроль-кнопку с расположенным рядом текстовым ярлыком.

Проверка состояния идентична проверки состояния переключателя.

Кнопки выбора или «радио-кнопка» (Radio Buttons)

Кнопки выбора подобны контроль-кнопкам за исключением того, что они создаются группами и в отдельно взятый момент времени может быть выбрана только одна из них. Это удобно там где нужно выбирать из нескольких возможных взаимоисключающих вариантов.

Создание кнопок выбора выполняется одним из этих вызовов:

Вы заметили наверное, что функции содержат дополнительные аргументы. Это нужно для выполнения группой кнопок выбора их обязанности должным образом. Если первый вызов gtk_radio_button_new() или gtk_radio_button_new_with_label() должен содержать NULL в качестве первого аргумента, то используйте:

Важно помнить, что gtk_radio_button_get_group() вызывается каждый раз, когда нужно добавить кнопку выбора в группу, используя в качестве аргумента предыдущую кнопку выбора. Результат передаётся в следующий вызов gtk_radio_button_new() или gtk_radio_button_new_with_label(). Это позволяет связать цепь кнопок выбора. Пример ниже проесняет это.

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

Варианты с _from_widget() позволяют создавать сокращенные функции в будущем, опуская вызов gtk_radio_button_get_group(). Эта форма используется для создания третьей кнопки в следующем примере:

Также хорошей идеей может быть установка по умолчанию определяющая выбранную кнопку:

Это описано в секции о переключателях и работает таким же образом. Как только кнопки выбора сгруппированы, только одна из них может быть выбрана. Если пользователь нажмет сначала на одну кнопку выбора, а затем на другую, то первая создаст сигнал «toggled» (сообщит о переходе в неактивное состояние), а вторая создаст «toggled» сигнал сообщая об активизации.

Пример создания группы из трёх кнопок выбора.

Глава 2. gtkmm

Основные возможности gtkmm:

Источник

Сказочный портал