Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
76
Добавлен:
02.04.2015
Размер:
8.79 Mб
Скачать
    1. Управление несколькими окнами

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

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

    1. Функции управления окнами

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

PhWindowChange()

Модифицирует атрибуты региона окна

PhWindowClose()

Закрывает окно

PhWindowOpen()

Создаёт регион окна

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

PhWindowQueryVisible()

Запрашивает видимое пространство

PtConsoleSwitch()

Переключает на другую виртуальную консоль

PtForwardWindowEvent()

Отсылает событие окна

PtForwardWindowTaskEvent()

Отсылает событие окна задаче

PtWindowConsoleSwitch()

Переключает на консоль, на которой отображено заданное окно

PtWindowFrameSize()

Определяет размер рамки окна

    1. Запуск самостоятельного приложения

Если предполагается, что приложение должно исполняться само, Вам может понадобиться:

  • Сделать так, чтобы Ваше приложение заполнило экран. Установите 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].

    1. Модальные диалоги

Иногда Вам понадобится, чтобы перед продолжением своей работы программа запросила у пользователя какую-то информацию. Обычно это делается с помощью всплывающего диалога; если Вы не хотите, чтобы пользователь мог выбрать какое-либо другое действие перед тем, как предоставить эту информацию, Вы должны использовать модальный диалог.

Модальный диалог не позволяет вводу пользователя пройти на какой-либо иной виджет приложения. Используя для запроса информации модальный диалог, Вы обеспечиваете, что события обрабатываются внутри функции ответной реакции. Чтобы создать модальный диалог, Вы должны создать новый виджет типа PtWindow, обычно как потомка главного окна приложения.

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

PtBlockAllWindows()

Блокировать все окна, кроме одного с заданным виджетом

PtBlockWindow()

Блокировать заданное окно

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

После того как модальный диалог активирован, вызовите функцию PtModalBlock(), чтобы запустить модальную петлю обработки событий Photon'а вплоть до возникновения состояния завершения.

Когда операция, связанная с модальным диалогом, завершена или прервана, Вам надо убрать диалог. Чтобы это сделать:

  1. Вызовите функцию PtModalUnblock(), чтобы остановить выполнение модальной петли. Вы можете установить значение, возвращённое функцией PtModalBlock().

  2. Уничтожьте (destroy) или удалите (unrealize) сам диалог.

Вызовите функцию PtUnblockWindows(), чтобы разблокировать все оконные виджеты, которые были блокированы при создании диалога. Вам не надо это делать, если вместо функций PtBlockAllWindows() или PtBlockWindow() Вы вызывали функцию PtMakeModal().

Мы можем легко изменить наш предыдущий пример рабочей процедуры, так что её "прогрессный" диалог будет вести себя как модальный диалог. Мы добавим структуру PtModalCtrl_t в ответную реакцию закрытия окна для её использования функциями PtModalBlock() и PtModalUnblock().

Ответная реакция done() вместо освобождения закрытия окна вызывает функцию PtModalUnblock():

int done(PtWidget_t *w, void *client, PtCallbackInfo_t *call) {

CountdownClosure *closure = (CountdownClosure *)client;

call = call;

if (!closure->done) {

PtAppRemoveWorkProc(NULL, closure->work_id);

}

PtDestroyWidget(closure->dialog->widget);

free(closure->dialog);

/* Новое: завершаем модальную петлю, возвращаем значение счётчика в качестве ответа */

PtModalUnblock(&(closure->modal_control), (void *) &(closure->value));

return (Pt_CONTINUE);

}

Всё, что осталось в этом месте сделать – это изменить функцию ответной реакции push_button_cb(), так чтобы она блокировала окно после реализации "прогрессного" диалога, запускала модальную петлю, разблокировала окна и освобождала закрытие после исчезновения диалога.

Вот новая версия функции ответной реакции push_button_cb():

int push_button_cb(PtWidget_t *w, void *client, PtCallbackInfo_t *call) {

PtWidget_t *parent = (PtWidget_t *)client;

WorkDialog *dialog;

PtBlockedList_t * blocked_list;

void * response;

w = w; call = call;

dialog = create_working_dialog(parent);

if (dialog) {

CountdownClosure *closure = (CountdownClosure *) malloc(sizeof(CountdownClosure));

if (closure) {

PtWorkProcId_t *id;

closure->dialog = dialog;

closure->value = 0;

closure->maxvalue = 200000;

closure->done = 0;

closure->work_id = id =

PtAppAddWorkProc(NULL, count_cb, closure);

PtAddCallback(dialog->ok_button, Pt_CB_ACTIVATE, done, closure);

PtRealizeWidget(dialog->widget);

/* Новое: блокируем все окна, кроме диалога, обработываем события вплоть

до закрытия диалога, и затем разблокируем все окна */

locked_list = PtBlockAllWindows (dialog->widget,

Ph_CURSOR_NOINPUT, Pg_TRANSPARENT);

response = PtModalBlock( &(closure->modal_control), 0 );

printf ("Достигнутое значение равно %d\n", *(int *)response );

free (closure);

PtUnblockWindows (blocked_list);

}

}

return (Pt_CONTINUE);

}

А вот новая версия программы в целом:

#include <Pt.h>

typedef struct workDialog {

PtWidget_t *widget;

PtWidget_t *label;

PtWidget_t *ok_button;

} WorkDialog;

typedef struct countdownClosure {

WorkDialog *dialog;

int value;

int maxvalue;

int done;

PtWorkProcId_t *work_id;

/* Новый член: */

PtModalCtrl_t modal_control;

} CountdownClosure;

