Horizontale und vertikale Layouts

Bei diesen beiden Formen von Layouts werden die Widgets von links nach rechts bzw. von oben nach unten angeordnet.
Dazu werden die Layout-Klassen QHBoxLayout (horizontal) und QVBoxLayout (vertikal) verwendet. Widgets werden mit der Funktion addWidget() hinzugefügt. Diese Funktion ist bereits in der Basisklasse QBoxLayout implementiert und wird in den Basisklassen entsprechend der Auslegungsrichtung angepasst:

void QBoxLayout::addWidget( QWidget *widget,
                            int stretch = 0,
                            Qt::Alignment alignment = Qt::Alignment() )

widget: Das einzufügende Widget
stretch: Gibt an, wie sich das Widget bei Vergrößerung des verfügbaren Raumes vergrößert
alignment: Gibt die Ausrichtung des Widgets an (wird von QHBoxLayout bzw. QVBoxLayout automatisch angepasst)

Analog dazu werden Layouts mit der Methode addLayout() hinzugefügt:

void QBoxLayout::addLayout( QLayout *layout,
                            int stretch = 0 )

layout: Das einzufügende Layout
stretch: Gibt an, wie sich das Layout bei Vergrößerung des verfügbaren Raumes vergrößert

Nun wollen wir unser Beispiel zur Synchronisierung von Widgets aus dem vorherigen Kapitel mit Layouts in einem Widget zusammenfassen:

#include <QApplication>
#include <QPushButton>
#include <QSpinBox>
#include <QSlider>
#include <QHBoxLayout>
#include <QVBoxLayout>
 
int main( int argc, char *argv[] )
{
  QApplication app( argc, argv );
  QSpinBox *spinbox;
  QSlider *slider;
  QPushButton *button;
  QHBoxLayout *hlayout;
  QVBoxLayout *vlayout;
  QWidget widget;
 
  // Objekte anlegen
  spinbox = new QSpinBox();
  slider = new QSlider();
  button = new QPushButton( "Quit" );
  hlayout = new QHBoxLayout();
  vlayout = new QVBoxLayout();
 
  // Wertebereich für Spinbox setzen
  spinbox->setMinimum( 0 );
  spinbox->setMaximum( 100 );
 
  // Wertebereich für Slider setzen
  slider->setMinimum( 0 );
  slider->setMaximum( 100 );
  // Slider quer darstellen
  slider->setOrientation( Qt::Horizontal );
 
  // Verbindungen erstellen
  QObject::connect( spinbox, static_cast<void (QSpinBox::*)(int)>( &QSpinBox::valueChanged ),
                    slider, &QSlider::setValue );
  QObject::connect( slider, static_cast<void (QSlider::*)(int)>( &QSlider::valueChanged ),
                    spinbox, &QSpinBox::setValue );
  QObject::connect( button, &QPushButton::clicked,
                    &app, &QApplication::quit );
 
  // Button und Spinbox zusammen in ein vertikales Layout einfügen
  vlayout->addWidget( slider );
  vlayout->addWidget( spinbox );
  // Vertikales Layout und Button in ein horizontales Layout einfügen
  hlayout->addLayout( vlayout );
  hlayout->addWidget( button );
 
  // Layout auf das Widget anwenden und Widget anzeigen
  widget.setWindowTitle( "Layouts" );
  widget.setLayout( hlayout );
  widget.show();
 
  return app.exec();
}

Im Beispiel erstellen wir uns das Hilfswidget widget, dessen einziger Zweck es ist das Layout anzunehmen und die anderen Widgets anzuzeigen. Durch die Verwendung von Layouts wird es zum Elternwidget aller anderen Widgets, die sich im angewandten Layout befinden (slider, spinbox und button).

Für die Widgets werden in diesem Beispiel Zeiger verwendet. Der Grund dafür ist einfach: Wie wir bereits gehört haben, übernimmt das Hauptwidget die Elternschaft über die Widgets in den Layouts. Wird das Hauptwidget zerstört (Aufruf des Destruktors nach main), versucht es den Speicher der Kindwidgets freizugeben. Verwenden wir dann für Widgets keine Zeiger, wird der Speicher der bereits zerstörten Widgets freigegeben. Deshalb sollte man für Widgets, die ein Elternobjekt bekommen, immer Zeiger verwenden. Aufgrund dieser Eigenschaft führt unser Programm auch nicht zu einem Speicherleck.

Hier ein Bild der Anwendung wobei die Verschachtelung der Layouts besonders hervorgehoben wurde (rot = vertikales Layout, grün = horizontales Layout):