本页内容

滑块示例

“滑块示例”展示了如何使用 Qt 中提供的不同类型的滑块:QSlider 、QScrollBar 和QDial 。

Qt 提供了三种滑块类控件:QSlider 、QScrollBar 和QDial 。它们的功能大多继承自QAbstractSlider ,由于差异仅在于外观和风格,因此理论上在应用程序中可以相互替代。本示例展示了它们的外观、工作原理,以及如何通过属性来调整其行为和外观。

该示例还演示了如何利用信号和插槽来同步两个或多个控件的行为,以及如何重写resizeEvent() 方法来实现响应式布局。

各种滑块、滚动条和旋钮的图集

“滑块”示例的屏幕截图

“滑块”示例由两个类组成:

  • SlidersGroup 是一个自定义小部件。它结合了QSlider 、QScrollBar 和QDial 。
  • Window 是主控件,由QGroupBox 和SlidersGroup组合而成。QGroupBox 包含多个控件,用于控制滑块样式控件的行为。

首先我们将回顾Window 类,然后将了解SlidersGroup 类。

Window 类定义

class Window : public QWidget
{
    Q_OBJECT

public:
    Window(QWidget *parent = nullptr);

private:
    void createControls(const QString &title);
    void resizeEvent(QResizeEvent *e);

    SlidersGroup *slidersGroup;

    QGroupBox *controlsGroup;
    QLabel *minimumLabel;
    QLabel *maximumLabel;
    QLabel *valueLabel;
    QCheckBox *invertedAppearance;
    QCheckBox *invertedKeyBindings;
    QSpinBox *minimumSpinBox;
    QSpinBox *maximumSpinBox;
    QSpinBox *valueSpinBox;
    QBoxLayout *layout;
};

Window 类继承自QWidget 类。它负责显示滑块控件,并允许用户设置其最小值、最大值和当前值,同时可自定义其外观、键位绑定和方向。我们使用私有函数createControls() 来创建提供这些控制机制的控件,并将它们与滑块控件关联起来。

Window 类的实现

Window::Window(QWidget *parent)
    : QWidget(parent)
{
    slidersGroup = new SlidersGroup(tr("Sliders"));

    createControls(tr("Controls"));

在构造函数中,我们首先创建用于显示滑块控件的SlidersGroup 控件。通过createControls() 创建控制控件,并将它们与滑块控件连接起来。

    layout = new QBoxLayout(QBoxLayout::LeftToRight);
    layout->addWidget(controlsGroup);
    layout->addWidget(slidersGroup);
    setLayout(layout);

    minimumSpinBox->setValue(0);
    maximumSpinBox->setValue(20);
    valueSpinBox->setValue(5);

    setWindowTitle(tr("Sliders"));
}

在初始化最小值、最大值和当前值之前,我们将控制控件组和滑块放置在一个水平布局中。当前值的初始化将通过我们在valueSpinBox 控件与SlidersGroup 控件之间建立的连接传播到滑块控件。最小值和最大值则通过我们使用createControls() 创建的连接进行传播。

