Описания компоновки (управления автоматическим размещением визуальных элементов) которые мне попадались на родном языке мне кажутся не достаточно погружают читателя в реальную проблематику которая стоит за этим процессом. Мне хочется акцентировать внимание на том откуда берется сложность в этом вопросе. Хотелось бы чтобы кто-то покритиковал мои формулировки.


В книжке по QT можно найти вот такой пример управления компоновкой элементов (кнопок например) в окне:

#include <QtWidgets>
int main(int argc, char** argv)
{
    QApplication app(argc, argv);
    app.setApplicationDisplayName("Вложенное размещение");
    QWidget wgt;

    QPushButton* pcmdA = new QPushButton("A");
    QPushButton* pcmdB = new QPushButton("B");
    QPushButton* pcmdC = new QPushButton("C");
    QPushButton* pcmdD = new QPushButton("D");

    QVBoxLayout* pvbxLayout = new QVBoxLayout;
    QHBoxLayout* phbxLayout = new QHBoxLayout;
    phbxLayout->setMargin(5);
    phbxLayout->setSpacing(15);
    //В горизонтальную компоновку
    //добавляем виджеты кнопок pcmdC и pcmdD
    phbxLayout->addWidget(pcmdC);
    phbxLayout->addWidget(pcmdD);

    pvbxLayout->setMargin(5);
    pvbxLayout->setSpacing(15);
    //Виджеты кнопок pcmdA и pcmdB по очереди передаются
    //в метод QLayout::addWidget() вертикальной компоновки pvbxLayout
    pvbxLayout->addWidget(pcmdA);
    pvbxLayout->addWidget(pcmdB);
    //При помощи метода QBoxLayout:: addLayout() 
    //передается объект горизонтальной компоновки phbxLayout
    pvbxLayout->addLayout(phbxLayout);
    //Вызов метода QWidget::setLayout() устанавливает
    //вертикальную компоновку pvbxLayout в виджете wgt
    wgt.setLayout(pvbxLayout);
    wgt.show();
    return app.exec();
}

Этот код создает вот такое окно  с четырьмя кнопками внутри:

созданное окно
созданное окно

Мы можем видеть что код выглядит очень естественно он фактически отражает процесс рисования объектов на экране.

Если коротко сформулировать что здесь закодировано на человеческом языке

  • Мы создаем окно,

    задаем ему способ вертикальной компоновки,

    добавляем два визуальных объекта (две кнопки),

    и устанавливаем способ горизонтальной компоновки для третьего объекта, который будет составным объектом,

    и в который мы добавим еще два визуальных объекта (кнопки) из которых он будет состоять.

Я поясню идею компоновки как я ее понимаю. Qt дает возможность задавать размеры и координаты визуальных элементов (виджетов) внутри контейнера в который они помещены, напрямую вызывая соответствующие методы этих виджетов. Но если вы хотите определить некоторый алгоритм вычисления этих координат и размеров в зависимости от количества виджетов (например) помещенных в один контейнер вы должны будете постоянно выполнять вычисления этих координат и размеров при каждом добавлении виджета в контейнер, но эти параметры нужны только во время отрисовки, то есть когда все контейнеры заполнены и все количества известны. Объект компоновки как раз позволяет отложить эти вычисления координат и размеров до момента перед самым рисованием. Перед тем как отрисовать окно и все дочерние виджеты в нем вызываются функции стандартного интерфейса компоновки, который наследуют все объекты компоновки, чтобы посчитать и задать координаты и размеры всех дочерних элементов в окне. Как мы видим из приведенного примера объекты компоновки также допускают вложенность. В нашем примере объект вертикальной компоновки принимает объект горизонтальной компоновки в качестве дочернего.

Я хочу обратить ваше внимание на некоторую двойственность сущности объекта компоновки в Qt. С одной стороны объект компоновки определяет способ размещения своих дочерних виджетов (вертикальный, горизонтальный, можно создать например горизонтальный с переходом на следующую линию как построчный, можно расставлять наискось, ..., можно придумать неограниченное количество способов компоновки вообще говоря). Способ размещения виджетов это фактически функция (логика) которую мы определяем и отдаем любому виджету чтобы перед отрисовкой его контента, координаты и размеры элементов этого контента сконфигурировались по определенному алгоритму.

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

Как вы думаете как вместо второй кнопки добавить другую пару визуальных объектов (чек-боксов например) по горизонтали?

мое предположение

надо создать вместо кнопки В еще один объект компоновки и добавить в него чек-боксы и потом добавить этот новый QHBoxLayout как первый объект компоновки перед добавлением того QHBoxLayout который уже есть в коде?

Я пока не проверял, если мнения разойдутся мне придется проверить эту свою версию.

 Если проанализировать код, то мы можем представить себе что в нем создается иерархия следующего вида:

1. Главное окно (QWidget wgt)

1.1. -Объект вертикальной компоновки (QVBoxLayout* pvbxLayout)

1.1.1. --Кнопка А

1.1.2. --Кнопка B

1.1.3. --Объект горизонтальной компоновки (QVBoxLayout* pvbxLayout)

1.1.3.1. ---Кнопка С

1.1.3.2. ---Кнопка D

На самом деле такая иерархия не совсем корректна с точки зрения Qt так как объекты компоновки не являются наследниками класса QWidget они являются наследниками класса QLayout и поэтому вместо одной иерархии при программировании мы будем иметь дело с двумя горизонтально связанными иерархиями: иерархия виджетов и иерархия QLayout -ов.

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