logo
Литература_1 / photon_old

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

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

Модальный диалог не позволяет вводу пользователя пройти на какой-либо иной виджет приложения. Используя для запроса информации модальный диалог, Вы обеспечиваете, что события обрабатываются внутри функции ответной реакции. Чтобы создать модальный диалог, Вы должны создать новый виджет типа 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'а, пока заданный виджет не будет уничтожен.

Yandex.RTB R-A-252273-3
Yandex.RTB R-A-252273-4