void Window::createControls(const QString &title)
{
    controlsGroup = new QGroupBox(title);

    minimumLabel = new QLabel(tr("Minimum value:"));
    maximumLabel = new QLabel(tr("Maximum value:"));
    valueLabel = new QLabel(tr("Current value:"));

    invertedAppearance = new QCheckBox(tr("Inverted appearance"));
    invertedKeyBindings = new QCheckBox(tr("Inverted key bindings"));

在私有函数createControls() 中,我们让QGroupBox (controlsGroup )来显示控件小部件。组框可以提供边框、标题和键盘快捷键,并在其内部显示各种其他小部件。这组控件小部件由两个复选框和三个带标签的旋转框组成。

创建标签后,我们创建两个复选框。复选框通常用于表示应用程序中可启用或禁用的功能。当“invertedAppearance ”启用时,滑块的数值将被反转。下表展示了不同滑块类控件的外观:

QSliderQScrollBarQDial
正常反转正常反转正常倒置
Qt::Horizontal从左到右从右到左从左到右从右到左顺时针逆时针
Qt::Vertical从下到上从上到下从上到下自下而上顺时针逆时针

通常会反转垂直QSlider 的外观。例如,用于控制音量的垂直滑块通常从下往上滑动(未反转的外观),而用于控制屏幕上对象位置的垂直滑块则可能从上往下滑动,因为屏幕坐标是从上往下排列的。

当启用invertedKeyBindings 选项(对应于QAbstractSlider::invertedControls 属性)时,滑块的滚轮和按键事件将被反转。在常规键位绑定下,向上滚动鼠标滚轮或使用Page Up等按键会将滑块的当前值增加至最大值。 反转后,相同的滚轮和键盘事件将使数值向滑块的最小值移动。如果滑块的外观被反转,这可能会很有用:一些用户可能期望这些键在数值上的作用方式保持不变,而另一些用户则可能期望“PageUp ”在屏幕上表示“向上”。

请注意,对于水平和垂直滚动条,键位绑定默认是反转的:PageDown 会增加当前值,而PageUp 会减少当前值。

    minimumSpinBox = new QSpinBox;
    minimumSpinBox->setRange(-100, 100);
    minimumSpinBox->setSingleStep(1);

    maximumSpinBox = new QSpinBox;
    maximumSpinBox->setRange(-100, 100);
    maximumSpinBox->setSingleStep(1);

    valueSpinBox = new QSpinBox;
    valueSpinBox->setRange(-100, 100);
    valueSpinBox->setSingleStep(1);

接着我们创建旋转输入框。QSpinBox 允许用户通过点击上下按钮,或按下键盘上的Up 和Down 键来修改当前显示的数值。用户也可以手动输入数值。这些旋转输入框控制着QSlider 、QScrollBar 和QDial 控件的最小值、最大值和当前值。

    connect(slidersGroup, &SlidersGroup::valueChanged,
            valueSpinBox, &QSpinBox::setValue);
    connect(valueSpinBox, &QSpinBox::valueChanged,
            slidersGroup, &SlidersGroup::setValue);
    connect(minimumSpinBox, &QSpinBox::valueChanged,
            slidersGroup, &SlidersGroup::setMinimum);
    connect(maximumSpinBox, &QSpinBox::valueChanged,
            slidersGroup, &SlidersGroup::setMaximum);
    connect(invertedAppearance, &QCheckBox::toggled,
            slidersGroup, &SlidersGroup::invertAppearance);
    connect(invertedKeyBindings, &QCheckBox::toggled,
            slidersGroup, &SlidersGroup::invertKeyBindings);

    QGridLayout *controlsLayout = new QGridLayout;
    controlsLayout->addWidget(minimumLabel, 0, 0);
    controlsLayout->addWidget(maximumLabel, 1, 0);
    controlsLayout->addWidget(valueLabel, 2, 0);
    controlsLayout->addWidget(minimumSpinBox, 0, 1);
    controlsLayout->addWidget(maximumSpinBox, 1, 1);
    controlsLayout->addWidget(valueSpinBox, 2, 1);
    controlsLayout->addWidget(invertedAppearance, 0, 2);
    controlsLayout->addWidget(invertedKeyBindings, 1, 2);
    controlsGroup->setLayout(controlsLayout);

}

然后,我们将slidersGroup 和valueSpinBox 相互连接,以便当其中一个的当前值发生变化时,滑块控件和控制控件的行为能够保持同步。valueChanged() 信号会以新值作为参数发出。setValue() 槽将控件的当前值设置为新值,并且如果新值与旧值不同,则发出valueChanged() 信号。

我们通过信号和槽机制来同步控件小部件与滑块小部件的行为。我们将每个控件小部件分别连接到水平和垂直两组滑块小部件上。此外,我们将orientationCombo 连接到QStackedWidget ,以确保显示正确的“页面”。最后,我们在controlsGroup 组框内,通过QGridLayout 布局控件小部件。

void Window::resizeEvent(QResizeEvent *)
{
    if (width() == 0 || height() == 0)
        return;

    const double aspectRatio = double(width()) / double(height());

    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);
    }
}

最后,我们重写了QWidget 中的resizeEvent()方法。我们防止除以零的情况发生,并计算控件的纵横比。如果窗口为纵向布局,则将布局设置为垂直排列控件组件和滑块组,并将滑块设置为水平方向。 如果窗口为横向模式,则将布局调整为将滑块和控制控件并排显示,并将滑块设置为纵向方向。

SlidersGroup 类定义

class SlidersGroup : public QGroupBox
{
    Q_OBJECT

public:
    SlidersGroup(const QString &title, QWidget *parent = nullptr);

signals:
    void valueChanged(int value);

public slots:
    void setValue(int value);
    void setMinimum(int value);
    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;
};

