Qt:创建一个后面有阴影的滚动条,它包含最后一个值

时间:2021-12-11 21:12:22

I am trying to create a scrollbar that has a slider behind holding the last value saved by the user. To better explain my purpose, I created the image below.

我正在尝试创建一个滚动条,后面有一个滑块,保持用户保存的最后一个值。为了更好地解释我的目的,我创建了下面的图像。

Qt:创建一个后面有阴影的滚动条,它包含最后一个值

In the image, the slider in the middle is supposed to be holding the last value applied by the user, while the main slider, the one on the top, is free to be dragged. In other words, the one in the middle cannot be selected, and its value is changed to the value of the other one when the user presses a button or something.

在图像中,中间的滑块应该保持用户应用的最后一个值,而主滑块(顶部的滑块)可以*拖动。换句话说,当用户按下按钮或其他东西时,不能选择中间的那个,并且其值被改变为另一个的值。

So far I have tried the following approaches, with no success:

到目前为止,我尝试了以下方法,但没有成功:

  1. Create a class that inherits from QScrollBar, and add an other QScrollBar inside.

    创建一个继承自QScrollBar的类,并在其中添加其他QScrollBar。

    scrollbar.h

    scrollbar.h

    #ifndef SCROLLBAR_H
    #define SCROLLBAR_H
    
    #include <QScrollBar>
    
    class ScrollBar : public QScrollBar
    {
        Q_OBJECT
    
        public:
            ScrollBar ( Qt::Orientation orientation, QWidget * parent = 0 );
            void init();
            void update();
    
        private:
            QScrollBar* subslider;
    
    };
    
    #endif // SCROLLBAR_H
    

    scrollbar.cpp

    scrollbar.cpp

    #include "scrollbar.h"
    
    ScrollBar::ScrollBar( Qt::Orientation orientation, QWidget * parent ) :
        QScrollBar (orientation, parent) {
        subslider = new QScrollBar(orientation, this);
    }
    
    void ScrollBar::init() {
        subslider->setMaximum( QScrollBar::maximum() );
        subslider->setMinimum( QScrollBar::minimum() );
        subslider->setFixedSize( QScrollBar::size() );
        subslider->setValue( QScrollBar::minimum() );
        subslider->setEnabled(false);
        subslider->setVisible(true);
    }
    
    void ScrollBar::update() {
        subslider->setValue( QScrollBar::sliderPosition() );
    }
    
  2. Create a class that inherits from QScrollBar, and use paintEvent to add the other slider.

    创建一个继承自QScrollBar的类,并使用paintEvent添加另一个滑块。

    scrollbar.h

    scrollbar.h

    #ifndef SCROLLBAR_H
    #define SCROLLBAR_H
    
    #include <QScrollBar>
    #include <QPaintEvent>
    
    class ScrollBar : public QScrollBar
    {
        Q_OBJECT
    
        public:
            ScrollBar ( Qt::Orientation orientation, QWidget * parent = 0 );
            void update();
    
        private:
            int scrollbar_pos;
    
        signals:
        protected:
            void paintEvent( QPaintEvent* event );
    };
    
    #endif // SCROLLBAR_H
    

    scrollbar.cpp

    scrollbar.cpp

    #include "scrollbar.h"
    #include <QPainter>
    
    ScrollBar::ScrollBar( Qt::Orientation orientation, QWidget * parent ) :
        QScrollBar (orientation, parent) {
        scrollbar_pos = 0;
    }
    
    void ScrollBar::update() {
        subslider_pos = QScrollBar::sliderPosition();
    }
    
    void ScrollBar::paintEvent(QPaintEvent * event) {
        // This calls the base class's paint calls
        QScrollBar::paintEvent(event);
        // The following is painted on top of it
        QPainter p(this);
        /**
         * I think the code here should get the image used to display the slider
         * and put it on the correct position.
         */
    }
    

1 个解决方案

#1


1  

I managed to solve the problem using a different approach. I used a CSS stylesheet to manually configure the slider and created a button similar to the slider to represent the last saved value. Now the class looks like this.

我设法使用不同的方法解决问题。我使用CSS样式表手动配置滑块并创建了一个类似于滑块的按钮来表示最后保存的值。现在班级看起来像这样。

scrollbar.h

scrollbar.h

#ifndef SCROLLBAR_H
#define SCROLLBAR_H

