Как стать автором
Обновить

Сложность концепции компоновки на примере для QT (шпаргалка)

Уровень сложностиСредний
Время на прочтение4 мин
Количество просмотров3K

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


В книжке по 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 -ов.

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

Теги:
Хабы:
Всего голосов 4: ↑2 и ↓2+2
Комментарии48

Публикации

Работа

QT разработчик
5 вакансий
Программист C++
98 вакансий

Ближайшие события