2.4. Диалоги с изменяющимся внешним видом.

Мы рассмотрели примеры создания диалогов, которые никогда не меняют свой внешний вид. В некоторых случаях желательно иметь диалоги, которые могут динамически изменять свое представление. Наиболее часто на практике встречаются расширяемые диалоги и многостраничные диалоги. Оба вида диалогов могут быть созданы как в Qt Designer, так и в результате ручного кодирования.

Расширяемые диалоги, обычно выводятся на экран в сокращенном варианте, но дают пользователю возможность выбирать между сокращенным и расширенным режимом представления информации. Расширяемые диалоги как правило используются в тех случаях, когда необходимо сокрыть дополнительные сведения, которые не являются обязательными и пользователь явно не выразил свое желание видеть их. В этом разделе мы разберем процесс создания расширяемого диалога, показанного на рисунке 2.13, с помощью Qt Designer.

Рисунок 2.13. Диалог сортировки в простом и расширенном режимах.


Это диалог сортировки, используемый в электронных таблицах. Он появляется, когда пользователь пытается отсортировать данные по одному или нескольким столбцам. В сокращенном представлении диалог позволяет выбрать столбец и порядок сортировки, в расширенном варианте добавляется возможность указать еще два столбца и порядок сортировки по каждому из них. Кнопка "More" позволяет переходить из сокращенного режима -- в расширенный и обратно.

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

  1. Положите на заготовку формы GroupBox, два TextLabel, два ComboBox и одну горизонтальную распорку.

  2. "Растяните" GroupBox побольше, ухватив мышкой за правый нижний его угол.

  3. Разместите виджеты внутри GroupBox-а примерно так, как показано на рисунке 2.14(а)

  4. Ухватив мышкой за правый край второго ComboBox-а, сделайте его примерно в два раз больше первого.

  5. Запишите в свойство title, GroupBox-а, строку "&Primary Key". В свойство text первой метки -- "Column:", второй метки -- "Order:".

  6. Щелкните мышкой дважды по первому ComboBox. Перед вами появится окно редактора, в котором добавьте один элемент с текстом "None".

  7. Щелкните мышкой дважды по второму ComboBox и добавьте элементы "Ascending" и "Descending".

  8. Теперь скомпонуем виджеты внутри GroupBox, для этого, щелкните по GroupBox и выберите пункт меню Layout|Lay Out in a Grid. В результате вы должны получить нечто похожее на рисунок 2.14(б).



Рисунок 2.14(а). До выполнения компоновки.


Рисунок 2.14(б). После выполнения компоновки.


Если компоновка выполнилась не так как надо или вы допустили какую нибудь ошибку, вы всегда можете выбрать пункт меню Edit|Undo и отменить произведенное действие. После чего можете повторить попытку.

Теперь добавим группы виджетов для расширенного представления:

  1. Растяните форму диалога, чтобы хватило места для дополнительных виджетов. Выберите GroupBox и скопируйте его в буфер обмена, выбрав пункт меню Edit|Copy. Вставьте новые группы виджетов, дважды выбрав пункт меню Edit|Paste. Переместите новые GroupBox-ы на свои места. Измените у них свойство title.

  2. Создайте кнопки "OK", "Cancel" и "More".

  3. Для кнопки "OK" установите свойство default в TRUE.

  4. Добавьте две вертикальные распорки.

  5. Расположите кнопки "OK", "Cancel" и "More" по вертикали. Переместите одну из распорок так, чтобы она встала между кнопками "Cancel" и "More". Выделите все четыре элемента и выберите пункт меню Layout|Lay Out Vertically.

  6. Вторую распорку переместите так, чтобы она встала между первым и вторым GroupBox.

  7. Установите свойство sizeHint у вертикальных распорок в значение (20, 10).

  8. Разместите виджеты так, как это показано нарисунке 2.15(а).

  9. Выберите пункт меню Layout|Lay Out in a Grid. У вас должна получиться заготовка, показанная на рисунке 2.15(б)



Рисунок 2.15(а). До выполнения компоновки.


Рисунок 2.15(б). После выполнения компоновки.