#include <QSlider>
#include <QPaintEvent>
#include <QPushButton>

class ScrollBar : public QSlider
{
    Q_OBJECT

    public:
        ScrollBar ( QWidget * parent = 0 );
        ~ScrollBar();
        void init();
        void update();

    protected:
        QPushButton* button;

    protected slots:
        void mousePressEvent();
};

#endif // SCROLLBAR_H

scrollbar.cpp

scrollbar.cpp

#include "scrollbar.h"
#include <QPainter>

ScrollBar::ScrollBar( QWidget * parent ) :
    QSlider (Qt::Horizontal, parent) {
    QSlider::setMaximum(100);
    QSlider::setMinimum(0);
    QSlider::setValue(50);
    QSlider::setFixedSize(200, 20);

    button = new QPushButton(this);
    button->setObjectName("slider");
    button->move(0, 3);
    button->setEnabled(true);
    button->setFocusPolicy(Qt::NoFocus);

    connect(button, SIGNAL(pressed()), this, SLOT(mousePressEvent()));
}

void ScrollBar::update() {
    std::cout << "Called update()" << std::endl;
    // The following moves the false button
    double delta =  QSlider::sliderPosition() /
            (double) (QSlider::maximum() - QSlider::minimum()) *
            (QSlider::width() - 14);
    button->move(delta, 3);
}

void ScrollBar::mousePressEvent() {
    QPoint pos = button->pos();
    pos.setX( pos.x() + 7 );
    pos.setY(6);
    QMouseEvent evt(QEvent::MouseButtonPress, pos, Qt::LeftButton,
                    Qt::LeftButton, Qt::NoModifier);
    QSlider::mousePressEvent(&evt);
}

ScrollBar::~ScrollBar() {
}

slider.css

slider.css

QSlider::groove:horizontal {
border: 1px solid #bbb;
background: white;
height: 10px;
border-radius: 4px;
}

