Руководство программиста в Photon (1037671), страница 66
Текст из файла (страница 66)
Когда виджет реализован, он использует значения своих ресурсов, чтобы определить, насколько большим он должен быть, чтобы отобразить своё содержание. Перед реализацией виджета Вы должны установить все ресурсы, которые могут сказаться на размере. Вы можете изменить некоторые из этих ресурсов уже после того, как виджет реализован, но это будет только тогда, когда виджет определит, что он может или хочет изменить свои размеры, чтобы подстроиться под изменения в значении ресурса.
Вы можете установить флаги изменения размеров, которые виджет использует для того, чтобы определить, подстраивать ли ему или не подстраивать свои размеры в ответ на эти изменения, но заметьте, что если виджет выйдет за пределы размеров, выделенных ему его родителем, он будет отсечён в соответствии с размерами родителя. Не существует механизма, позволяющего виджету договориться со своим родителем о выделении большего пространства. Более подробно об этом см. в главе "Управление геометрией".
Если для корректного отображения требуется регион Photon'а, он создаётся каждый раз при реализации виджета. Регион требуется при любом из следующих условий:
-
Виджет устанавливает курсор
-
Виджету требуется получать события, который не перенаправляются ему его родительским контейнером (напр., охват границей, события перемещения указателя).
-
В ресурсе Pt_ARG_FLAGS установлен флаг Pt_REGION (см. описание PtWidget в "Справочнике виджетов Photon'а").
Вы можете дереализовать (unrealize) виджет, вызвав функцию PtUnrealizeWidget(). Это влияет на факт отображения виджета и его потомков на экране, но не освобождает иерархию семейства виджетов. Вы позже вновь можете отобразить виджет, вызвав функцию PtRealizeWidget().
Вы можете предотвратить реализацию виджета и его потомков при реализации его родителя. Чтобы это сделать, установите флаг Pt_DELAY_REALIZE в ресурсе Pt_ARG_FLAGS. Если Вы установите этот флаг, Вашей заботой станет вызвать функцию PtRealizeWidget() для этого виджета, когда Вы захотите, чтобы он появился на экране.
PtMainLoop()
Вызов функции PtMainLoop передаёт управление приложениям библиотеки виджетов Photon'а.
Библиотека виджетов ожидает события Photon'а и передаёт их виджетам для обработки. Программный код приложения исполняется только тогда, когда в результате появления события вызываются функции ответных реакций, которые приложение зарегистрировало в виджете для этого события.
Подсоединение программного кода приложения к виджету
Если вы откомпилируете, слинкуете и запустите образец приложения, Вы увидите, что появится окно с кнопкой на нём. Если Вы нажмёте на кнопку, ничего не произойдёт, поскольку с этим не связан никакой программный код приложения.
Библиотека виджетов Photon'а спроектирована таким образом, что код пользовательского интерфейса может содержаться совершенно отдельно от программного кода приложения. Пользовательский интерфейс скомпонован из кода, направленного на создание и управление иерархией семейства виджетов, и должен вызывать программный код приложения, чтобы отзываться на конкретные события или действия пользователя. Связь между программным кодом и пользовательским интерфейсом, позволяющая пользовательскому интерфейсу использовать программный код, является единственным местом, где эти две части получают глубокое знание друг о друге.
Связи между пользовательским интерфейсом и программным кодом приложения осуществляется использованием ответных реакций и обработчиков событий.
Ответные реакции – это особый тип ресурса виджета, который позволяет приложению реализовать все существующие возможности виджета. Используя ответные реакции, приложение может зарегистрировать функцию, которая будет затем вызываться библиотекой виджетов в ответ на конкретные ситуации, возникающие внутри ыиджета.
Обработчики событий (необработанные и отфильтрованные ответные реакции) обычно используются для добавления возможностей виджета. Например, Вы можете добавить поведение нажатия кнопки внутри виджета, который не имеет ответных реакций, связанных с событиями нажатия кнопки.
Ответные реакции
Ресурс ответной реакции используется для уведомления приложения о том, что у виджета произошло какое-то определённое действие (напр., Вы нажали кнопку). Каждый ресурс ответной реакции представляет некое действие пользователя, которое, по Вашей задумке, может быть интересно приложению.
Как и для всех ресурсов, виджет имеет свои ресурсы ответных реакций, определённые для его виджетного класса, и он наследует ресурсы ответных реакций, заданные для всех потомков его класса. Это означает, что виджет может иметь несколько действий пользователя, о которых он может уведомлять приложение.
Значением ресурса ответной реакции является список ответных реакций. Каждый элемент списка представляет из себя какую-то функцию приложения, вызываемую в ответ на изменение поведения и данные клиента, присоединённые к ответной реакции. Данные клиента – это указатель на какие-либо произвольного характера данные, которые могут понадобиться Вашему приложению, чтобы обеспечить правильную работу функции ответной реакции.
Информацию об ответных реакциях см. в разделе "Ответные реакции" главы "Управление виджетами в программном коде приложения".
Обработка событий
Когда мы создаём виджетный класс, мы не в силах предвидеть всего, что может понадобиться нашему приложению. Ваше приложение может захотеть быть уведомленным о чём-то, произошедшим с виджетом, что не связано с ресурсом ответной реакции. В этих случаях приложение может задать функции обработки событий.
Информацию об обработчиках событий см. в разделе "Обработчики событий" в главе "Управление виджетами в программном коде приложения".
Полный пример приложения
И теперь мы можем использовать наши вновь приобретённые знания о ресурсах и ответных реакциях для создания более функциональной версии образца приложения, данного выше. Используя ресурсы, мы можем дать виджету кнопки те же размеры, что и окну, и задать, какой шрифт использовать для текста надписи. Мы можем также задать ответную реакцию, исполняемую при нажатии кнопки. Мы сделаем ответную реакцию, которая будет отображать простое сообщение и завершаться.
Вот полный текст программного кода нашего образца программы с этими изменениями:
#include <stdio.h>
#include <stdlib.h>
#include <Pt.h>
int main( int argc, char *argv[] ) {
PtArg_t args[3];
int n;
PtWidget_t *window;
int push_button_cb( PtWidget_t *, void *, PtCallbackInfo_t *);
PtCallback_t callbacks[] = {{push_button_cb, NULL}};
char Helvetica14[MAX_FONT_TAG];
if (PtInit(NULL) = = -1) PtExit(EXIT_FAILURE);
window = PtCreateWidget(PtWindow, Pt_NO_PARENT, 0, NULL);
n = 0;
PtSetArg(&args[n++], Pt_ARG_TEXT_STRING, "Нажмите для выхода", 0);
/* Использовать, если доступен, шрифт 14-пунктовый жирный Helvetica */
if (PfGenerateFontName("Helvetica", 0, 14, Helvetica14) = = NULL) {
perror("Невозможно сгенерировать имя шрифта");
}
else {
PtSetArg(&args[n++], Pt_ARG_TEXT_FONT, Helvetica14, 0);
}
PtSetArg(&args[n++], Pt_CB_ACTIVATE, callbacks, sizeof(callbacks)/sizeof(callbacks[0]));
PtCreateWidget(PtButton, window, n, args);
PtRealizeWidget(window);
PtMainLoop();
return (EXIT_SUCCESS);
} // main()
int push_button_cb(PtWidget_t *w, void *data, PtCallbackInfo_t *cbinfo) {
printf( "Я была нажата\n" );
PtExit( EXIT_SUCCESS );
/* Эта строка никогда не будет исполняться, но она делает счастливым компилятор */
return( Pt_CONTINUE );
}
Приложение 1. Архитектура Photon'а
В этом приложении представлен технический обзор архитектуры Photon'а. Он включает:
-
Пространство событий
-
События
-
Регионы
-
Типы событий
-
Как владельцы региона уведомляются о событиях
-
Регион устройств
-
Регион драйверов
-
Оконный менеджер Photon'а
Пространство событий
Важнейшей характерной чертой Photon'а является способ представления графических приложений. Все приложения Photon'а состоят из одного или более прямоугольников, называемых регионами. Эти регионы пребывают в неком абстрактном трёхмерном пространстве событий; пользователь смотрит на это пространство извне.
Пространство событий
Регионы могут генерировать и собирать объекты, называемые событиями. Эти события могут перемещаться в одном из двух направлений через пространство событий (т.е. либо к пользователю, либо от него). Перемещаясь сквозь пространство событий, события взаимодействуют с другими регионами – таким образом приложения взаимодействуют друг с другом. Процессом, поддерживающим эту простую архитектуру, является менеджер Photon'а.
Используя регионы и события, можно легко создать все службы, требуемые для системы управления окнами – оконные менеджеры, драйверы и приложения. И поскольку процессы, регионами которых управляет менеджер Photon'а, не обязательно должны размещаться на том же компьютере, что и менеджер Photon'а, легко выполнить распределённые по сети приложения.
Регионы и события
Программы Photon'а используют два базовых объекта: регионы и события. Регионы – объекты стационарные, тогда как события перемещаются через пространство событий.
Регион – это одиночная, фиксированная прямоугольная область, которую программа перемещает в пространстве событий. Регион обладает атрибутами, которые определяют, как он взаимодействует с событиями.
Некое событие представляет из себя набор неперекрываемых прямоугольников, которые могут генерироваться и собираться регионами в любом направлении пространства событий. Все события имеют какой-то присоединённый тип. Некоторые типы событий также владеют соответствующими данными.
События
Когда некое событие проходит сквозь пространство событий, его набор прямоугольников взаимодействует с регионами, размещёнными в пространстве событий другими приложениями. Когда такое происходит, менеджер Photon'а настраивает набор прямоугольников события в соответствии с атрибутами регионов, с которыми это событие взаимодействует.
Начальный набор прямоугольников
По умолчанию генерируемый событием начальный набор прямоугольников содержит один прямоугольник, размеры которого обычно являются размерами генерирующего региона. Когда событие проходит через пространство событий, его взаимодействия с другими регионами может привести к тому, что какие-то части этого прямоугольника могут быть удалены. Если это происходит, прямоугольник разделится на набор меньших по размеру прямоугольников, которые представляют оставшиеся части:
Набор прямоугольников события
Определённые типы событий (напр., нажатие кнопки), чтобы иметь размеры генерирующего диапазона, не требуют для себя начального набора прямоугольников. Для таких событий набор прямоугольников состоит из одного прямоугольника, размером в одну точку. Одноточечный набор прямоугольников называется точечным источником.
Накопленный набор прямоугольников
Набор прямоугольников "накопленных" событий состоит из прямоугольников, получившихся в результате взаимодействия события с предшествующими регионами в пространстве событий. Если событие полностью перекрыто другими регионами, так что в результате набор не содержит прямоугольников, то такое событие пришло к концу.
Список типов событий см. в разделе "Типы событий".
Регионы
Процесс может создавать или использовать любое количество регионов и может размещать их где угодно в пространстве событий. Более того, управляя размерами, местоположением и атрибутами региона (относительно других регионов пространства событий), процесс может использовать, модифицировать и удалять службы, предоставляемые другими регионами.
Photon использует серии регионов, выстроенных от корневого региона в конце пространства событий Photon'а к графическому региону в начале (впереди). События рисования стартуют в регионе приложения и движутся вперёд к графическому региону. События ввода стартуют на регионе Мышь/Клавиатура и перемещаются назад в направлении к корневому региону.
Расщеплённый образ регионов Photon'а
В файле <photon/PhT.h> определены следующие константы:
-
Ph_DEV_RID – идентификатор региона устройств
-
Ph_ROOT_RID – идентификатор корневого региона
Владелец регионов и менеджер Photon'а могут располагаться на разных компьютерах.
Регион имеет два атрибута, которые управляют тем, как с событиями обращаться, когда те пересекают регион:
-
чувствительность
-
непрозрачность
Вы можете устанавливать их независимо для каждого отдельного типа событий.
Чувствительность
Если регион чувствителен к какому-то конкретному типу события, то владелец региона собирает копии всех событий этого типа, которые пересекли регион. Если другие регионы чувствительны к этому же самому типу и событие с ними пересекается, то они тоже накапливают копии события – но с возможно другим набором прямоугольников.
Несмотря на то, что многие регионы могут собирать копии одного и того же события, набор прямоугольников для каждого события может быть скорректированным и поэтому будет уникальным для каждого региона, собирающего события. Набор прямоугольников отражает взаимодействие события с другими регионами в пространстве событий до того, как оно достигло накапливающего региона.
Если регион нечувствителен к некоему типу события, владелец региона никогда не будет накапливать этот тип события. Атрибут чувствительности не модифицирует набор прямоугольников события и не оказывает никакого влияния на способности события продолжать свой путь сквозь пространство событий.
Непрозрачность
Непрозрачные регионы блокируют дальнейшее прохождение набора прямоугольников события сквозь пространство событий. Атрибут непрозрачности управляет тем, корректируется ли набор прямоугольников события в результате взаимодействия с регионом.
Если регион непрозрачен для какого-то типа события, любое событие этого типа, пересекающее регион, получает набор прямоугольников события, откорректированный таким образом, что отсекается пересекаемым регионом. Эти изменения набора прямоугольников таковы, что они включают прямоугольники меньших размеров. Эти новые прямоугольники описывают части события, которые остались видимы для регионов, находящихся в пространстве событий позади этого региона.
Если какой-то регион не является непрозрачным для какого-то типа события, то для событий этого типа набор прямоугольников никогда не подвергается корректировке в результате пересечения с этим регионом.
Краткая сводка атрибутов
В следующей таблице суммируется, как атрибуты региона оказывают воздействие на пересекающие регион события:
Если регион является: | То событие является: | И набор для прямоугольников является: |
Не чувствительным, не непрозрачным | Проигнорированным | Не подвергшимся воздействию |
Не чувствительным, непрозрачным | Проигнорированным | Подвергшимся воздействию |
Чувствительным, не непрозрачным | Собранным | Не подвергшимся воздействию |
Чувствительным, непрозрачным | Собранным | Подвергшимся воздействию |
Регистрация событий (event logging)
Размещая регион так, чтобы тот перекрывал всё пространство событий, процесс может взаимодействовать и модифицировать любые события, проходящие через регион. Если регион чувствителен ко всем событиям, но не является непрозрачным, он может прозрачно регистрировать все события.
Модификация событий
Если регион является чувствительным и непрозрачным, он может принять решение продолжить испускание уже модифицированной версии события. Например, регион может накапливать события мыши, выполнять в этих событиях распознавание рукописного текста, и затем генерировать эквивалентное событие клавиатуры.
Взаимосвязь родитель/потомок
Все регионы обладают взаимосвязями типа родитель/потомок. Регион потомка всегда располагается впереди родительского региона (т.е. ближе к пользователю), и его координаты являются относительными – задаются относительно родительского региона.
Координатное пространство Photon'а
Все регионы располагаются внутри координатного пространства Photon'а, имеющего следующие размеры: