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

标签 c++ qt user-interface scrollbar

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

Image showing the desired effect.

在图像中,中间的 slider 应该保存用户应用的最后一个值,而顶部的主 slider 可以自由拖动。换句话说,不能选择中间的一个,当用户按下按钮或其他东西时,它的值将更改为另一个的值。

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

  1. 创建一个继承自QScrollBar的类,并在里面添加另一个QScrollBar。

    滚动条.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
    

    滚动条.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. 创建一个继承自 QScrollBar 的类,并使用 paintEvent 添加另一个 slider 。

    滚动条.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
    

    滚动条.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.
         */
    }
    

最佳答案

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

滚动条.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

滚动条.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

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

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

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

. 结果如下所示:

enter image description here


我必须连接按下按钮以将鼠标事件传递给 slider ,因为按钮位于 slider 之上。


编辑

一个更简洁的解决方案是添加透明滚动条而不是按钮。

滚动条.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

滚动条.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

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

关于c++ - Qt:创建一个滚动条,后面有一个阴影,它包含最后一个值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24636135/

相关文章:

qt - qmake 项目中的 CMake 项目

c++ - 如何用qt分发代码?

python - Urwid 列表框 : How to get fluid focus movement?

c++ - "Rock, paper, scissors"C++ 代码有问题

使用 std::atomic 的 C++ 线程安全增量,带模而不带互斥锁

c++ - glColor 实际上并没有改变 OpenGL 的颜色

python - Tkinter 从正在运行的程序中删除按钮

android - setContentView 需要很长时间(10-15 秒)才能执行

c++ - regex_replace 在 Windows 上不起作用

c++ - 为什么 "\n"在标准输入而不是代码中输入时显示不同?