QSlider::sub-page:horizontal {
background: qlineargradient(x1: 0, y1: 0,    x2: 0, y2: 1,
    stop: 0 #66e, stop: 1 #bbf);
background: qlineargradient(x1: 0, y1: 0.2, x2: 1, y2: 1,
    stop: 0 #bbf, stop: 1 #55f);
border: 1px solid #777;
height: 10px;
border-radius: 4px;
}

QSlider::add-page:horizontal {
background: #fff;
border: 1px solid #777;
height: 10px;
border-radius: 4px;
}

QSlider::handle:horizontal {
background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
    stop:0 #eee, stop:1 #ccc);
border: 1px solid #777;
width: 13px;
margin-top: -2px;
margin-bottom: -2px;
border-radius: 4px;
}

QSlider::handle:horizontal:hover {
background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
    stop:0 #fff, stop:1 #ddd);
border: 1px solid #444;
border-radius: 4px;
}

QSlider::sub-page:horizontal:disabled {
background: #bbb;
border-color: #999;
}

QSlider::add-page:horizontal:disabled {
background: #eee;
border-color: #999;
}

QSlider::handle:horizontal:disabled {
background: #eee;
border: 1px solid #aaa;
border-radius: 4px;
}

QPushButton#slider {
background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
    stop:0 #ccc, stop:1 #aaa);
border: 1px solid #777;
max-width: 13px;
min-width: 13px;
max-height: 12px;
min-height: 12px;
border-radius: 4px;
}

Adding the widget looks something like this:

添加小部件看起来像这样:

QFile file("slider.css");
file.open(QFile::ReadOnly);
QString style = file.readAll();
file.close();

ScrollBar* scroll = new ScrollBar(parent);

parent->setStyleSheet(style);
// or scroll->setStyleSheet(style); if the style should be added only to this widget

. The result looks like this:

。结果如下:

Qt:创建一个后面有阴影的滚动条,它包含最后一个值


I had to connect the button press to pass the mouse event to the slider, since the button is on top of it.

我必须连接按钮才能将鼠标事件传递给滑块,因为按钮位于按钮顶部。


EDIT

编辑

An even cleaner solution is to add transparent scrollbars instead of the push button.

更清晰的解决方案是添加透明滚动条而不是按钮。

scrollbar.h

scrollbar.h

#ifndef SCROLLBAR_H
#define SCROLLBAR_H

#include <QSlider>
#include <QResizeEvent>

class ScrollBar : public QSlider
{
    Q_OBJECT

    public:
        bool enabled;

        ScrollBar ( QWidget * parent = 0 );
        ~ScrollBar();

        void init();
        void update();

        void setValue(int);
        void setFixedValue(int);

        QSize sizeHint() const;

    protected:
        QSlider* slider_fixed;
        QSlider* slider_top;

        virtual void resizeEvent(QResizeEvent *evt);
};

#endif

scrollbar.cpp

scrollbar.cpp

#include "scrollbar.h"
#include <QFile>

ScrollBar::ScrollBar( QWidget * parent ) : QSlider (Qt::Horizontal, parent) {
    QSlider::setMaximum(100);
    QSlider::setMinimum(0);
    QSlider::setValue(50);

    slider_fixed = new QSlider(Qt::Horizontal, this);
    slider_fixed->setMaximum( QSlider::maximum() );
    slider_fixed->setMinimum( QSlider::minimum() );
    slider_fixed->setValue( QSlider::minimum() );
    slider_fixed->setObjectName("transparent_fixed");

    slider_top = new QSlider(Qt::Horizontal, this);
    slider_top->setMaximum( QSlider::maximum() );
    slider_top->setMinimum( QSlider::minimum() );
    slider_top->setValue( QSlider::sliderPosition() );
    slider_top->setObjectName("transparent_top");

    QFile file("slider.css");
    file.open(QFile::ReadOnly);
    QString style = file.readAll();
    file.close();

    QSlider::setStyleSheet(style);

    QObject::connect(slider_top, SIGNAL(valueChanged(int)), this, SLOT(setValue(int)));
}

QSize ScrollBar::sizeHint() const {
    return QSize(2000, 20);
}

void ScrollBar::resizeEvent(QResizeEvent *evt) {
    int width  = evt->size().width();
    int height = evt->size().height();

    slider_fixed->resize(width, height);
    slider_top->resize(width, height);
}

void ScrollBar::setFixedValue(int value) {
    slider_fixed->setValue( value );
}

void ScrollBar::setValue(int value) {
    slider_top->setValue(value);
}

ScrollBar::~ScrollBar() {
}

slider.css

slider.css

QSlider::groove:horizontal {
border: 1px solid #bbb;
background: white;
height: 10px;
border-radius: 4px;
}

QSlider::sub-page:horizontal {
background: qlineargradient(x1: 0, y1: 0,    x2: 0, y2: 1,
    stop: 0 #66e, stop: 1 #bbf);
background: qlineargradient(x1: 0, y1: 0.2, x2: 1, y2: 1,
    stop: 0 #bbf, stop: 1 #55f);
border: 1px solid #777;
height: 10px;
border-radius: 4px;
}

QSlider::add-page:horizontal {
background: #fff;
border: 1px solid #777;
height: 10px;
border-radius: 4px;
}

QSlider::handle:horizontal {
background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
    stop:0 #eee, stop:1 #ccc);
border: 1px solid #777;
width: 13px;
margin-top: -2px;
margin-bottom: -2px;
border-radius: 4px;
}

QSlider::handle:horizontal:hover {
background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
    stop:0 #fff, stop:1 #ddd);
border: 1px solid #444;
border-radius: 4px;
}

QSlider#transparent_fixed::groove:horizontal {
border: none;
background: transparent;
border-radius: 0px;
}

QSlider#transparent_fixed::sub-page:horizontal {
background: transparent;
border: none;
border-radius: 0px;
}

QSlider#transparent_fixed::add-page:horizontal {
background: transparent;
border: none;
border-radius: 0px;
}

QSlider#transparent_fixed::handle:horizontal {
background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
    stop:0 #bbb, stop:1 #999);
}

QSlider#transparent_fixed::handle:horizontal:hover {
border: 1px solid #777;
}

QSlider#transparent_top::groove:horizontal {
border: none;
background: transparent;
border-radius: 0px;
}

QSlider#transparent_top::sub-page:horizontal {
background: transparent;
border: none;
border-radius: 0px;
}

QSlider#transparent_top::add-page:horizontal {
background: transparent;
border: none;
border-radius: 0px;
}

#1


1  

I managed to solve the problem using a different approach. I used a CSS stylesheet to manually configure the slider and created a button similar to the slider to represent the last saved value. Now the class looks like this.

