Revision control

++ // Copyright (C) 2016 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
++
++ /*!
++ \example widgets/sliders
++ \title Sliders Example
++ \examplecategory {User Interface Components}
++ \ingroup examples-widgets
++ \brief The Sliders example shows how to use the different types of sliders
++ available in Qt: QSlider, QScrollBar and QDial.
++
++ Qt provides three types of slider-like widgets: QSlider,
++ QScrollBar and QDial. They all inherit most of their
++ functionality from QAbstractSlider, and can in theory replace
++ each other in an application since the differences only concern
++ their look and feel. This example shows what they look like, how
++ they work and how their behavior and appearance can be
++ manipulated through their properties.
++
++ The example also demonstrates how signals and slots can be used to
++ synchronize the behavior of two or more widgets, and how to override
++ \l{QWidget::}{resizeEvent()} to implement a responsive layout.
++
++ \image sliders-example.png
++ {Gallery of different sliders, scroll bars, and dials}
++ \caption Screenshot of the Sliders example
++
++ The Sliders example consists of two classes:
++
++ \list
++
++ \li \c SlidersGroup is a custom widget. It combines a QSlider, a
++ QScrollBar and a QDial.
++
++ \li \c Window is the main widget combining a QGroupBox and a
++ SlidersGroup. The QGroupBox contains several widgets that control
++ the behavior of the slider-like widgets.
++
++ \endlist
++
++ First we will review the \c Window class, then we
++ will take a look at the \c SlidersGroup class.
++
++ \section1 Window Class Definition
++
++ \snippet widgets/sliders/window.h 0
++
++ The \c Window class inherits from QWidget. It displays the slider
++ widgets and allows the user to set their minimum, maximum and
++ current values and to customize their appearance, key bindings
++ and orientation. We use a private \c createControls() function to
++ create the widgets that provide these controlling mechanisms and
++ to connect them to the slider widgets.
++
++ \section1 Window Class Implementation
++
++ \snippet widgets/sliders/window.cpp 0
++
++ 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 the
++ sliders.
++
++ \snippet widgets/sliders/window.cpp 1
++
++ 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
++ between \c valueSpinBox and the \c SlidersGroup widgets. The
++ 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
++
++ 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, and three spin boxes with labels.
++
++ After creating the labels, we create the two checkboxes.
++ Checkboxes are typically used to represent features in an
++ application that can be enabled or disabled. When \c
++ invertedAppearance is enabled, the slider values are inverted.
++ The table below shows the appearance for the different
++ slider-like widgets:
++
++ \table
++ \header \li \li{2,1} QSlider \li{2,1} QScrollBar \li{2,1} QDial
++ \header \li \li Normal \li Inverted \li Normal \li Inverted \li Normal \li Inverted
++ \row \li Qt::Horizontal \li Left to right \li Right to left \li Left to right \li Right to left \li Clockwise \li Counterclockwise
++ \row \li Qt::Vertical \li Bottom to top \li Top to bottom \li Top to bottom \li Bottom to top \li Clockwise \li Counterclockwise
++ \endtable
++
++ It is common to invert the appearance of a vertical QSlider. A
++ vertical slider that controls volume, for example, will typically
++ go from bottom to top (the non-inverted appearance), whereas a
++ vertical slider that controls the position of an object on screen
++ might go from top to bottom, because screen coordinates go from
++ top to bottom.
++
++ When the \c invertedKeyBindings option is enabled (corresponding
++ to the QAbstractSlider::invertedControls property), the slider's
++ wheel and key events are inverted. The normal key bindings mean
++ that scrolling the mouse wheel "up" or using keys like page up
++ will increase the slider's current value towards its maximum.
++ Inverted, the same wheel and key events will move the value
++ toward the slider's minimum. This can be useful if the \e
++ appearance of a slider is inverted: Some users might expect the
++ keys to still work the same way on the value, whereas others
++ might expect \uicontrol PageUp to mean "up" on the screen.
++
++ Note that for horizontal and vertical scroll bars, the key
++ 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
++
++ 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
++ Up and \uicontrol Down keys on the keyboard to modify the value
++ currently displayed. The user can also type in the value
++ manually. The spin boxes control the minimum, maximum and current
++ values for the QSlider, QScrollBar, and QDial widgets.
++
++ \snippet widgets/sliders/window.cpp 6
++
++ 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
++ widget to both the horizontal and vertical group of slider
++ widgets. We also connect \c orientationCombo to the
++ QStackedWidget, so that the correct "page" is shown. Finally, we
++ 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
++
++ The \c SlidersGroup class inherits from QGroupBox. It provides a
++ frame and a title, and contains a QSlider, a QScrollBar and a
++ QDial.
++
++ We provide a \c valueChanged() signal and a public \c setValue()
++ 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, and set the
++ orientation.
++
++ \section1 SlidersGroup Class Implementation
++
++ \snippet widgets/sliders/slidersgroup.cpp 0
++
++ First we create the slider-like widgets with the appropriate
++ properties. In particular we set the focus policy for each
++ widget. Qt::FocusPolicy is an enum type that defines the various
++ policies a widget can have with respect to acquiring keyboard
++ 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.
++
++ 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.
++
++ \codeline
++ \snippet widgets/sliders/slidersgroup.cpp 4
++
++ 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
++
++ The \c setValue() slot sets the value of the QSlider. We don't
++ need to explicitly call
++ \l{QAbstractSlider::setValue()}{setValue()} on the QScrollBar and
++ QDial widgets, since QSlider will emit the
++ \l{QAbstractSlider::valueChanged()}{valueChanged()} signal when
++ its value changes, triggering a domino effect.
++
++ \snippet widgets/sliders/slidersgroup.cpp 7
++ \snippet widgets/sliders/slidersgroup.cpp 8
++ \codeline
++ \snippet widgets/sliders/slidersgroup.cpp 9
++ \snippet widgets/sliders/slidersgroup.cpp 10
++
++ The \c setMinimum() and \c setMaximum() slots are used by the \c
++ Window class to set the range of the QSlider, QScrollBar, and
++ QDial widgets.
++
++ \snippet widgets/sliders/slidersgroup.cpp 11
++ \snippet widgets/sliders/slidersgroup.cpp 12
++ \codeline
++ \snippet widgets/sliders/slidersgroup.cpp 13
++ \snippet widgets/sliders/slidersgroup.cpp 14
++
++ The \c invertAppearance() and \c invertKeyBindings() slots
++ control the child widgets'
++ \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.
++ */