В результате такого размещения мы получили "сетку" из двух колонок и четырех строк -- всего восемь ячеек. Первый GroupBox, левая вертикальная распорка, второй и третий GroupBox занимают по одной ячейке. Кнопки "OK", "Cancel", "More" и правая вертикальная распорка занимают две ячейки. И вправом нижнем углу диалога у нас остаются две пустых ячейки. Если у вас не получилась такая компоновка виджетов -- отмените ее и повторите попытку.

Проверьте свойство формы resizeMode. Оно должно быть установлено как "Fixed", благодаря чему пользователь не сможет растягивать окно диалога. Тогда, всю ответственность за размер окна диалога возьмут на себя менеджеры размещения, изменяя его в случае, когда подчиненные виджеты показываются или скрываются. Это гарантирует показ окна диалога с оптимальными размерами.

Дайте форме имя "SortDialog" и установите свойство caption в "Sort". Дайте имена виджетам, в соответствии с рисунком 2.16.

Рисунок 2.16. Имена виджетов на форме.


В заключение соединим сигналы и слоты:

  1. Соедините okButton clicked() с SortDialog accept()

  2. Соедините cancelButton clicked() с SortDialog reject()

  3. Соедините moreButton toggled(bool) с secondaryGroupBox setShown(bool)

  4. Соедините moreButton toggled(bool) с tertiaryGroupBox setShown(bool)



Щелкните мышкой по форме дважды, чтобы запустить редактор и добавьте следующий текст:

1 void SortDialog::init() 2 { 3 secondaryGroupBox->hide(); 4 tertiaryGroupBox->hide(); 5 setColumnRange('A', 'Z'); 6 } 7 void SortDialog::setColumnRange(QChar first, QChar last) 8 { 9 primaryColumnCombo->clear(); 10 secondaryColumnCombo->clear(); 11 tertiaryColumnCombo->clear(); 12 secondaryColumnCombo->insertItem(tr("None")); 13 tertiaryColumnCombo->insertItem(tr("None")); 14 primaryColumnCombo->setMinimumSize( 15 secondaryColumnCombo->sizeHint()); 16 QChar ch = first; 17 while (ch <= last) { 18 primaryColumnCombo->insertItem(ch); 19 secondaryColumnCombo->insertItem(ch); 20 tertiaryColumnCombo->insertItem(ch); 21 ch = ch.unicode() + 1; 22 } 23 } Функция init делает второй и третий GroupBox невидимыми.

Слот setColumnRange() инициализирует содержимое выпадающих списков, в соответствии с именами выделенных колонок в электронной таблице. Мы вставили элемент "None", во второй и третий выпадающий списки, на тот случай, если пользователь пожелает выполнить сортировку только по одному столбцу. Не смотря на то, что мы не создавали это слот в Qt Designer, тем не менее он его обнаружит самостоятельно, а uic создаст соответствующее объявление в определении класса SortDialog.

В строках 14 и 15 можно наблюдать один хитрый трюк, связаный с размещением компонента. Функция QWidget::sizeHint() возвращает "идеальный" размер виджета, который пробует соблюсти система размещения. Дело в том, что виджетам с различным содержимым могут быть заданы различные размеры. Для выпадающих списков это означает, что второй и третий списки, содержащие слово "None", могут иметь больший размер, чем первый, в котором указано односимвольное имя столбца. Чтобы избежать такой несогласованности, мы задаем мнимальный размер, для первого выпадающего списка, равный "идеальному" размеру второго.

Ниже приводится текст функции main(), которая устанавливает диапазон выделенных столбцов от "C" до "F" и затем вызывает диалог:

#include <qapplication.h> #include "sortdialog.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); SortDialog *dialog = new SortDialog; app.setMainWidget(dialog); dialog->setColumnRange('C', 'F'); dialog->show(); return app.exec(); } На этом мы завершаем рассмотрение расширяемого диалога. Из примера видно, что разработка расширяемых диалогов ненамного сложнее, чем обычных. Все что нам потребовалось добавить -- это кнопка перехода из режима в режим, несколько дополнительных сигналов и слотов, и фиксированный размер формы.

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

Класс QWidgetStack обсуждается в Главе 6.