WorkDialog *create_working_dialog(PtWidget_t *parent) {

PhDim_t dim;

PtArg_t args[3];

int nargs;

PtWidget_t *window, *group;

WorkDialog *dialog = (WorkDialog *)malloc(sizeof(WorkDialog));

if (dialog) {

nargs = 0;

PtSetArg(&args[nargs], Pt_ARG_WIN_PARENT, parent, 0);

nargs++;

PtSetParentWidget(NULL);

dialog->widget = window = PtCreateWidget(PtWindow, parent, nargs, args);

nargs = 0;

PtSetArg(&args[nargs], Pt_ARG_GROUP_ORIENTATION, Pt_GROUP_VERTICAL, 0);

nargs++;

PtSetArg(&args[nargs], Pt_ARG_GROUP_VERT_ALIGN, Pt_GROUP_VERT_CENTER, 0);

nargs++;

group = PtCreateWidget(PtGroup, window, nargs, args);

nargs = 0;

dim.w = 200;

dim.h = 100;

PtSetArg(&args[nargs], Pt_ARG_DIM, &dim, 0);

nargs++;

PtSetArg(&args[nargs], Pt_ARG_TEXT_STRING, "Counter: ", 0);

nargs++;

dialog->label = PtCreateWidget(PtLabel, group, nargs, args);

PtCreateWidget(PtSeparator, group, 0, NULL);

nargs = 0;

PtSetArg(&args[nargs], Pt_ARG_TEXT_STRING, "Stop", 0);

nargs++;

dialog->ok_button = PtCreateWidget(PtButton, group, 1, args);

}

return dialog;

} // create_working_dialog()

int done(PtWidget_t *w, void *client, PtCallbackInfo_t *call) {

CountdownClosure *closure = (CountdownClosure *)client;

call = call;

if (!closure->done) {

PtAppRemoveWorkProc(NULL, closure->work_id);

}

PtDestroyWidget(closure->dialog->widget);

free(closure->dialog);

/* Новое: завершаем модальную петлю, возвращаем значение счётчика в качестве ответа */

PtModalUnblock(&(closure->modal_control), (void *) &(closure->value));

return (Pt_CONTINUE);

} // done()

int count_cb(void *data) {

CountdownClosure *closure = (CountdownClosure *)data;

char buf[64];

int finished = 0;

if ( closure->value++ == 0 || closure->value % 1000 == 0 ) {

sprintf(buf, "Счётчик: %d", closure->value);

PtSetResource( closure->dialog->label, Pt_ARG_TEXT_STRING, buf, 0);

}

if ( closure->value == closure->maxvalue ) {

closure->done = finished = 1;

PtSetResource( closure->dialog->ok_button, Pt_ARG_TEXT_STRING, "Done", 0);

}

return finished ? Pt_END : Pt_CONTINUE;

} // count_cb()

int push_button_cb(PtWidget_t *w, void *client, PtCallbackInfo_t *call) {

PtWidget_t *parent = (PtWidget_t *)client;

WorkDialog *dialog;

PtBlockedList_t * blocked_list;

void * response;

w = w; call = call;

dialog = create_working_dialog(parent);

if (dialog) {

CountdownClosure *closure = (CountdownClosure *) malloc(sizeof(CountdownClosure));

if (closure) {

PtWorkProcId_t *id;

closure->dialog = dialog;

closure->value = 0;

closure->maxvalue = 200000;

closure->done = 0;

closure->work_id = id = PtAppAddWorkProc(NULL, count_cb, closure);

PtAddCallback(dialog->ok_button, Pt_CB_ACTIVATE, done, closure);

PtRealizeWidget(dialog->widget);

/* Новое: блокируем все окна, кроме диалога, обрабатываем события вплоть до его закрытия,

и затем разблокируем все окна */

blocked_list = PtBlockAllWindows (dialog->widget,

Ph_CURSOR_NOINPUT, Pg_TRANSPARENT);

response = PtModalBlock( &(closure->modal_control), 0 );

printf ("Достигнутое значение равно %d\n", *(int *)response );

free (closure);

PtUnblockWindows (blocked_list);

}

}

return (Pt_CONTINUE);

} // push_button_cb()

int main(int argc, char *argv[]) {

PhDim_t dim;

PtArg_t args[3];

int n;

PtWidget_t *window;

PtCallback_t callbacks[] = {{push_button_cb, NULL}};

char Helvetica14b[MAX_FONT_TAG];

if (PtInit(NULL) = = -1) PtExit(EXIT_FAILURE);

dim.w = 200;

dim.h = 100;

PtSetArg(&args[0], Pt_ARG_DIM, &dim, 0);

if ((window = PtCreateWidget(PtWindow, Pt_NO_PARENT, 1, args)) = = NULL) PtExit(EXIT_FAILURE);

callbacks[0].data = window;

n = 0;

PtSetArg(&args[n++], Pt_ARG_TEXT_STRING, "Count Down...", 0);

/* Используется 14-пунктовый жирный шрифт Helvetica, если он доступен */

if(PfGenerateFontName("Helvetica", PF_STYLE_BOLD, 14, Helvetica14b) = = NULL) {

perror("Невозможно сгенерировать имя шрифта");

}

else {

PtSetArg(&args[n++], Pt_ARG_TEXT_FONT, Helvetica14b, 0);

}

PtSetArg(&args[n++], Pt_CB_ACTIVATE, callbacks, sizeof(callbacks)/sizeof(PtCallback_t));

PtCreateWidget(PtButton, window, n, args);

PtRealizeWidget(window);

PtMainLoop();

return (EXIT_SUCCESS);

} // main()

Если Ваш диалог является автономным и Вам просто надо подождать его завершения, Вам может пригодиться такая функция:

ApModalWait() Обрабатывать события Photon'а, пока заданный виджет не будет уничтожен.

Соседние файлы в папке Литература_1