我设法使用不同的方法解决问题。我使用CSS样式表手动配置滑块并创建了一个类似于滑块的按钮来表示最后保存的值。现在班级看起来像这样。

scrollbar.h

scrollbar.h

#ifndef SCROLLBAR_H
#define SCROLLBAR_H

#include <QSlider>
#include <QPaintEvent>
#include <QPushButton>

class ScrollBar : public QSlider
{
    Q_OBJECT

    public:
        ScrollBar ( QWidget * parent = 0 );
        ~ScrollBar();
        void init();
        void update();

    protected:
        QPushButton* button;

    protected slots:
        void mousePressEvent();
};

#endif // SCROLLBAR_H

scrollbar.cpp

scrollbar.cpp

#include "scrollbar.h"
#include <QPainter>

ScrollBar::ScrollBar( QWidget * parent ) :
    QSlider (Qt::Horizontal, parent) {
    QSlider::setMaximum(100);
    QSlider::setMinimum(0);
    QSlider::setValue(50);
    QSlider::setFixedSize(200, 20);

    button = new QPushButton(this);
    button->setObjectName("slider");
    button->move(0, 3);
    button->setEnabled(true);
    button->setFocusPolicy(Qt::NoFocus);

    connect(button, SIGNAL(pressed()), this, SLOT(mousePressEvent()));
}

void ScrollBar::update() {
    std::cout << "Called update()" << std::endl;
    // The following moves the false button
    double delta =  QSlider::sliderPosition() /
            (double) (QSlider::maximum() - QSlider::minimum()) *
            (QSlider::width() - 14);
    button->move(delta, 3);
}

void ScrollBar::mousePressEvent() {
    QPoint pos = button->pos();
    pos.setX( pos.x() + 7 );
    pos.setY(6);
    QMouseEvent evt(QEvent::MouseButtonPress, pos, Qt::LeftButton,
                    Qt::LeftButton, Qt::NoModifier);
    QSlider::mousePressEvent(&evt);
}

ScrollBar::~ScrollBar() {
}

slider.css

slider.css

QSlider::groove:horizontal {
border: 1px solid #bbb;
background: white;
height: 10px;
border-radius: 4px;
}

