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

时间:2014-07-08 15:42:41

标签: c++ qt user-interface scrollbar

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

Image showing the desired effect.

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

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

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

    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

    #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添加另一个滑块。

    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

    #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 个答案:

答案 0 :(得分:1)

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

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

#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


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


修改

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

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

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