Update Sliders example

Simplify the "responsive layout" implementation. Just use a QBoxLayout
with changing direction instead of repopulating a QGridLayout, and
change the orientation of one set of sliders instead of creating two
sets in a stacked layout.

Simplify the resizeEvent() implementation accordingly.

Update the documentation snippet text to match the code, and document
the resizeEvent() override.

Fixes: QTBUG-119977
Change-Id: I73a1bb215c956fa283291ebf0ea45ff9a975c727
Reviewed-by: Axel Spoerl <axel.spoerl@qt.io>
(cherry picked from commit f3fb89ba298e1741320d8bfac9cbd0d503373bff)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
(cherry picked from commit 2d3ee8ac34bdf30ffc14054a8aeb64ba292bb96e)
This commit is contained in:
Volker Hilsheimer 2023-12-18 16:39:34 +01:00 committed by Qt Cherry-pick Bot
parent 493c596a6c
commit b791b19d3d
6 changed files with 97 additions and 136 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 23 KiB

View File

@ -18,7 +18,8 @@
manipulated through their properties.
The example also demonstrates how signals and slots can be used to
synchronize the behavior of two or more widgets.
synchronize the behavior of two or more widgets, and how to override
\l{QWidget::}{resizeEvent()} to implement a responsive layout.
\borderedimage sliders-example.png
\caption Screenshot of the Sliders example
@ -31,10 +32,8 @@
QScrollBar and a QDial.
\li \c Window is the main widget combining a QGroupBox and a
QStackedWidget. In this example, the QStackedWidget provides a
stack of two \c SlidersGroup widgets. The QGroupBox contain
several widgets that control the behavior of the slider-like
widgets.
SlidersGroup. The QGroupBox contains several widgets that control
the behavior of the slider-like widgets.
\endlist
@ -56,28 +55,14 @@
\snippet widgets/sliders/window.cpp 0
In the constructor we first create the two \c SlidersGroup
widgets that display the slider widgets horizontally and
vertically, and add them to the QStackedWidget. QStackedWidget
provides a stack of widgets where only the top widget is visible.
With \c createControls() we create a connection from a
controlling widget to the QStackedWidget, making the user able to
choose between horizontal and vertical orientation of the slider
widgets. The rest of the controlling mechanisms is implemented by
the same function call.
In the constructor we first create the \c SlidersGroup widget
that displays the slider widgets. With \c createControls() we
create the controlling widgets, and connect those to to the
sliders.
\snippet widgets/sliders/window.cpp 1
\snippet widgets/sliders/window.cpp 2
Then we connect the \c horizontalSliders, \c verticalSliders and
\c valueSpinBox to each other, so that the slider widgets and the
control widget will behave synchronized when the current value of
one of them changes. The \c valueChanged() signal is emitted with
the new value as argument. The \c setValue() slot sets the
current value of the widget to the new value, and emits \c
valueChanged() if the new value is different from the old one.
We put the group of control widgets and the stacked widget in a
We put the groups of control widgets and the sliders in a
horizontal layout before we initialize the minimum, maximum and
current values. The initialization of the current value will
propagate to the slider widgets through the connection we made
@ -85,15 +70,14 @@
minimum and maximum values propagate through the connections we
created with \c createControls().
\snippet widgets/sliders/window.cpp 2
\snippet widgets/sliders/window.cpp 3
\snippet widgets/sliders/window.cpp 4
In the private \c createControls() function, we let a QGroupBox
(\c controlsGroup) display the control widgets. A group box can
provide a frame, a title and a keyboard shortcut, and displays
various other widgets inside itself. The group of control widgets
is composed by two checkboxes, three spin boxes (with labels) and
one combobox.
is composed by two checkboxes, and three spin boxes with labels.
After creating the labels, we create the two checkboxes.
Checkboxes are typically used to represent features in an
@ -131,8 +115,8 @@
bindings are inverted by default: \uicontrol PageDown increases the
current value, and \uicontrol PageUp decreases it.
\snippet widgets/sliders/window.cpp 4
\snippet widgets/sliders/window.cpp 5
\snippet widgets/sliders/window.cpp 6
Then we create the spin boxes. QSpinBox allows the user to choose
a value by clicking the up and down buttons or pressing the \uicontrol
@ -141,14 +125,15 @@
manually. The spin boxes control the minimum, maximum and current
values for the QSlider, QScrollBar, and QDial widgets.
We create a QComboBox that allows the user to choose the
orientation of the slider widgets. The QComboBox widget is a
combined button and popup list. It provides a means of presenting
a list of options to the user in a way that takes up the minimum
amount of screen space.
\snippet widgets/sliders/window.cpp 6
\snippet widgets/sliders/window.cpp 7
\snippet widgets/sliders/window.cpp 8
Then we connect the \c slidersGroup and the \c valueSpinBox to each
other, so that the slider widgets and the control widget will behave
synchronized when the current value of one of them changes.
The \c valueChanged() signal is emitted with the new value as
argument. The \c setValue() slot sets the current value of the
widget to the new value, and emits \c valueChanged() if the new
value is different from the old one.
We synchronize the behavior of the control widgets and the slider
widgets through their signals and slots. We connect each control
@ -158,6 +143,17 @@
lay out the control widgets in a QGridLayout within the \c
controlsGroup group box.
\snippet widgets/sliders/window.cpp 7
Lastly, we override resizeEvent() from QWidget. We guard against
dividing by zero, and otherwise compute the aspect ratio of the
widget. If the window has a portrait format, then we set the
layout to organize the groups of control widgets and sliders
vertically, and we give the sliders a horizontal orientation.
If the window has a landscape format, then we change the layout
to show the sliders and controlling widgets side by side, and
give the sliders a vertical orientation.
\section1 SlidersGroup Class Definition
\snippet widgets/sliders/slidersgroup.h 0
@ -170,7 +166,8 @@
slot with equivalent functionality to the ones in QAbstractSlider
and QSpinBox. In addition, we implement several other public
slots to set the minimum and maximum value, and invert the slider
widgets' appearance as well as key bindings.
widgets' appearance as well as key bindings, and set the
orientation.
\section1 SlidersGroup Class Implementation
@ -183,24 +180,21 @@
focus. The Qt::StrongFocus policy means that the widget accepts
focus by both tabbing and clicking.
\snippet widgets/sliders/slidersgroup.cpp 1
Then we connect the widgets with each other, so that they will
stay synchronized when the current value of one of them changes.
\snippet widgets/sliders/slidersgroup.cpp 1
\snippet widgets/sliders/slidersgroup.cpp 2
We connect \c {dial}'s \c valueChanged() signal to the
\c{SlidersGroup}'s \c valueChanged() signal, to notify the other
widgets in the application (i.e., the control widgets) of the
changed value.
\snippet widgets/sliders/slidersgroup.cpp 3
\codeline
\snippet widgets/sliders/slidersgroup.cpp 4
Finally, depending on the \l {Qt::Orientation}{orientation} given
at the time of construction, we choose and create the layout for
the slider widgets within the group box.
Finally, we create the layout for the slider widgets within the
group box. We start with a horizontal arrangement of the sliders.
\snippet widgets/sliders/slidersgroup.cpp 5
\snippet widgets/sliders/slidersgroup.cpp 6
@ -233,4 +227,12 @@
\l{QAbstractSlider::invertedAppearance}{invertedAppearance} and
\l{QAbstractSlider::invertedControls}{invertedControls}
properties.
\snippet widgets/sliders/slidersgroup.cpp 15
The setOrientation() slot controls the direction of the layout
and the orientation of the sliders. In a horizontal group, the
sliders have a horizontal orientation, and are laid out on top
of each other. In a vertical group, the sliders have a vertical
orientation, and are laid out next to each other.
*/

