Каждый из виджетов, помещаемый на форму, должен быть размещен в нужном месте и с соответствующими размерами. Виджеты, размеры которых превышают размер формы, могут снабжаться полосами прокрутки, чтобы пользователь мог просмотреть все его содержимое. В этой главе мы рассмотрим различные способы размещения виджетов на форме и покажем, как реализовать отстыковываемые (dockable) окна и многодокументный интерфейс (MDI).
Qt предоставляет три основных способа управления размещением подчиненных виджетов на форме: абсолютное позиционирование, ручное управление размещением и менеджеры компоновки. Мы рассмотрим каждый из них, на примере диалога "Find File", показанный на рисунке 6.1.
Рисунок 6.1. Диалог "Find File".
FindFileDialog::FindFileDialog(QWidget *parent, const char *name)
: QDialog(parent, name)
{
...
namedLabel->setGeometry(10, 10, 50, 20);
namedLineEdit->setGeometry(70, 10, 200, 20);
lookInLabel->setGeometry(10, 35, 50, 20);
lookInLineEdit->setGeometry(70, 35, 200, 20);
subfoldersCheckBox->setGeometry(10, 60, 260, 20);
listView->setGeometry(10, 85, 260, 100);
messageLabel->setGeometry(10, 190, 260, 20);
findButton->setGeometry(275, 10, 80, 25);
stopButton->setGeometry(275, 40, 80, 25);
closeButton->setGeometry(275, 70, 80, 25);
helpButton->setGeometry(275, 185, 80, 25);
setFixedSize(365, 220);
}
Абсолютное позиционирование имеет массу недостатков. Самый
главный недостаток -- невозможность изменить размеры окна. Другой
недостаток: текст меток может не умещаться в заданные размеры, если
пользователь выбрал большой размер шрифта или, если интерфейс
приложения был переведен на другой язык. Кроме того, этот подход
требует от нас выполнения кропотливой работы по вычислению положения и
размеров виджетов.При ручном управлении размещением виджетов, мы по прежнему должны задавать положение компонентов на форме, но их размеры устанавливаются пропорционально размерам окна. Добиться этого можно за счет перекрытия обработчика события resizeEvent() формы, в котором можно пересчитывать и задавать новые размеры подчиненных виджетов:
FindFileDialog::FindFileDialog(QWidget *parent, const char *name)
: QDialog(parent, name)
{
...
setMinimumSize(215, 170);
resize(365, 220);
}
void FindFileDialog::resizeEvent(QResizeEvent *)
{
int extraWidth = width() - minimumWidth();
int extraHeight = height() - minimumHeight();
namedLabel->setGeometry(10, 10, 50, 20);
namedLineEdit->setGeometry(70, 10, 50 + extraWidth, 20);
lookInLabel->setGeometry(10, 35, 50, 20);
lookInLineEdit->setGeometry(70, 35, 50 + extraWidth, 20);
subfoldersCheckBox->setGeometry(10, 60, 110 + extraWidth, 20);
listView->setGeometry(10, 85,
110 + extraWidth, 50 + extraHeight);
messageLabel->setGeometry(10, 140 + extraHeight,
110 + extraWidth, 20);
findButton->setGeometry(125 + extraWidth, 10, 80, 25);
stopButton->setGeometry(125 + extraWidth, 40, 80, 25);
closeButton->setGeometry(125 + extraWidth, 70, 80, 25);
helpButton->setGeometry(125 + extraWidth, 135 + extraHeight,
80, 25);
}
В конструкторе мы установили минимальные размеры формы 215 X 170
и начальный размер 365 X 220. В обработчике
resizeEvent() устанавливаются новые размеры виджетов при
изменении размеров окна.Как и в случае с абсолютным позиционированием, ручное управление размещением требует от программиста предварительного вычисления некоторых констант, которые потом жестко зашиваются в код программы. Написание таких программ очень утомительное занятие, особенно если потом потребуется внести изменения в дизайн формы. По прежнему сохраняется риск того, что какие-то надписи на форме не поместятся в отведенное им пространство. Избежать этого можно, если учитывать "идеальные" размеры виджетов, но это еще больше усложнит код.
Рисунок 6.2. Диалог "Find File" с изменяемыми размерами.
В Qt имеется три вида менеджеров компоновки: QHBoxLayout, QVBoxLayout и QGridLayout. Это классы-потомки от QLayout, который реализует основные методы управления размещением. Все три класса полностью поддерживаются Qt Designer-ом, а так же могут использоваться при написании кода вручную. Оба варианта использования были рассмотрены в Главе 2.
Ниже приводится конструктор FindFileDialog, в котором используются менеджеры размещения:
FindFileDialog::FindFileDialog(QWidget *parent, const char *name)
: QDialog(parent, name)
{
...
QGridLayout *leftLayout = new QGridLayout;
leftLayout->addWidget(namedLabel, 0, 0);
leftLayout->addWidget(namedLineEdit, 0, 1);
leftLayout->addWidget(lookInLabel, 1, 0);
leftLayout->addWidget(lookInLineEdit, 1, 1);
leftLayout->addMultiCellWidget(subfoldersCheckBox, 2, 2, 0, 1);
leftLayout->addMultiCellWidget(listView, 3, 3, 0, 1);
leftLayout->addMultiCellWidget(messageLabel, 4, 4, 0, 1);
QVBoxLayout *rightLayout = new QVBoxLayout;
rightLayout->addWidget(findButton);
rightLayout->addWidget(stopButton);
rightLayout->addWidget(closeButton);
rightLayout->addStretch(1);
rightLayout->addWidget(helpButton);
QHBoxLayout *mainLayout = new QHBoxLayout(this);
mainLayout->setMargin(11);
mainLayout->setSpacing(6);
mainLayout->addLayout(leftLayout);
mainLayout->addLayout(rightLayout);
}
Размещением компонентов на форме управляют один QHBoxLayout, один QGridLayout и один QVBoxLayout. QGridLayout и
QVBoxLayout расположены рядом друг с
дружкой, внутри QHBoxLayout. Рамка вокруг
формы имеет ширину 11 пикселей, промежутки между подчиненными виджетами
-- 6 пикселей.
Рисунок 6.3. Раскладка диалога "Find File".
leftLayout->addMultiCellWidget(widget, row1, row2, col1, col2);
где widget -- это подчиненный
виджет, передаваемый этому менеджеру компоновки,
row1, col1 -- верхняя левая ячейка, которую
занимает виджет и row2, col2
-- правая нижняя ячейка.Тот же самый диалог может быть создан с помощью визуального построителя Qt Designer. Пример работы с визуальным построителем, мы рассматривали в Главе 2.
Использование менеджеров размещения дает определенные преимущества, которые мы уже обсуждали ранее. Если в область компоновки добавляется виджет или удаляется из нее, менеджер автоматически адаптируется под изменившиеся условия. То же самое применимо и к случаю, когда вызываются методы подчиненного компонента -- hide() и show(). Если подчиненный виджет изменит "идеальный" размер, то раскладка изменится, с учетом изменившихся обстоятельств. Кроме того, менеджеры размещения автоматически установят минимальный размер формы в целом, основываясь на минимальных и "идеальных" размерах дочерних виджетов.
Во всех примерах, которые мы до сих пор рассматривали, мы просто объединяли виджеты менеджерами размещения и добавляли дополнительные распорки, для утилизации свободного пространства. Но иногда, чтобы расположение компонентов полностью соответствовало нашим желаниям, этого бывает недостаточно. В таких ситуациях необходимо дополнительно настраивать политики изменения размеров и "идеальные" размеры виджетов.
Политика изменения размеров сообщает менеджеру компоновки, как виджет должен растягиваться или сжиматься. Qt по-умолчанию дает неплохие значения политики изменения размеров для всех стандартных виджетов, но никакое значение по-умолчанию не может идеально подходить под все случаи жизни. Поэтому, до сих пор обычной практикой считается дополнительная настройка политик изменения размеров для одного-двух виджетов на форме. Политика изменения размеров назначается для каждого из двух направлений (по вертикали и по горизонтали). Наиболее часто используются значения Fixed, Minimum, Maximum, Preferred и Expanding:
Fixed -- виджет имеет фиксированные размеры, т.е. он не может ни растягиваться, ни сжиматься. Он всегда должен иметь "идеальный" ( sizeHint() ) размер.
Minimum -- "идеальный" размер виджета, это минимально возможный его размер. Виджет не может сжиматься меньше этого размера, но может растягиваться и занимать все доступное пространство, если это потребуется.
Maximum -- "идеальный" размер виджета, это максимально возможный его размер, т.е. виджет может сжиматься до минимально возможного размера, но не может растягиваться больше "идеального".
Preferred -- "идеальный" размер виджета, это предпочтительный его размер, но в случае необходимости виджет может как растягиваться, так и сжиматься.
Expanding -- виджет может и растягиваться, и сжиматься, но он предпочитает растягиваться.
Рисунок 6.4. Различные политики изменения размеров.
Существует еще две политики изменения размеров: MinimumExpanding и Ignored. Первая из них использовалась в ранних версиях Qt, хотя и довольно редко, в настоящее время не играет большой роли, поскольку лучший результат дает назначение политики Expanding и повторная реализация (перекрытие) метода minimumSizeHint(). Вторая -- во многом похожа на Expanding, но при этом игнорирует "идеальные" размеры виджета.
В дополнение к политикам изменения размера, горизонтальная и вертикальная составляющие визуального компонента, QSizePolicy хранят факторы растяжения. Они используются для задания степени растяжимости. Например, предположим, что на форме находятся QListView, а под ним -- QTextEdit. Нам необходимо, чтобы при растягивании формы QTextEdit рос в два раза быстрее, чем QListView. Для этого, фактор растягивания по вертикали (verticalStretch) компонента QTextEdit устанавливаем равным 2, а QListView -- 1.
Еще один способ воздействовать на порядок расположения -- изменять минимальный и максимальный размеры подчиненных виджетов. Менеджер компоновки будет учитывать значения этих параметров.
Пред. | В начало | След. |
Углубленные сведения | На уровень выше | Разделители. |