6.2. Разделители.

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

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

#include <qapplication.h> #include <qsplitter.h> #include <qtextedit.h> int main(int argc, char *argv[]) { QApplication app(argc, argv); QSplitter splitter(Qt::Horizontal); splitter.setCaption(QObject::tr("Splitter")); app.setMainWidget(&splitter); QTextEdit *firstEditor = new QTextEdit(&splitter); QTextEdit *secondEditor = new QTextEdit(&splitter); QTextEdit *thirdEditor = new QTextEdit(&splitter); splitter.show(); return app.exec(); } На форме находятся три компонента QTextEdit, выровненных по горизонтали виджетом QSplitter. В отличие от менеджера размещения, который отвечает только за размещение подчиненных виджетов, QSplitter является потомком класса QWidget и может использоваться как любой другой виджет.

Рисунок 6.5. Разделитель в приложении.




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

Ниже приводится код конструктора подкласса QMainWindow:

MailClient::MailClient(QWidget *parent, const char *name) : QMainWindow(parent, name) { horizontalSplitter = new QSplitter(Horizontal, this); setCentralWidget(horizontalSplitter); foldersListView = new QListView(horizontalSplitter); foldersListView->addColumn(tr("Folders")); foldersListView->setResizeMode(QListView::AllColumns); verticalSplitter = new QSplitter(Vertical, horizontalSplitter); messagesListView = new QListView(verticalSplitter); messagesListView->addColumn(tr("Subject")); messagesListView->addColumn(tr("Sender")); messagesListView->addColumn(tr("Date")); messagesListView->setAllColumnsShowFocus(true); messagesListView->setShowSortIndicator(true); messagesListView->setResizeMode(QListView::AllColumns); textEdit = new QTextEdit(verticalSplitter); textEdit->setReadOnly(true); horizontalSplitter->setResizeMode(foldersListView, QSplitter::KeepSize); verticalSplitter->setResizeMode(messagesListView, QSplitter::KeepSize); ... readSettings(); } Здесь сначала создается горизонтальный разделитель, после чего он назначается центральным виджетом. Затем создаются подчиненные виджеты.

Рисунок 6.6. Почтовый клиент в Mac OS X.


Когда пользователь изменит размеры окна, QSplitter распределит пространство между подчиненными виджетами таким образом, что относительные их размеры останутся без изменения. Но в случае с почтовым клиентом нам необходимо, чтобы два QListView сохранили свои размеры, а все дополнительное пространство было отдано компоненту QTextEdit. Достигается это парой вызовов setResizeMode().

На запуске приложения, QSplitter устанавливает размеры подчиненных виджетов, основываясь на их начальных размерах. Передвинуть разделитель можно не только вручную, но и программно, вызвав QSplitter::setSizes(). Кроме того, QSplitter предоставляет возможность сохранить свое положение, при завершении работы приложения, и восстановить его на следующем запуске. Ниже приводится функция, которая сохраняет настройки приложения - почтового клиента:

void MailClient::writeSettings() { QSettings settings; settings.setPath("software-inc.com", "MailClient"); settings.beginGroup("/MailClient"); QString str; QTextOStream out1(&str); out1 << *horizontalSplitter; settings.writeEntry("/horizontalSplitter", str); QTextOStream out2(&str); out2 << *verticalSplitter; settings.writeEntry("/verticalSplitter", str); settings.endGroup(); } И, соответствующая ей, функция readSettings(). void MailClient::readSettings() { QSettings settings; settings.setPath("software-inc.com", "MailClient"); settings.beginGroup("/MailClient"); QString str1 = settings.readEntry("/horizontalSplitter"); QTextIStream in1(&str1); in1 >> *horizontalSplitter; QString str2 = settings.readEntry("/verticalSplitter"); QTextIStream in2(&str2); in2 >> *verticalSplitter; settings.endGroup(); } Вся файловые операции, в этих функциях, выполняются через классы QTextIStream и QTextOStream -- потомки класса QTextStream.

По-умолчанию, во время перетаскивания, разделитель отображается в виде рамки. А размеры виджетов, с обеих сторон разделителя, изменяют размер только тогда, когда пользователь отпустит кнопку мыши. Чтобы изменения размеров происходили в реальном времени, необходимо вызвать setOpaqueResize(true).

Разделители QSplitter полностью поддерживаются визуальным построителем Qt Designer. Чтобы поместить виджеты в разделитель -- разместите подчиненные виджеты на форме примерно так, как вы желаете, затем выделите их и выберите пункт меню Layout|Lay Out Horizontally (in Splitter) или Layout|Lay Out Vertically (in Splitter).