View File

@ -9,39 +9,28 @@
#include <QSlider>
//! [0]
SlidersGroup::SlidersGroup(Qt::Orientation orientation, const QString &title,
QWidget *parent)
SlidersGroup::SlidersGroup(const QString &title, QWidget *parent)
: QGroupBox(title, parent)
{
slider = new QSlider(orientation);
slider = new QSlider;
slider->setFocusPolicy(Qt::StrongFocus);
slider->setTickPosition(QSlider::TicksBothSides);
slider->setTickInterval(10);
slider->setSingleStep(1);
scrollBar = new QScrollBar(orientation);
scrollBar = new QScrollBar;
scrollBar->setFocusPolicy(Qt::StrongFocus);
dial = new QDial;
dial->setFocusPolicy(Qt::StrongFocus);
//! [0] //! [1]
connect(slider, &QSlider::valueChanged, scrollBar, &QScrollBar::setValue);
connect(scrollBar, &QScrollBar::valueChanged, dial, &QDial::setValue);
connect(dial, &QDial::valueChanged, slider, &QSlider::setValue);
//! [0] //! [1]
connect(dial, &QDial::valueChanged, this, &SlidersGroup::valueChanged);
//! [1] //! [2]
//! [2] //! [3]
QBoxLayout::Direction direction;
//! [3] //! [4]
if (orientation == Qt::Horizontal)
direction = QBoxLayout::TopToBottom;
else
direction = QBoxLayout::LeftToRight;
QBoxLayout *slidersLayout = new QBoxLayout(direction);
//! [1] //! [4]
slidersLayout = new QBoxLayout(QBoxLayout::LeftToRight);
slidersLayout->addWidget(slider);
slidersLayout->addWidget(scrollBar);
slidersLayout->addWidget(dial);
@ -96,3 +85,14 @@ void SlidersGroup::invertKeyBindings(bool invert)
dial->setInvertedControls(invert);
}
//! [14]
//! [15]
void SlidersGroup::setOrientation(Qt::Orientation orientation)
{
slidersLayout->setDirection(orientation == Qt::Horizontal
? QBoxLayout::TopToBottom
: QBoxLayout::LeftToRight);
scrollBar->setOrientation(orientation);
slider->setOrientation(orientation);
}
//! [15]

