Рис. 6.8. Виджеты приложения Splitter.
Можно обеспечить сложную компоновку путем применения вложенных горизонтальных и вертикальных разделителей QSplitter. Например, показанное на рис. 6.9 приложение Mail Client (почтовый клиент) состоит из горизонтального QSplitter, который содержит справа от себя вертикальный QSplitter.
Рис. 6.9. Приложение Mail Client в системе Mac OS X.
Ниже приводится программный код конструктора подкласса QMainWindow приложения Mail Client:
01 MailClient::MailClient()
02 {
03 …
04 rightSplitter = new QSplitter(Qt::Vertical);
05 rightSplitter->addWidget(messagesTreeWidget);
06 rightSplitter->addWidget(textEdit);
07 rightSplitter->setStretchFactor(1, 1);
08 mainSplitter = new QSplitter(Qt::Horizontal);
09 mainSplitter->addWidget(foldersTreeWidget);
10 mainSplitter->addWidget(rigntSplitter);
11 mainSplitter->setStretchFactor(1, 1);
12 setCentralWidget(mainSplitter);
13 setWindowTitle(tr("Mail Client"));
14 readSettings();
15 }
После создания трех виджетов, которые мы собираемся выводить на экран, мы создаем вертикальный разделитель rightSplitter и добавляем два виджета, которые мы собираемся отображать справа. Затем мы создаем горизонтальный разделитель mainSplitter и добавляем виджет, который мы хотим отображать слева, и rightSplitter, виджеты которого мы хотим показывать справа. Мы делаем mainSplitter центральным виджетом QMainWindow.
Когда пользователь изменяет размер окна, QSplitter обычно распределяет пространство таким образом, что относительные размеры дочерних виджетов остаются прежними. В примере приложения Mail Client нам не нужен такой режим работы; вместо этого мы хотим, чтобы QTreeWidget и QTableWidget сохраняли свои размеры, и мы хотим отдавать любое дополнительное пространство полю редактирования QTextEdit. Это достигается с помощью двух вызовов функции setStretchFactor(). В первом аргументе задается индекс дочернего виджета разделителя (индексация начинается с нуля), а во втором аргументе — коэффициент растяжения; по умолчанию используется 0.
Рис.6.10. Индексация разделителя в приложении Mail Client.
Первый вызов setStretchFactor() делаем для rightSplitter, устанавливая виджет в позицию 1 (textEdit) и коэффициент растяжения на 1. Второй вызов setStretcnFactor() делаем для mainSplitter, устанавливая виджет в позицию 1 (rightSplitter) и коэффициент растяжения на 1. Это обеспечивает получение всего дополнительного пространства полем редактирования textEdit.
При запуске приложения разделитель QSplitter задает дочерним виджетам соответствующие размеры на основе их первоначального размера (или на основе их идеального размера, если начальный размер не указан). Мы можем передвигать разделительные линии программно, вызывaя фyнкцию QSplitter::setSizes(). Класс QSplitter предоставляет также средство сохранения своего состояния и его восстановления при следующем запуске приложения. Ниже приводится функция writeSettings(), которая сохраняет настройки Mail Client:
01 void MailClient::writeSettings()
02 {
03 QSettings settings("Software Inc.", "Mail Client");
04 settings.beginGroup("mainWindow");
05 settings.setValue("size", size());
06 settings.setValue("mainSplitter", mainSplitter->saveState());
07 settings.setValue("rightSplitter", rightSplitter->saveState());
08 settings.endGroup();
09 }
Ниже приводится соответствующая функция по чтению настроек readSettings():
01 void MailClient::readSettings()
02 {
03 QSettings settings("Software Inc.", "Mail Client");
04 settings.beginGroup("mainWindow");
05 resize(settings.value("size", QSize(480, 360)).toSize());
06 mainSplitter->restoreState(
07 settings.value("mainSplitter").toByteArray());
08 rightSplitter->restoreState(
09 settings.value("rightSplitter").toByteArray());
10 settings.endGroup();
11 }
Разделитель QSplitter полностью поддерживается Qt Designer. Для размещения виджетов в разделителе поместите дочерние виджеты приблизительно в то место, где они должны находиться, выделите их и выберите пункт меню Form | Lay Out Horizontally in Splitter или Form | Lay Out Vertically in Splitter (Форма | Компоновка no roризонтали в разделитель или Форма | Компоновка по вертикали в разделитель).