最近做项目使用到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