Диалоговые окна в Qt: Модальные и немодальные

qt диалоговые окна

Модальное диалоговое окно блокирует родительский виджет. Блокировка снимается только при закрытии диалогового окна. Такое поведение оказывается проще при реализации, поскольку оно ограничивает свободу пользователя и снижает количество возможных проблем. Однако пользователи могут счесть это недостатком.

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

Выбор типа диалогового окна основывается на здравом смысле и относится к этапу юзабилити-тестирования. Мы этого вопроса касаться не станем.

Класс диалогового окна

Реализуем простой класс диалогового окна. Именно его мы попробуем вызывать в модальном и немодальном режимах.

На нашем диалоговом окне мы разместили одно поле ввода и три кнопки: OK, Apply и Cancel.

Кнопка OK предназначена для подтверждения ввода с последующим закрытием окна. Этого мы добились, связав сигнал щелчка по кнопке со стандартным слотом QDialog::accept().

Кнопка Apply так же предназначена для подтверждения ввода. Но предполагает продолжение работы с диалоговым окном. Для реализации такой логики мы предусмотрели сигнал applied().

Последняя кнопка Cancel просто закрывает диалоговое окно. Больше ничего не происходит. Введенные данные отклоняются. Для этого мы используем слот QDialog::reject().

Других кодов в QDialog не предусмотрено (кроме Accepted и Rejected). Поэтому существует слот QDialog::done( int ). Он закрывает окно и возвращает в качестве результата вызова указанное целочисленное значение.

Нажатие клавиши Esc в диалоговом окне приводит к вызову QDialog::reject(), а Enter связывается с кнопкой по умолчанию. Такой кнопкой становится либо первая добавленная кнопка (в нашем случае OK), либо кнопка, для которой вызвана функция btn->setDefault( true ).

Чтобы извлечь введенное значение в текстовое поле, мы предусмотрели константную функцию-член getInput().

Модальное диалоговое окно

Реализуем виджет, который будет использовать наше диалоговое окно:

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

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

Мы должны не забыть привязать сигнал applied() нашего диалогового окна к специально созданному слоту onApplied(). В нем мы просто устанавливаем значение введенной строки в качестве значения текстового поля виджета.

Момент отображения диалогового окна соответствует строке с вызовом dlg.exec(). В качестве ответа возвращается код завершения работы окна. Единственный интересный для нас случай: QDialog::Accepted. Для него мы делаем то же самое, что и в слоте onApplied().

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

Немодальное диалоговое окно

Добавим реализацию слота onNonModalDemo() для вызова нашего диалогового окна в немодальном режиме:

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

Для обработки ответа QDialog::Accepted мы делаем привязку к сигналу диалогового окна accepted(). Есть аналогичный сигнал для отрицательного ответа rejected(). А также для нашего собственного кода результата (на случай вызова слота done( int ) ): finished( int ).

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

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

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

Выводы

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

Понравилась статья? Поделиться с друзьями:
Добавить комментарий