Руководство программиста в Photon (1037671), страница 64
Текст из файла (страница 64)
Когда происходит запрошенное действие, вызывается ответная реакция Pt_CB_WINDOW. См. раздел "Ответная реакция уведомления" ниже. Если Вы установили флаг уведомления Ph_WM_CLOSE, ответная реакция Pt_CB_WINDOW Вашего приложения вызывается, когда кто-то хочет закрыть окно. Ваше приложение не закрывает окно – оно может решить, что его надо оставить открытым. Напротив, ответная реакция Pt_CB_WINDOW_CLOSING вызывается, когда окно удалено (unrealized), но до того, как удалён его регион. На этот момент приложение не может прекратить закрытие окна.
Если вы установили флаг управления Ph_WM_CLOSE, менеджер окна указывает на необходимость обработки закрытия окна. В этом случае вызывается ответная реакция Pt_CB_WINDOW_CLOSING, но не ответная реакция Pt_CB_WINDOW.
Ответная реакция уведомления
Когда происходит действие оконного менеджера, которое занесено в список уведомительных флагов окна (Pt_ARG_WINDOW_NOTIFY_FLAGS), вызывается ответная рекция окна Pt_CB_WINDOW.
Каждой функции ответной реакции, имеющейся в списке этого ресурса, передаётся структура PtCallbackInfo(см. "Справочник виджетов Photon'а"), которая содержит по меньшей мере следующие члены:
reason | Pt_CB_WINDOW |
reason_subtype | 0 (не используется) |
event | Указатель на событие, вызвавшее ответную реакцию |
cbdata | Указатель на структуру PhWindowEvent_t (описанную в "Справочнике библиотечных функций Photon'а") |
Эти функции ответных реакций должны возвращать Pt_CONTINUE.
Пример: проверка закрытия окна
Предположим, Вы хотите проверить, действительно ли пользователь хочет завершить работу приложения, закрывая окно. Вот что Вам надо сделать:
-
Сбросить флаг Ph_WM_CLOSE в ресурсе Pt_ARG_WINDOW_MANAGED_FLAGS. Это укажет оконному менежеру не закрывать окно.
-
Установите флаг Ph_WM_CLOSE в ресурсе Pt_ARG_WINDOW_NOTIFY_FLAGS. Оконный менеджер будет уведомлять Вас, когда пользователь попытается закрыть окно.
-
Добавьте ответную реакцию Pt_CB_WINDOW такого вида:
int window_callback( PtWidget_t *widget, ApInfo_t *apinfo, PtCallbackInfo_t *cbinfo ) {
PhWindowEvent_t *we = cbinfo->cbdata;
char *btns[] = { "&Yes", "&No" };
char Helvetica14[MAX_FONT_TAG];
/* предотвращает предупреждения (варнинги) об отсутствии ссылок */
widget = widget, apinfo = apinfo, cbinfo = cbinfo;
if ( we->event_f == Ph_WM_CLOSE ) {
/* Спросит пользователя, действительно ли лн хочет выйти.
Использовать шрифт 14-point Helvetica, если он доступен */
switch( PtAlert( ABW_base, NULL, NULL, NULL, "Вы действительно хотите уйти?",
PfGenerateFontName("Helvetica", 0, 14, Helvetica14),
2, btns, NULL, 1, 2, Pt_MODAL ) ) {
case 1: /* да */
PtExit (EXIT_SUCCESS);
break;
case 2: /* нет */
return (Pt_CONTINUE);
}
}
else {
/* Проверка других событий */
}
return( Pt_CONTINUE );
}
Есть весьма существенная разница между событием Ph_WM_CLOSE и ответной реакцией закрытия окна (Pt_CB_WINDOW_CLOSING).
Ответная реакция Pt_CB_WINDOW с событием Ph_WM_CLOSE является просто уведомлением со стороны оконного менеджера Photon'а, что пользователь щёлкнул на кнопке закрытия или выбрал пункт "Close" из меню оконного менеджера Photon'а. Если в ресурсе Pt_ARG_WINDOW_MANAGED_FLAGS сброшен бит Ph_WM_CLOSE, библиотека больше не предпринимает никаких действий.
Закрытие окна (Pt_CB_WINDOW_CLOSING) вызывается, когда окно собирается по какой-либо причине прекратить своё существование (unrealize). Это включает транспортировку в другой Photon и явные вызовы PtDestroyWidget() или PtUnrealizeWidget(). Если в ответной реакции закрытия окна Вы хотите убедиться, что окно действительно уничтожено, установите флаг Pt_DESTROYED в Pt_ARG_FLAGS. Вы можете также использовать ответную реакцию Pt_CB_DESTROYED, чтобы знать, когда окно помечается для уничтожения, или Pt_CB_IS_DESTROYED, чтобы знать, когда оно уничтожается.
Заметьте также, что вызов функции exit() явным образом игнорирует все эти ответные реакции.
Получение и установка состояния окна
Ресурс Pt_ARG_WINDOW_STATE управляет состоянием окна:
Чтобы сделать это: | Установите этот бит: |
Максимизировать окно | Ph_WM_STATE_ISMAX |
Сделать окно фоновым | Ph_WM_STATE_ISBACKDROP |
Минимизировать окно | Ph_WM_STATE_ISHIDDEN |
Разместить базовое окно впереди окон всех других приложений | Ph_WM_STATE_ISFRONT |
Передать фокус клавиатуры на окно, если фокус курсора отключён | Ph_WM_STATE_ISFOCUS |
Передать приложению комбинации с клавишей <Alt> | Ph_WM_STATE_ISALTKEY |
Заблокировать окно | Ph_WM_STATE_ISBLOCED (только для чтения) |
Принятым по умолчанию значением является PH_WM_STATE_ISFOCUS.
Вы можете получить и установить состояние окна в любой момент, использовав ресурс Pt_ARG_WINDOW_STATE, но это может привести к непредсказуемым результатам, если пользователь как раз в этот момент изменит состояние окна.
Наиболее безопасным временем, когда можно использовать этот ресурс для установки состояния окна – время перед тем, как окно реализовано. Например, Вы можете выполнить установки, когда создаётся виджет PtWindow или в ответной реакции окна Pt_CB_WINDOW_OPENING. Установки обретут силу, когда окно реализуется.
Вы можете установить Pt_ARG_WINDOW_STATE после реализации окна, основывая Ваши изменения на Ваших предположениях о том, каково текущее состояние окна, но безопаснее сообщить оконному менеджеру о том, как Вы хотите изменить состояние окна, вызвав:
PtForwardWindowEvent() | Изменить состояние окна, связанного с данным идентификатором региона |
PtForwardWindowTaskEvent() | Изменить состояние окна, связанного с данным идентификатором коннекции Photon'а. |
Например, чтобы минимизировать окно, которое принадлежит Вашему приложению и уже открыто:
static void send_key( long key ) {
struct {
PhEvent_t event;
PhRect_t rect;
PhKeyEvent_t pevent;
} new_event;
PhEvent_t event;
PhKeyEvent_t key_event;
PhRect_t rect;
rect.ul.x = rect.ul.y = 0;
rect.lr.x = rect.lr.y = 0;
memset( &event, 0, sizeof(event));
memset( &key_event, 0, sizeof(key_event) );
event.type = Ph_EV_KEY;
event.emitter.rid = Ph_DEV_RID;
event.num_rects = 1;
event.data_len = sizeof(key_event);
event.input_group = 1;
key_event.key_cap = key;
key_event.key_sym = key;
if ( isascii( key ) && isupper( key ) ) {
key_event.key_mods = Pk_KM_Shift;
}
/* Генерирование нажатия клавиши */
key_event.key_flags = Pk_KF_Sym_Valid | Pk_KF_Cap_Valid | Pk_KF_Key_Down;
PhEmit( &event, &rect, &key_event );
/* Генерирование отпускания клавиши */
key_event.key_flags &= ~(Pk_KF_Key_Down | Pk_KF_Sym_Valid) ;
PhEmit( &event ,&rect, &key_event );
return;
}
Чтобы минимизировать окно, принадлежащее другому приложению и уже открыто:
PhWindowEvent_t event;
memset( &event, 0, sizeof (event) );
event.event_f = Ph_WM_HIDE;
event.event_state = Ph_WM_EVSTATE_HIDE;
PtForwardWindowTaskEvent( connection_id, &event );
Когда Вы вызываете эти функции, Вы просите оконный менеджер выполнить заданное действие. Если это действие не входит в набор флагов управления (Pt_ARG_WINDOW_MANAGED_FLAGS) для данного окна, оконный менеджер этого и на сделает.
Управление несколькими окнами
Если Ваше приложение имеет более одного окна, Вам понадобится учитывать взаимодействие между ними.
По определению, окно-потомок всегда располагается перед своим родителем. Окна-потомки могут размещаться впереди и позади своих братьев. Для окон, способных переходить за другие окна, они должны быть братьями. Таким образом, окно, способное перемещаться за базовое окно, не должно иметь родителя.
Функции управления окнами
Нижеприведенные низкоуровневые функции связаны с оконным менеджером, но Вам не надо использовать их в приложении, использующем виджеты:
PhWindowChange() | Модифицирует атрибуты региона окна |
PhWindowClose() | Закрывает окно |
PhWindowOpen() | Создаёт регион окна |
Эти функции могут быть вызваны в приложении, использующем виджеты:
PhWindowQueryVisible() | Запрашивает видимое пространство |
PtConsoleSwitch() | Переключает на другую виртуальную консоль |
PtForwardWindowEvent() | Отсылает событие окна |
PtForwardWindowTaskEvent() | Отсылает событие окна задаче |
PtWindowConsoleSwitch() | Переключает на консоль, на которой отображено заданное окно |
PtWindowFrameSize() | Определяет размер рамки окна |
Запуск самостоятельного приложения
Если предполагается, что приложение должно исполняться само, Вам может понадобиться:
-
Сделать так, чтобы Ваше приложение заполнило экран. Установите Ph_WM_STATE_ISMAX в ресурсе Pt_ARG_WINDOW_STATE базового окна.
-
Отключите все флаги во флагах Pt_ARG_WINDOW_RENDER_FLAGS базового окна, так чтобы у окна не было заголовочного бруска рамки, границ, кнопок меню и всего такого прочего – этого всего не нужно, если никакие другие приложения не будут исполняться.
[Примечание от переводчика: к сожалению, при этом базовое окно занимает всё доступное пространство, а не весь экран. Иными словами, всю область экрана, кроме Shelf'ов и Task Bar'а. Так что для того, чтобы перкрыть весь экран, можно установить в ресурсах окна Minimum Window Width = Maximum Window Width = 1015 (например), и аналогично по высоте (т.е. для разрешения 1024х768 можно 1015х740), и снять, как и указывается, по крайней мере, следующие флаги Ph_WM_RENDER_* : COLLAPSE, MIN, RESIZE, MAX, MENU, CLOSE].
Модальные диалоги
Иногда Вам понадобится, чтобы перед продолжением своей работы программа запросила у пользователя какую-то информацию. Обычно это делается с помощью всплывающего диалога; если Вы не хотите, чтобы пользователь мог выбрать какое-либо другое действие перед тем, как предоставить эту информацию, Вы должны использовать модальный диалог.
Модальный диалог не позволяет вводу пользователя пройти на какой-либо иной виджет приложения. Используя для запроса информации модальный диалог, Вы обеспечиваете, что события обрабатываются внутри функции ответной реакции. Чтобы создать модальный диалог, Вы должны создать новый виджет типа PtWindow, обычно как потомка главного окна приложения.
Для активации модального диалога Вы должны реализовать диалоговый виджет и блокировать все остальные оконные виджеты приложения. Чтобы блокировать окно или окна, вызовите одну из функций:
PtBlockAllWindows() | Блокировать все окна, кроме одного с заданным виджетом |
PtBlockWindow() | Блокировать заданное окно |
Обе эти функции возвращают список заблокированных виджетов, который Вам понадобиться, когда Вы будете их разблокировать. В отличие от блокировки окон, Вы можете сделать диалог модальным с помощью функции PtMakeModal().
После того как модальный диалог активирован, вызовите функцию PtModalBlock(), чтобы запустить модальную петлю обработки событий Photon'а вплоть до возникновения состояния завершения.
Когда операция, связанная с модальным диалогом, завершена или прервана, Вам надо убрать диалог. Чтобы это сделать:
-
Вызовите функцию PtModalUnblock(), чтобы остановить выполнение модальной петли. Вы можете установить значение, возвращённое функцией PtModalBlock().
-
Уничтожьте (destroy) или удалите (unrealize) сам диалог.
Вызовите функцию PtUnblockWindows(), чтобы разблокировать все оконные виджеты, которые были блокированы при создании диалога. Вам не надо это делать, если вместо функций PtBlockAllWindows() или PtBlockWindow() Вы вызывали функцию PtMakeModal().
Мы можем легко изменить наш предыдущий пример рабочей процедуры, так что её "прогрессный" диалог будет вести себя как модальный диалог. Мы добавим структуру PtModalCtrl_t в ответную реакцию закрытия окна для её использования функциями PtModalBlock() и PtModalUnblock().