[Предыдущая: Классы виджетов] [Виджеты и компоновки] [Следующая: Стили] Управление компоновкой
|
QBoxLayout | Выравнивает дочерние виджеты по горизонтали или по вертикали |
---|---|
QButtonGroup | Контейнер для управления группой виджетов-кнопок |
QFormLayout | Управляет формой виджетов ввода информации и связанных с ними меток |
QGraphicsAnchor | Представляет якорь между двумя элементами в QGraphicsAnchorLayout |
QGraphicsAnchorLayout | Компоновщик, в котором можно скреплять виджеты вместе в графическом представлении |
QGridLayout | Размещает виджеты в сетке |
QGroupBox | Рамка с заголовком для панели-контейнера |
QHBoxLayout | Выстраивает виджеты в горизонтальный ряд |
QLayout | Базовый класс для менеджеров компоновки |
QLayoutItem | Абстрактный элемент, которым манипулирует QLayout |
QSizePolicy | Атрибут компоновки, описывающий политику изменения размера в вертикальном и горизонтальном направлении |
QSpacerItem | Пустое пространство в компоновке |
QStackedLayout | Стек виджетов, в котором в один момент виден только один виджет |
QStackedWidget | Стек виджетов, в котором в один момент виден только один виджет |
QVBoxLayout | Выстраивает виджеты в линию по вертикали |
QWidgetItem | Элемент компоновки, представляющий виджет |
Самый легкий способ задания правильного расположения виджетов состоит в использовании встроенных менеджеров компоновки: QHBoxLayout, QVBoxLayout, QGridLayout и QFormLayout. Эти классы унаследованы от QLayout, который, в свою очередь, происходит от QObject (а не от QWidget). Они берут на себя заботы по управлению геометрией множества виджетов. Для создания более сложных компоновок вы можете помещать менеджеры компоновок друг в друга.
В следующем коде создается QHBoxLayout, управляющий геометрией пяти QPushButton, как это показано на первом снимке экрана:
QWidget *window = new QWidget; QPushButton *button1 = new QPushButton("One"); QPushButton *button2 = new QPushButton("Two"); QPushButton *button3 = new QPushButton("Three"); QPushButton *button4 = new QPushButton("Four"); QPushButton *button5 = new QPushButton("Five"); QHBoxLayout *layout = new QHBoxLayout; layout->addWidget(button1); layout->addWidget(button2); layout->addWidget(button3); layout->addWidget(button4); layout->addWidget(button5); window->setLayout(layout); window->show();
Код для QVBoxLayout идентичен, за исключением строки, в которой создается компоновщик. Код для QGridLayout немного другой, так как мы должны задавать строки и столбцы, в которых располагаются дочерние виджеты:
QWidget *window = new QWidget; QPushButton *button1 = new QPushButton("One"); QPushButton *button2 = new QPushButton("Two"); QPushButton *button3 = new QPushButton("Three"); QPushButton *button4 = new QPushButton("Four"); QPushButton *button5 = new QPushButton("Five"); QGridLayout *layout = new QGridLayout; layout->addWidget(button1, 0, 0); layout->addWidget(button2, 0, 1); layout->addWidget(button3, 1, 0, 1, 2); layout->addWidget(button4, 2, 0); layout->addWidget(button5, 2, 1); window->setLayout(layout); window->show();
Третий виджет QPushButton растягивается на 2 колонки. Это задается с помощью передачи числа 2 в качестве пятого аргумента в QGridLayout::addWidget().
В заключение код для QFormLayout - это ..
Если вы используете компоновщик, то при создании дочерних виджетов вы не должны передавать родителя в их конструктор. Компоновщик автоматически изменит родителя виджетов (используя QWidget::setParent()), так, чтобы они стали дочерними виджетами по отношению к виджету, на котором он (компоновщик) установлен.
Замечание: Компонуемые виджеты являются дочерними виджетами по отношению к виджету, на котором расположен компоновщик, а не по отношению к самому компоновщику. Виджеты могут иметь в качестве родителя другой виджет, но не компоновщик.
Вы можете вставлять компоновщики в другой компоновщик с помощью addLayout()(); в этом случае внутренний компоновщик становится дочерним по отношению к внешнему.
При добавлении виджета в компоновщик, компоновщик выполняет следующие действия:
Виджеты, обычно, создаются без заданного коэффициента растяжения. При помещении виджета в компоновщик ему выделяется часть общего пространства, в соответствии с максимальным значением из QWidget::sizePolicy() и предпочтения минимального размера. Коэффициенты растяжения используются для изменения пропорций, по отношению друг к другу, частей общего пространства выделяемых каждому виджету.
Если имеются три виджета, размещаемые с помощью QHBoxLayout без установленных коэффициентов растяжения, то получается размещение подобное следующему:
При применении коэффициентов растяжения к каждому виджету, виджеты будут размещены пропорционально (но никогда не станут меньше своего минимального размера), например
При создании своего класса виджета, вы должны сообщить о его свойствах расположения. Если виджет имеет одну из компоновок Qt, то он позаботится об этом. Если виджет не имеет дочерних виджетов или использует свой компоновщик, то, используя следующие механизмы, вы можете изменить поведение виджета:
Вызывайте QWidget::updateGeometry() всякий раз, когда изменяется минимальный размер, предпочитаемый минимальный размер или политика размера. Это вызовет перерасчет компоновки. Многократные последовательные вызовы QWidget::updateGeometry() приведут только к одному перерасчету компоновки.
Если предпочитаемая высота вашего виджета зависит от его текущей ширины (например, в метке с автоматическим переносом слов), установите флаг высота-по-ширине (height-for-width) в политике размера (size policy) виджета и переопределите QWidget::heightForWidth().
Даже если вы реализовали QWidget::heightForWidth(), будет неплохо определить также и подходящий sizeHint().
Для получения дальнейших инструкций по реализации данных функций смотрите в Qt Quarterly статью Установка высоты в зависимости от ширины.
Использование форматированного текста в виджете метки может вызвать некоторые проблемы при компоновке его родительского виджета. Проблема возникает из-за способа обработки форматированного текста менеджерами компоновки Qt, если метка переносит текст по словам.
В некоторых случаях родительский компоновщик размещается в режиме QLayout::FreeResize, что означает отказ от адаптации содержимого компоновщика к внутренностям маленьких окон, или даже запрет пользователю на создание окон, слишком маленьких для использования. Это можно преодолеть, создав подклассы проблемных виджетов и реализовав подходящим образом функции sizeHint() и minimumSizeHint().
В некоторых случаях, это существенно когда компоновка добавлена на виджет. Когда вы устанавливаете прикрепляемый виджет QDockWidget или прокручиваемую область QScrollArea (вместе с QDockWidget::setWidget() и QScrollArea::setWidget()), компоновщик должен уже установлена на виджет. Если нет, то виджет не будет виден.
Если вы создаете один из видов специального компоновщика, вы также можете создать один из пользовательских виджетов, как это описано выше. Заново реализуйте QWidget::resizeEvent() для расчета требуемых размеров и вызова setGeometry() для каждого дочернего объекта.
Когда будет необходимо произвести пересчет компоновки, виджет получит событие типа QEvent::LayoutRequest. Заново реализуйте QWidget::event() чтобы обработать сообщения QEvent::LayoutRequest.
Альтернативой ручной компоновке является написание вашего собственного менеджера компоновки создав подкласс QLayout. Примеры Border Layout и Flow Layout показывают, как это сделать.
Здесь мы представим подробный пример. Класс CardLayout является подобием менеджера компоновки Java с подобным названием. Он размещает элементы (виджеты или вложенные компоновщики) поверх друг друга, каждый элемент сдвигается на QLayout::spacing().
При написании вашего класса компоновки, вы должны определить следующее:
В большинстве случаев, вы также должны реализовать minimumSize().
#ifndef CARD_H #define CARD_H #include <QtGui> #include <QList> class CardLayout : public QLayout { public: CardLayout(QWidget *parent, int dist): QLayout(parent, 0, dist) {} CardLayout(QLayout *parent, int dist): QLayout(parent, dist) {} CardLayout(int dist): QLayout(dist) {} ~CardLayout(); void addItem(QLayoutItem *item); QSize sizeHint() const; QSize minimumSize() const; QLayoutItem *count() const; QLayoutItem *itemAt(int) const; QLayoutItem *takeAt(int); void setGeometry(const QRect &rect); private: QList<QLayoutItem*> list; }; #endif
//#include "card.h"
Сначала мы определили count() для получения количества элементов в списке.
QLayoutItem *CardLayout::count() const { // QList::size() возвращает количеством элементов QLayoutItem в списке return list.size(); }
Затем мы реализуем две функции, позволяющие перебирать элементы компоновщика и удалять их: itemAt() и takeAt(). Эти функции используются внутренней системой компоновщика для удаления виджетов. Они также доступны прикладным программистам.
itemAt() возвращает элемент с заданным индексом. takeAt() удаляет элемент с заданным индексом и возвращает его. В нашем случае мы используем индекс списка как индекс компоновщика. В других случаях, когда мы имеем более сложную структуру данных, нам, вероятно, потребуется больше усилий для определения линейного порядка элементов.
QLayoutItem *CardLayout::itemAt(int idx) const { // QList::value() выполняет проверку индекса и возвращает 0, если он находится // вне диапазона значений return list.value(idx); } QLayoutItem *CardLayout::takeAt(int idx) { // QList::take не выполняет проверку индекса return idx >= 0 && idx < list.size() ? list.takeAt(idx) : 0; }
addItem() реализует стратегию размещения элементов компоновщика по умолчанию. Функция должна быть реализована. Она используется QLayout::add(), конструктором QLayout, принимающим компоновщик в качестве родителя. Если ваш компоновщик имеет дополнительные опции размещения, которым требуются параметры, то вы должны предоставить дополнительные функции доступа, такие как объединение строк и столбцов, перегружая QGridLayout::addItem(), QGridLayout::addWidget() и QGridLayout::addLayout().
void CardLayout::addItem(QLayoutItem *item) { list.append(item); }
Компоновщик принимает ответственность за добавление элементов. Так как QLayoutItem не наследует QObject, мы должны удалять записи вручную. В деструкторе мы удаляем каждый элемент списка используя takeAt(), а затем удаляем его.
CardLayout::~CardLayout() { QLayoutItem *item; while ((item = takeAt(0))) delete item; }
Функция setGeometry() выполняет операцию компоновки. Прямоугольник, переданный как аргумент, не включает margin(). Если нужно, используйте spacing() для задания расстояния между элементами.
void CardLayout::setGeometry(const QRect &r) { QLayout::setGeometry(r); if (list.size() == 0) return; int w = r.width() - (list.count() - 1) * spacing(); int h = r.height() - (list.count() - 1) * spacing(); int i = 0; while (i < list.size()) { QLayoutItem *o = list.at(i); QRect geom(r.x() + i * spacing(), r.y() + i * spacing(), w, h); o->setGeometry(geom); ++i; } }
sizeHint() и minimumSize() обычно имеют очень похожие реализации. Размеры, возвращаемые обеими функциями, должны включать spacing(), но не должны включать margin().
QSize CardLayout::sizeHint() const { QSize s(0,0); int n = list.count(); if (n > 0) s = QSize(100,70); // начинаем с подходящим стандартным размером int i = 0; while (i < n) { QLayoutItem *o = list.at(i); s = s.expandedTo(o->sizeHint()); ++i; } return s + n*QSize(spacing(), spacing()); } QSize CardLayout::minimumSize() const { QSize s(0,0); int n = list.count(); int i = 0; while (i < n) { QLayoutItem *o = list.at(i); s = s.expandedTo(o->minimumSize()); ++i; } return s + n*QSize(spacing(), spacing()); }
[Предыдущая: Классы виджетов] [Виджеты и компоновки] [Следующая: Стили]
Авторские права © 2010 Nokia Corporation и/или её дочерние компании | Торговые марки | Qt 4.6.4 |
Попытка перевода Qt документации. Если есть желание присоединиться, или если есть замечания или пожелания, то заходите на форум: Перевод Qt документации на русский язык... Люди внесшие вклад в перевод: Команда переводчиков |