QSlider使用笔记

最近做项目使用到QSlider滑动条控件,在使用过的过程中,发现一个问题就是点滑动条上的一个位置,滑块并没有移动到鼠标点击的位置,体验感很差,于是研究了下,让鼠标点击后滑块移动到鼠标点击的位置。
1、eventFilter采用事件过滤的方式:
给QSlider安装事件过滤器,重写事件过滤方法:
ui->hSliderAge->installEventFilter(this);

bool Dialog::eventFilter(QObject *watched, QEvent *event)
{
    if(ui->hSliderAge == watched && event->type() == QEvent::MouseButtonPress)
    {
        QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
        if(mouseEvent->button() == Qt::LeftButton)
        {
            //方法1:
//            int curValue = ui->hSliderAge->maximum() - ui->hSliderAge->minimum();
//            int curPos = ui->hSliderAge->minimum() + curValue*(static_cast<double>(mouseEvent->x()) / ui->hSliderAge->width());
//            ui->hSliderAge->setValue(curPos);
            //方法2:
            int value = QStyle::sliderValueFromPosition(ui->hSliderAge->minimum(), ui->hSliderAge->maximum(), mouseEvent->pos().x(), ui->hSliderAge->width());
            ui->hSliderAge->setValue(value);
        }
    }
    return QDialog::eventFilter(watched, event);
}

运行效果:

这种方式是每个QSlider控件都要写到eventFilter函数里进行处理,如果有多个QSlider控件就会非常混乱,那有没有一种自定义控件的方式来实现这个功能,下面就介绍这种方法。

2、自定义QSlider控件实现点击效果。

#ifndef CUSTOMSLIDER_H
#define CUSTOMSLIDER_H

#include <QSlider>

class CustomSlider : public QSlider
{
    Q_OBJECT
public:
    explicit CustomSlider(QWidget *parent = nullptr);

protected:
    void mousePressEvent(QMouseEvent *event) override;

signals:

};

#endif // CUSTOMSLIDER_H
#include "customslider.h"
#include <QMouseEvent>
#include <QDebug>
#include <QStyle>

CustomSlider::CustomSlider(QWidget *parent)
    : QSlider{parent}
{

}

void CustomSlider::mousePressEvent(QMouseEvent *event)
{
    //获取当前点击位置,得到的这个鼠标坐标是相对于当前QSlider的坐标
    int currentX = event->pos().x();

    //获取当前点击的位置占整个Slider的百分比
    double per = currentX *1.0 / this->width();

    //利用算得的百分比得到具体数字
    int value = per*(this->maximum() - this->minimum()) + this->minimum();
    //int value2 = QStyle::sliderValueFromPosition(this->minimum(), this->maximum(), currentX, this->width());
    //double value3 = per*(this->maximum() - this->minimum()) + this->minimum();
    //设定滑动条位置
    this->setValue(value);

    //滑动条移动事件等事件也用到了mousePressEvent,加这句话是为了不对其产生影响,是的Slider能正常相应其他鼠标事件
    QSlider::mousePressEvent(event);
}

使用:

运行效果:

完整代码如下:

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>

QT_BEGIN_NAMESPACE
namespace Ui { class Dialog; }
QT_END_NAMESPACE

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = nullptr);
    ~Dialog();
    void initData();

public slots:
    void slotValueChangedSliderAge(int value);
    void slotValueChangedSpinBoxAge(int value);
    void slotValueChangedSlider(int value);
    void slotValueChangedSpinBox(int value);

protected:
    bool eventFilter(QObject *watched, QEvent *event) override;
    bool eventFilter2(QObject *watched, QEvent *event);

private:
    Ui::Dialog *ui;
};
#endif // DIALOG_H
#include "dialog.h"
#include "ui_dialog.h"
#include <QDebug>
#include <QMouseEvent>
#include <QStyle>

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
    , ui(new Ui::Dialog)
{
    ui->setupUi(this);
    initData();
}

Dialog::~Dialog()
{
    delete ui;
}

void Dialog::initData()
{
    ui->hSliderAge->installEventFilter(this);
    ui->hSliderAge->setValue(18);
    ui->spinBoxAge->setValue(18);
    //设置步长
    ui->hSliderAge->setSingleStep(4);
    ui->hSlider->setSingleStep(4);
    ui->spinBoxAge->setSingleStep(4);
    ui->spinBox->setSingleStep(4);
    ui->hSliderAge->setRange(0, 115);
    ui->hSlider->setRange(0, 115);
    ui->spinBoxAge->setRange(0, 115);
    ui->spinBox->setRange(0, 115);
    //滑动条托动释放时触发信号
    ui->hSliderAge->setTracking(false);
    ui->hSlider->setTracking(false);
    connect(ui->hSliderAge, SIGNAL(valueChanged(int)), this, SLOT(slotValueChangedSliderAge(int)));
    connect(ui->spinBoxAge, SIGNAL(valueChanged(int)), this, SLOT(slotValueChangedSpinBoxAge(int)));
    connect(ui->hSlider, SIGNAL(valueChanged(int)), this, SLOT(slotValueChangedSlider(int)));
    connect(ui->spinBox, SIGNAL(valueChanged(int)), this, SLOT(slotValueChangedSpinBox(int)));
}

void Dialog::slotValueChangedSliderAge(int value)
{
    ui->spinBoxAge->blockSignals(true);
    ui->spinBoxAge->setValue(value);
    ui->spinBoxAge->blockSignals(false);
}

