Usually, CSS is a sufficient and convenient way to indicate how to layout widgets within a container widget, and we recommend to get familiarized with CSS for basic layout and styling.
There are however several situations when CSS is not effective to create a layout, especially for complex web applications. In particular, when placing contents within a dialog it is often necessary to adjust its contents to available vertical space, and it is often desirable to distribute excess space to a particular widget while keeping other widgets to their preferred size. It is for these reasons that Wt has a comprehensive set of layout managers that use JavaScript to compute and apply layout management to children of a WContainerWidget.
Wt provides the typical box, grid or border layout management options and layout managers and CSS can safely be intermixed.
WVBoxLayout and WHBoxLayout provide respectively vertical and horizontal layout of widgets inside a WContainerWidget.
In a horizontal box layout, widgets are given an appropriate width based on available space in the container and layout rules, while all widgets get the same height. Similarly, in a vertical box layout, widgets are given appropriate heights based on available space in the container and layout rules, while all widgets get the same width.
In the example below, a WHBoxLayout
with default
padding (9 pixels) and spacing (6 pixels) is used to manage two
child widgets. If no stretch factors have been specified, space
is evenly distributed to all widgets.
By giving Item 1 a non-zero stretch factor value of 1, Item 2 will only use its preferred width, and Item 1 consumes all excess space, as illustrated below.
#include <Wt/WContainerWidget.h>
#include <Wt/WHBoxLayout.h>
#include <Wt/WText.h>
#include <memory>
auto container = std::make_unique<Wt::WContainerWidget>();
container->setStyleClass("yellow-box");
auto hbox = container->setLayout(std::make_unique<Wt::WHBoxLayout>());
auto item = std::make_unique<Wt::WText>("Item 1");
item->setStyleClass("green-box");
hbox->addWidget(std::move(item), 1);
item = std::make_unique<Wt::WText>("Item 2");
item->setStyleClass("blue-box");
hbox->addWidget(std::move(item));
The preferred width of a widget is either based on its contents
(which for text is the in some cases impractical assumption of
putting all text on a single line), but can be further
controlled using widget->setWidth()
or CSS
width
settings.
The WVBoxLayout
works in exactly the same way, but
stacks children vertically.
#include <Wt/WContainerWidget.h>
#include <Wt/WText.h>
#include <Wt/WVBoxLayout.h>
auto container = std::make_unique<Wt::WContainerWidget>();
container->resize(150, 150);
container->setStyleClass("yellow-box centered");
auto vbox = container->setLayout(std::make_unique<Wt::WVBoxLayout>());
auto item = std::make_unique<Wt::WText>("Item 1");
item->setStyleClass("green-box");
vbox->addWidget(std::move(item));
item = std::make_unique<Wt::WText>("Item 2");
item->setStyleClass("blue-box");
vbox->addWidget(std::move(item));
#include <Wt/WContainerWidget.h>
#include <Wt/WText.h>
#include <Wt/WVBoxLayout.h>
auto container = std::make_unique<Wt::WContainerWidget>();
container->resize(150, 150);
container->setStyleClass("yellow-box centered");
auto vbox = container->setLayout(std::make_unique<Wt::WVBoxLayout>());
auto item = std::make_unique<Wt::WText>("Item 1");
item->setStyleClass("green-box");
vbox->addWidget(std::move(item), 1);
item = std::make_unique<Wt::WText>("Item 2");
item->setStyleClass("blue-box");
vbox->addWidget(std::move(item));
Layout managers may be arbitrarily nested, either directly, or indirectly through widget composition, to create complex layouts. Layout managers fully cooperate with CSS, honoring the CSS margins and paddings of children, but also those of intermediate widgets in complex layouts.
In the example below we nest a WHBoxLayout
containing
two items in a WVBoxLayout
containing one other item.
#include <Wt/WContainerWidget.h>
#include <Wt/WHBoxLayout.h>
#include <Wt/WText.h>
#include <Wt/WVBoxLayout.h>
auto container = std::make_unique<Wt::WContainerWidget>();
container->resize(200, 200);
container->setStyleClass("yellow-box centered");
auto vbox = container->setLayout(std::make_unique<Wt::WVBoxLayout>());
auto item = std::make_unique<Wt::WText>("Item 1");
item->setStyleClass("green-box");
vbox->addWidget(std::move(item), 1);
auto hbox = vbox->addLayout(std::make_unique<Wt::WHBoxLayout>());
item = std::make_unique<Wt::WText>("Item 2");
item->setStyleClass("green-box");
hbox->addWidget(std::move(item));
item = std::make_unique<Wt::WText>("Item 3");
item->setStyleClass("blue-box");
hbox->addWidget(std::move(item));
This layout manager organizes the contents of a WContainerWidget
in a grid.
Like WBoxLayout
, a
stretch factor defined for rows or columns is used to distribute
excess space. In the example below, row 1 and columns 1 and 2
are given a non-zero stretch factor.
Item (0, 0) | Item (0, 1) | Item (0, 2) | Item (0, 3) |
Item (1, 0) | Item (1, 1) | Item (1, 2) | Item (1, 3) |
Item (2, 0) | Item (2, 1) | Item (2, 2) | Item (2, 3) |
#include <Wt/WContainerWidget.h>
#include <Wt/WGridLayout.h>
#include <Wt/WText.h>
auto container = std::make_unique<Wt::WContainerWidget>();
container->setHeight(400);
container->setStyleClass("yellow-box");
auto grid = container->setLayout(std::make_unique<Wt::WGridLayout>());
for (int row = 0; row < 3; ++row) {
for (int column = 0; column < 4; ++column) {
Wt::WString cell = Wt::WString("Item ({1}, {2})").arg(row).arg(column);
auto text = std::make_unique<Wt::WText>(cell);
if (row == 1 || column == 1 || column == 2)
text->setStyleClass("blue-box");
else
text->setStyleClass("green-box");
grid->addWidget(std::move(text), row, column);
}
}
grid->setRowStretch(1, 1);
grid->setColumnStretch(1, 1);
grid->setColumnStretch(2, 1);
This is a layout manager that organizes the container space in up to 5 regions, with a central region consuming any excess space.
Any of the regions can be omitted.
North item | ||
West item | Center item | East item |
South item |
#include <Wt/WContainerWidget.h>
#include <Wt/WBorderLayout.h>
#include <Wt/WText.h>
auto container = std::make_unique<Wt::WContainerWidget>();
container->setHeight(400);
container->setStyleClass("yellow-box");
auto layout = container->setLayout(std::make_unique<Wt::WBorderLayout>());
const char *cell = "{1} item";
auto item = std::make_unique<Wt::WText>(Wt::WString(cell).arg("North"));
item->setStyleClass("green-box");
layout->addWidget(std::move(item), Wt::LayoutPosition::North);
item = std::make_unique<Wt::WText>(Wt::WString(cell).arg("West"));
item->setStyleClass("green-box");
layout->addWidget(std::move(item), Wt::LayoutPosition::West);
item = std::make_unique<Wt::WText>(Wt::WString(cell).arg("East"));
item->setStyleClass("green-box");
layout->addWidget(std::move(item), Wt::LayoutPosition::East);
item = std::make_unique<Wt::WText>(Wt::WString(cell).arg("South"));
item->setStyleClass("green-box");
layout->addWidget(std::move(item), Wt::LayoutPosition::South);
item = std::make_unique<Wt::WText>(Wt::WString(cell).arg("Center"));
item->setStyleClass("green-box");
layout->addWidget(std::move(item), Wt::LayoutPosition::Center);