SlidersGroup 类继承自QGroupBox 。它提供了一个框架和一个标题,并包含一个QSlider 、一个QScrollBar 和一个QDial 。

我们提供了一个valueChanged() 信号和一个公共setValue() 槽,其功能与QAbstractSlider 和QSpinBox 中的信号和槽等效。此外,我们还实现了几个其他公共槽,用于设置最小值和最大值、反转滑块控件的外观以及键位绑定,并设置其方向。

SlidersGroup 类的实现

SlidersGroup::SlidersGroup(const QString &title, QWidget *parent)
    : QGroupBox(title, parent)
{
    slider = new QSlider;
    slider->setFocusPolicy(Qt::StrongFocus);
    slider->setTickPosition(QSlider::TicksBothSides);
    slider->setTickInterval(10);
    slider->setSingleStep(1);

    scrollBar = new QScrollBar;
    scrollBar->setFocusPolicy(Qt::StrongFocus);

    dial = new QDial;
    dial->setFocusPolicy(Qt::StrongFocus);

首先,我们创建具有相应属性的滑块样式控件。特别是,我们为每个控件设置了焦点策略。Qt::FocusPolicy 是一个枚举类型,定义了控件在获取键盘焦点方面可能采用的各种策略。Qt::StrongFocus 策略表示该控件既可以通过 Tab 键切换焦点,也可以通过点击获取焦点。

    connect(slider, &QSlider::valueChanged, scrollBar, &QScrollBar::setValue);
    connect(scrollBar, &QScrollBar::valueChanged, dial, &QDial::setValue);
    connect(dial, &QDial::valueChanged, slider, &QSlider::setValue);
    connect(dial, &QDial::valueChanged, this, &SlidersGroup::valueChanged);

然后,我们将这些控件相互连接,以便当其中一个控件的当前值发生变化时,它们能保持同步。

我们将dial 的valueChanged() 信号连接到SlidersGroup 的valueChanged() 信号,以将值的变化通知给应用程序中的其他控件(即控制控件)。


    slidersLayout = new QBoxLayout(QBoxLayout::LeftToRight);
    slidersLayout->addWidget(slider);
    slidersLayout->addWidget(scrollBar);
    slidersLayout->addWidget(dial);
    setLayout(slidersLayout);
}

最后,我们在组框内为滑块控件创建布局。首先将滑块以水平方式排列。

void SlidersGroup::setValue(int value)
{
    slider->setValue(value);
}

setValue() 槽用于设置QSlider 的值。我们无需在QScrollBar 和QDial 控件上显式调用setValue(),因为当QSlider 的值发生变化时,它会发出valueChanged()信号,从而触发多米诺骨牌效应。

void SlidersGroup::setMinimum(int value)
{
    slider->setMinimum(value);
    scrollBar->setMinimum(value);
    dial->setMinimum(value);
}

void SlidersGroup::setMaximum(int value)
{
    slider->setMaximum(value);
    scrollBar->setMaximum(value);
    dial->setMaximum(value);
}

Window 类使用setMinimum() 和setMaximum() 插槽来设置QSlider 、QScrollBar 和QDial 控件的取值范围。

void SlidersGroup::invertAppearance(bool invert)
{
    slider->setInvertedAppearance(invert);
    scrollBar->setInvertedAppearance(invert);
    dial->setInvertedAppearance(invert);
}

void SlidersGroup::invertKeyBindings(bool invert)
{
    slider->setInvertedControls(invert);
    scrollBar->setInvertedControls(invert);
    dial->setInvertedControls(invert);
}

invertAppearance() 和invertKeyBindings() 插槽分别控制子控件的invertedAppearance 和invertedControls 属性。

void SlidersGroup::setOrientation(Qt::Orientation orientation)
{
    slidersLayout->setDirection(orientation == Qt::Horizontal
                                ? QBoxLayout::TopToBottom
                                : QBoxLayout::LeftToRight);
    scrollBar->setOrientation(orientation);
    slider->setOrientation(orientation);
}

setOrientation() 槽控制布局的方向以及滑块的朝向。在水平组中,滑块呈水平朝向,并上下排列;在垂直组中,滑块呈垂直朝向,并并排排列。

示例项目 @ code.qt.io

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.