View File

@ -10,6 +10,7 @@ QT_BEGIN_NAMESPACE
class QDial;
class QScrollBar;
class QSlider;
class QBoxLayout;
QT_END_NAMESPACE
//! [0]
@ -18,8 +19,7 @@ class SlidersGroup : public QGroupBox
Q_OBJECT
public:
SlidersGroup(Qt::Orientation orientation, const QString &title,
QWidget *parent = nullptr);
SlidersGroup(const QString &title, QWidget *parent = nullptr);
signals:
void valueChanged(int value);
@ -30,11 +30,13 @@ public slots:
void setMaximum(int value);
void invertAppearance(bool invert);
void invertKeyBindings(bool invert);
void setOrientation(Qt::Orientation orientation);
private:
QSlider *slider;
QScrollBar *scrollBar;
QDial *dial;
QBoxLayout *slidersLayout;
};
//! [0]

View File

@ -13,29 +13,15 @@
Window::Window(QWidget *parent)
: QWidget(parent)
{
horizontalSliders = new SlidersGroup(Qt::Horizontal, tr("Horizontal"));
verticalSliders = new SlidersGroup(Qt::Vertical, tr("Vertical"));
stackedWidget = new QStackedWidget;
stackedWidget->addWidget(horizontalSliders);
stackedWidget->addWidget(verticalSliders);
slidersGroup = new SlidersGroup(tr("Sliders"));
createControls(tr("Controls"));
//! [0]
//! [1]
connect(horizontalSliders, &SlidersGroup::valueChanged,
//! [1] //! [2]
verticalSliders, &SlidersGroup::setValue);
connect(verticalSliders, &SlidersGroup::valueChanged,
valueSpinBox, &QSpinBox::setValue);
connect(valueSpinBox, &QSpinBox::valueChanged,
horizontalSliders, &SlidersGroup::setValue);
layout = new QGridLayout;
layout->addWidget(stackedWidget, 0, 1);
layout->addWidget(controlsGroup, 0, 0);
layout = new QBoxLayout(QBoxLayout::LeftToRight);
layout->addWidget(controlsGroup);
layout->addWidget(slidersGroup);
setLayout(layout);
minimumSpinBox->setValue(0);
@ -44,11 +30,11 @@ Window::Window(QWidget *parent)
setWindowTitle(tr("Sliders"));
}
//! [2]
//! [1]
//! [3]
//! [2]
void Window::createControls(const QString &title)
//! [3] //! [4]
//! [2] //! [3]
{
controlsGroup = new QGroupBox(title);
@ -59,9 +45,9 @@ void Window::createControls(const QString &title)
invertedAppearance = new QCheckBox(tr("Inverted appearance"));
invertedKeyBindings = new QCheckBox(tr("Inverted key bindings"));
//! [4] //! [5]
//! [3] //! [4]
minimumSpinBox = new QSpinBox;
//! [5] //! [6]
//! [4] //! [5]
minimumSpinBox->setRange(-100, 100);
minimumSpinBox->setSingleStep(1);
@ -73,30 +59,19 @@ void Window::createControls(const QString &title)
valueSpinBox->setRange(-100, 100);
valueSpinBox->setSingleStep(1);
orientationCombo = new QComboBox;
orientationCombo->addItem(tr("Horizontal slider-like widgets"));
orientationCombo->addItem(tr("Vertical slider-like widgets"));
//! [6] //! [7]
connect(orientationCombo, &QComboBox::activated,
//! [7] //! [8]
stackedWidget, &QStackedWidget::setCurrentIndex);
//! [5] //! [6]
connect(slidersGroup, &SlidersGroup::valueChanged,
valueSpinBox, &QSpinBox::setValue);
connect(valueSpinBox, &QSpinBox::valueChanged,
slidersGroup, &SlidersGroup::setValue);
connect(minimumSpinBox, &QSpinBox::valueChanged,
horizontalSliders, &SlidersGroup::setMinimum);
connect(minimumSpinBox, &QSpinBox::valueChanged,
verticalSliders, &SlidersGroup::setMinimum);
slidersGroup, &SlidersGroup::setMinimum);
connect(maximumSpinBox, &QSpinBox::valueChanged,
horizontalSliders, &SlidersGroup::setMaximum);
connect(maximumSpinBox, &QSpinBox::valueChanged,
verticalSliders, &SlidersGroup::setMaximum);
slidersGroup, &SlidersGroup::setMaximum);
connect(invertedAppearance, &QCheckBox::toggled,
horizontalSliders, &SlidersGroup::invertAppearance);
connect(invertedAppearance, &QCheckBox::toggled,
verticalSliders, &SlidersGroup::invertAppearance);
slidersGroup, &SlidersGroup::invertAppearance);
connect(invertedKeyBindings, &QCheckBox::toggled,
horizontalSliders, &SlidersGroup::invertKeyBindings);
connect(invertedKeyBindings, &QCheckBox::toggled,
verticalSliders, &SlidersGroup::invertKeyBindings);
slidersGroup, &SlidersGroup::invertKeyBindings);
QGridLayout *controlsLayout = new QGridLayout;
controlsLayout->addWidget(minimumLabel, 0, 0);
@ -107,40 +82,26 @@ void Window::createControls(const QString &title)
controlsLayout->addWidget(valueSpinBox, 2, 1);
controlsLayout->addWidget(invertedAppearance, 0, 2);
controlsLayout->addWidget(invertedKeyBindings, 1, 2);
controlsLayout->addWidget(orientationCombo, 3, 0, 1, 3);
controlsGroup->setLayout(controlsLayout);
}
//! [8]
//! [6]
void Window::resizeEvent(QResizeEvent *e)
//! [7]
void Window::resizeEvent(QResizeEvent *)
{
Q_UNUSED(e);
if (width() == 0 || height() == 0)
return;
const double aspectRatio = double(width()) / double(height());
const double aspectRatio = double(width()) / double(height());
if ((aspectRatio < 1.0) && (oldAspectRatio > 1.0)) {
layout->removeWidget(controlsGroup);
layout->removeWidget(stackedWidget);
layout->addWidget(stackedWidget, 1, 0);
layout->addWidget(controlsGroup, 0, 0);
oldAspectRatio = aspectRatio;
}
else if ((aspectRatio > 1.0) && (oldAspectRatio < 1.0)) {
layout->removeWidget(controlsGroup);
layout->removeWidget(stackedWidget);
layout->addWidget(stackedWidget, 0, 1);
layout->addWidget(controlsGroup, 0, 0);
oldAspectRatio = aspectRatio;
if (aspectRatio < 1.0) {
layout->setDirection(QBoxLayout::TopToBottom);
slidersGroup->setOrientation(Qt::Horizontal);
} else if (aspectRatio > 1.0) {
layout->setDirection(QBoxLayout::LeftToRight);
slidersGroup->setOrientation(Qt::Vertical);
}
}
//! [7]

View File

@ -29,9 +29,7 @@ private:
void createControls(const QString &title);
void resizeEvent(QResizeEvent *e);
SlidersGroup *horizontalSliders;
SlidersGroup *verticalSliders;
QStackedWidget *stackedWidget;
SlidersGroup *slidersGroup;
QGroupBox *controlsGroup;
QLabel *minimumLabel;
@ -42,9 +40,7 @@ private:
QSpinBox *minimumSpinBox;
QSpinBox *maximumSpinBox;
QSpinBox *valueSpinBox;
QComboBox *orientationCombo;
QGridLayout *layout;
double oldAspectRatio;
QBoxLayout *layout;
};
//! [0]