QSlider::sub-page:horizontal {
background: qlineargradient(x1: 0, y1: 0,    x2: 0, y2: 1,
    stop: 0 #66e, stop: 1 #bbf);
background: qlineargradient(x1: 0, y1: 0.2, x2: 1, y2: 1,
    stop: 0 #bbf, stop: 1 #55f);
border: 1px solid #777;
height: 10px;
border-radius: 4px;
}

QSlider::add-page:horizontal {
background: #fff;
border: 1px solid #777;
height: 10px;
border-radius: 4px;
}

QSlider::handle:horizontal {
background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
    stop:0 #eee, stop:1 #ccc);
border: 1px solid #777;
width: 13px;
margin-top: -2px;
margin-bottom: -2px;
border-radius: 4px;
}

QSlider::handle:horizontal:hover {
background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
    stop:0 #fff, stop:1 #ddd);
border: 1px solid #444;
border-radius: 4px;
}

QSlider::sub-page:horizontal:disabled {
background: #bbb;
border-color: #999;
}

QSlider::add-page:horizontal:disabled {
background: #eee;
border-color: #999;
}

QSlider::handle:horizontal:disabled {
background: #eee;
border: 1px solid #aaa;
border-radius: 4px;
}

QPushButton#slider {
background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
    stop:0 #ccc, stop:1 #aaa);
border: 1px solid #777;
max-width: 13px;
min-width: 13px;
max-height: 12px;
min-height: 12px;
border-radius: 4px;
}

Adding the widget looks something like this:

添加小部件看起来像这样:

QFile file("slider.css");
file.open(QFile::ReadOnly);
QString style = file.readAll();
file.close();

ScrollBar* scroll = new ScrollBar(parent);

parent->setStyleSheet(style);
// or scroll->setStyleSheet(style); if the style should be added only to this widget

. The result looks like this:

。结果如下:

Qt:创建一个后面有阴影的滚动条,它包含最后一个值


I had to connect the button press to pass the mouse event to the slider, since the button is on top of it.

我必须连接按钮才能将鼠标事件传递给滑块,因为按钮位于按钮顶部。


EDIT

编辑

An even cleaner solution is to add transparent scrollbars instead of the push button.

更清晰的解决方案是添加透明滚动条而不是按钮。

scrollbar.h

scrollbar.h

#ifndef SCROLLBAR_H
#define SCROLLBAR_H

#include <QSlider>
#include <QResizeEvent>

class ScrollBar : public QSlider
{
    Q_OBJECT

    public:
        bool enabled;

        ScrollBar ( QWidget * parent = 0 );
        ~ScrollBar();

        void init();
        void update();

        void setValue(int);
        void setFixedValue(int);

        QSize sizeHint() const;

    protected:
        QSlider* slider_fixed;
        QSlider* slider_top;

        virtual void resizeEvent(QResizeEvent *evt);
};

#endif

scrollbar.cpp

scrollbar.cpp

#include "scrollbar.h"
#include <QFile>

ScrollBar::ScrollBar( QWidget * parent ) : QSlider (Qt::Horizontal, parent) {
    QSlider::setMaximum(100);
    QSlider::setMinimum(0);
    QSlider::setValue(50);

    slider_fixed = new QSlider(Qt::Horizontal, this);
    slider_fixed->setMaximum( QSlider::maximum() );
    slider_fixed->setMinimum( QSlider::minimum() );
    slider_fixed->setValue( QSlider::minimum() );
    slider_fixed->setObjectName("transparent_fixed");

    slider_top = new QSlider(Qt::Horizontal, this);
    slider_top->setMaximum( QSlider::maximum() );
    slider_top->setMinimum( QSlider::minimum() );
    slider_top->setValue( QSlider::sliderPosition() );
    slider_top->setObjectName("transparent_top");

    QFile file("slider.css");
    file.open(QFile::ReadOnly);
    QString style = file.readAll();
    file.close();

    QSlider::setStyleSheet(style);

    QObject::connect(slider_top, SIGNAL(valueChanged(int)), this, SLOT(setValue(int)));
}

QSize ScrollBar::sizeHint() const {
    return QSize(2000, 20);
}

void ScrollBar::resizeEvent(QResizeEvent *evt) {
    int width  = evt->size().width();
    int height = evt->size().height();

    slider_fixed->resize(width, height);
    slider_top->resize(width, height);
}

void ScrollBar::setFixedValue(int value) {
    slider_fixed->setValue( value );
}

void ScrollBar::setValue(int value) {
    slider_top->setValue(value);
}

ScrollBar::~ScrollBar() {
}

slider.css

slider.css

QSlider::groove:horizontal {
border: 1px solid #bbb;
background: white;
height: 10px;
border-radius: 4px;
}

QSlider::sub-page:horizontal {
background: qlineargradient(x1: 0, y1: 0,    x2: 0, y2: 1,
    stop: 0 #66e, stop: 1 #bbf);
background: qlineargradient(x1: 0, y1: 0.2, x2: 1, y2: 1,
    stop: 0 #bbf, stop: 1 #55f);
border: 1px solid #777;
height: 10px;
border-radius: 4px;
}

QSlider::add-page:horizontal {
background: #fff;
border: 1px solid #777;
height: 10px;
border-radius: 4px;
}

QSlider::handle:horizontal {
background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
    stop:0 #eee, stop:1 #ccc);
border: 1px solid #777;
width: 13px;
margin-top: -2px;
margin-bottom: -2px;
border-radius: 4px;
}

QSlider::handle:horizontal:hover {
background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
    stop:0 #fff, stop:1 #ddd);
border: 1px solid #444;
border-radius: 4px;
}

QSlider#transparent_fixed::groove:horizontal {
border: none;
background: transparent;
border-radius: 0px;
}

QSlider#transparent_fixed::sub-page:horizontal {
background: transparent;
border: none;
border-radius: 0px;
}

QSlider#transparent_fixed::add-page:horizontal {
background: transparent;
border: none;
border-radius: 0px;
}

QSlider#transparent_fixed::handle:horizontal {
background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
    stop:0 #bbb, stop:1 #999);
}

QSlider#transparent_fixed::handle:horizontal:hover {
border: 1px solid #777;
}

QSlider#transparent_top::groove:horizontal {
border: none;
background: transparent;
border-radius: 0px;
}

QSlider#transparent_top::sub-page:horizontal {
background: transparent;
border: none;
border-radius: 0px;
}

QSlider#transparent_top::add-page:horizontal {
background: transparent;
border: none;
border-radius: 0px;
}