void Dialog::slotValueChangedSpinBoxAge(int value)
{
    ui->hSliderAge->blockSignals(true);
    ui->hSliderAge->setValue(value);
    ui->hSliderAge->blockSignals(false);
}

void Dialog::slotValueChangedSlider(int value)
{
    ui->spinBox->blockSignals(true);
    ui->spinBox->setValue(value);
    ui->spinBox->blockSignals(false);
}

void Dialog::slotValueChangedSpinBox(int value)
{
    ui->hSlider->blockSignals(true);
    ui->hSlider->setValue(value);
    ui->hSlider->blockSignals(false);
}

bool Dialog::eventFilter(QObject *watched, QEvent *event)
{
    if(ui->hSliderAge == watched && event->type() == QEvent::MouseButtonPress)
    {
        QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
        if(mouseEvent->button() == Qt::LeftButton)
        {
            //方法1:
//            int curValue = ui->hSliderAge->maximum() - ui->hSliderAge->minimum();
//            int curPos = ui->hSliderAge->minimum() + curValue*(static_cast<double>(mouseEvent->x()) / ui->hSliderAge->width());
//            ui->hSliderAge->setValue(curPos);
            //方法2:
//            int value = QStyle::sliderValueFromPosition(ui->hSliderAge->minimum(), ui->hSliderAge->maximum(), mouseEvent->pos().x(), ui->hSliderAge->width());
//            ui->hSliderAge->setValue(value);

            //方法3:
            eventFilter2(watched, event);

        }
    }
    return QDialog::eventFilter(watched, event);
}

bool Dialog::eventFilter2(QObject *watched, QEvent *event)
{
    if(watched == ui->hSliderAge && event->type() == QEvent::MouseButtonPress)
    {
        QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
        //捕获左键按下
        if(mouseEvent->button() == Qt::LeftButton)
        {
            int chunkLen{0};       //滑块宽度
            int sliderLen{0};      //滑槽宽度
            int mousePos{0};       //鼠标按下的位置
            //水平滑动条
            if(ui->hSliderAge->orientation() == Qt::Horizontal)
            {
                chunkLen = ui->hSliderAge->minimumSizeHint().width();
                sliderLen = ui->hSliderAge->width();
                if(ui->hSliderAge->invertedAppearance())
                {
                    mousePos = sliderLen - mouseEvent->x();
                }
                else
                {
                    mousePos = mouseEvent->x();
                }
            }
            else
            {
                //垂直滑动条
                chunkLen = ui->hSliderAge->minimumSizeHint().height();
                sliderLen = ui->hSliderAge->height();
                if(ui->hSliderAge->invertedAppearance())
                {
                    mousePos = sliderLen - mouseEvent->y();
                }
                else
                {
                    mousePos = mouseEvent->y();
                }
            }

            if(sliderLen > chunkLen)
            {
                //计算位置,设置滑动位置
                int curValue = ui->hSliderAge->maximum() - ui->hSliderAge->minimum();
                int sliderPos = ui->hSliderAge->minimum() +
                        (int)(curValue * (mousePos - chunkLen/2.0)/(sliderLen - chunkLen));
                if(ui->hSliderAge->sliderPosition() != sliderPos)
                {
                    ui->hSliderAge->setSliderPosition(sliderPos);
                }
            }
        }
    }

    return QDialog::eventFilter(watched, event);
}

参考:
https://www.cnblogs.com/Gaaagaa/p/12130799.html
https://blog.csdn.net/lion_cxq/article/details/128212132
https://blog.csdn.net/qq_14945437/article/details/98730805

使用 `installEventFilter` 来为 `QSlider` 安装事件过滤器,可以捕获和处理滑块控件的事件。通过事件过滤器,你可以拦截并处理滑块控件的各种事件,例如鼠标点击、滑动等。 下面是一个示例代码,展示如何使用事件过滤器来监听 `QSlider` 的鼠标点击事件: ```cpp #include <QSlider> #include <QEvent> #include <QDebug> class SliderEventFilter : public QObject { Q_OBJECT public: explicit SliderEventFilter(QObject *parent = nullptr) : QObject(parent) {} protected: bool eventFilter(QObject *obj, QEvent *event) override { if (event->type() == QEvent::MouseButtonPress) { QSlider *slider = qobject_cast<QSlider*>(obj); if (slider) { qDebug() << "Slider clicked!"; // 在这里处理滑块点击事件的逻辑 return true; } } return QObject::eventFilter(obj, event); } }; ``` 在上面的示例中,我们创建了一个继承自 `QObject` 的事件过滤器类 `SliderEventFilter`。在 `eventFilter` 方法中,我们首先判断接收到的事件类型是否为鼠标按下事件(`QEvent::MouseButtonPress`),然后使用 `qobject_cast` 将对象转换为 `QSlider` 类型。如果转换成功,说明事件发生在 `QSlider` 上,我们在这里可以处理滑块点击事件的逻辑。 为了使用事件过滤器,你需要在你的代码中安装它: ```cpp QSlider *slider = new QSlider(parent); SliderEventFilter *eventFilter = new SliderEventFilter(slider); slider->installEventFilter(eventFilter); ``` 通过以上步骤,你可以成功使用事件过滤器来监听和处理 `QSlider` 的鼠标点击事件。你可以根据需要在 `eventFilter` 方法中处理其他类型的事件,以实现自定义的功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值