需求:我们需要对一个滑动条 滚轮事件 和 点击到滑动条的位置 实时显示
问题:其中在做的时候遇到了很多的问题,一开始感觉很简单,现在将这些问题记录下来
ui图:
问题1:处理QSlider 滚轮事件的时候
这里有很大的问题,但是不知道原因,为什么会出现这样的原因,网上也没搜索到相关的内容
问题描述:我们在打印我们的滑动条的值的时候显示不正确
为了更加清楚显示值的变化,我加了值的显示(这个是测试需要,方便写笔记查看)
bool SliderWidget::eventFilter(QObject* watched, QEvent* event)
{
if (ui.slider == watched)
{
if (event->type() == QEvent::Wheel)
{
QWheelEvent* wheelEvent = static_cast<QWheelEvent*>(event);
ui.lineEdit1->setText(QString::number(m_index1));
ui.lineEdit2->setText(QString::number(ui.slider->value()));
ui.lineEdit3->setText(QString::number(ui.slider->sliderPosition()));
}
}
return QWidget::eventFilter(watched, event);
}
不知道各位有没有看出这个滑动条的值出现了什么错误:
错误1:当我在向右滑动的时候,滑到最右边的时候,我再向滑动时,滑动条的值是在第10条分割线,上面显示的值: 10 ,实际应该的值:9
错误2:当我继续在向左滑动时,滑动条对应的值 都 对应不上了,上面显示的值 都比原来减少了1
错误3:当我滑动到最左边的时候,我 操控滑动条 从右 再 向左 , 上面的 值竟然从1-》2-》1,实际应该为 2-》1-》0
我的解决办法是:因为刻度总共有11个,通过滑动条 向前 向后 来改变index 的值
bool SliderWidget::eventFilter(QObject* watched, QEvent* event)
{
if (ui.slider == watched)
{
if (event->type() == QEvent::Wheel)
{
//滚轮向前
if (wheelEvent->delta() > 0)
{
if (m_index1 >= 10)
{
m_index1 = 10;
}
else if (m_index1 < 10)
{
m_index1 += 1;
}
}
else if (wheelEvent->delta() < 0)
{
if (m_index1 <= 0)
{
m_index1 = 0;
}
else if (m_index1 > 0)
{
m_index1 -= 1;
}
}
//获取滑动条的值
ui.lineEdit1->setText(QString::number(m_index1));
}
}
return QWidget::eventFilter(watched, event);
}
结果如下:此时我获取的index 值时正确的,因为另外两个参数不是我需要的
问题2:处理QSlider 点击位置事件的时候
问题描述:我发现QSlider点击最后一个刻度的时候,非常的困难,基本上不可能到最后一个刻度(只通过点击的形式,不通过滑动条滚动的形式)
bool SliderWidget::eventFilter(QObject* watched, QEvent* event)
{
if (ui.slider == watched)
{
if (event->type() == QEvent::MouseButtonRelease)
{
//根据鼠标点击的位置 来设置滑动条的 位置
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
if (mouseEvent->button() == Qt::LeftButton)
{
int curValue = ui.slider->maximum() - ui.slider->minimum();
int curPos = ui.slider->minimum() + curValue * (static_cast<double>(mouseEvent->x()) / ui.slider->width());
ui.slider->setValue(curPos);
}
}
}
return QWidget::eventFilter(watched, event);
}
效果如下:我们发现 点击最后一个确实非常的困难
解决办法:
bool SliderWidget::eventFilter(QObject* watched, QEvent* event)
{
if (ui.slider == watched)
{
if (event->type() == QEvent::MouseButtonRelease)
{
//根据鼠标点击的位置 来设置滑动条的 位置
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
if (mouseEvent->button() == Qt::LeftButton)
{
int value = QStyle::sliderValueFromPosition(ui.slider->minimum(), ui.slider->maximum(), mouseEvent->pos().x(), ui.slider->width());
ui.slider->setValue(value);
}
}
}
return QWidget::eventFilter(watched, event);
}
问题3:因为我的需求是 两个按钮共享一个滑动条,但是 两个 滑动条 有自己对应的index,此时我们就需要设置点击到自己的按钮的时候,设置index值
bool SliderWidget::eventFilter(QObject* watched, QEvent* event)
{
if (ui.slider == watched)
{
if (event->type() == QEvent::Wheel)
{
//滚轮向前
if (wheelEvent->delta() > 0)
{
if (m_index1 >= 10)
{
m_index1 = 10;
}
else if (m_index1 < 10)
{
m_index1 += 1;
}
}
else if (wheelEvent->delta() < 0)
{
if (m_index1 <= 0)
{
m_index1 = 0;
}
else if (m_index1 > 0)
{
m_index1 -= 1;
}
}
//获取滑动条的值
ui.lineEdit1->setText(QString::number(m_index1));
qDebug() << "m_index:" << m_index1;
//既然获取到了正确的m_index1 ,那么我们直接设置值应该没有问题吧(下面两种形式都不行,滑动条滑动的时候 会错乱,导致我们的index 错乱)
ui.slider->setValue((int)m_index1);
//ui.slider->setSliderPosition(m_index);
}
}
return QWidget::eventFilter(watched, event);
}
void SliderWidget::on_btn1_clicked()
{
ui.slider->setValue(m_index1);
}
看一下下面的动图,很明显的就发现了问题
错误1:此时打乱了 我们原本正确的对应滑动条 的index 值,现在获取也不正确了
错误2:我们发现向前滑动一次 然后 向后 滑动一次 ,或者相反;滑动条的值 竟然跳了 2 个间隔,但是我在ui设置的时候只有1个间隔,这是肯定错误的,获取的值肯定是不正确的
解决办法:我就尝试不在事件过滤器里做操作,我在滑动条的ValueChanged事件中做操作
connect(ui.slider, &QSlider::valueChanged, this, [=](int value) {
ui.slider->setValue(value);
if (ui.btn1->isChecked())
{
m_index1 = ui.slider->value();
ui.lineEdit1->setText(QString::number(m_index1));
qDebug() << "m_index1:" << m_index1;
}
else if (ui.btn2->isChecked())
{
m_index2 = ui.slider->value();
ui.lineEdit1->setText(QString::number(m_index2));
qDebug() << "m_index2:" << m_index2;
}
});
完整代码:
.h文件
#pragma once
#include <QWidget>
#include "ui_SliderWidget.h"
#include <QWheelEvent>
#include <QDebug>
#include <QPoint>
#include <QStyle>
#include <QSlider>
class SliderWidget : public QWidget
{
Q_OBJECT
public:
SliderWidget(QWidget* parent = Q_NULLPTR);
~SliderWidget();
private:
bool eventFilter(QObject* watched, QEvent* event);
public slots:
void on_btn1_clicked();
void on_btn2_clicked();
private:
Ui::SliderWidgetClass ui;
quint8 m_index1 = 5;
quint8 m_index2 = 5;
};
.cpp文件
#include "SliderWidget.h"
SliderWidget::SliderWidget(QWidget* parent)
: QWidget(parent)
{
ui.setupUi(this);
ui.slider->installEventFilter(this);
connect(ui.slider, &QSlider::valueChanged, this, [=](int value) {
ui.slider->setValue(value);
if (ui.btn1->isChecked())
{
m_index1 = ui.slider->value();
ui.lineEdit1->setText(QString::number(m_index1));
}
else if (ui.btn2->isChecked())
{
m_index2 = ui.slider->value();
ui.lineEdit1->setText(QString::number(m_index2));
}
});
}
SliderWidget::~SliderWidget()
{
}
bool SliderWidget::eventFilter(QObject* watched, QEvent* event)
{
if (ui.slider == watched)
{
if (event->type() == QEvent::MouseButtonRelease)
{
//根据鼠标点击的位置 来设置滑动条的 位置
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
if (mouseEvent->button() == Qt::LeftButton)
{
//int nDur = ui.slider->maximum() - ui.slider->minimum();
//int nPos = ui.slider->minimum() + nDur * (static_cast<double>(mouseEvent->x()) / ui.slider->width());
int value = QStyle::sliderValueFromPosition(ui.slider->minimum(), ui.slider->maximum(), mouseEvent->pos().x(), ui.slider->width());
ui.slider->setValue(value);
//m_index1 = value;
//qDebug() << "m_index:" << m_index1;
//qDebug() << "value:" << ui.slider->value();
//qDebug() << "nPos:" << nPos;
//m_index = value + 1;
设定滑动条位置
ui.slider->setValue(value);
qDebug()<< "position:" << ui.slider->sliderPosition();
qDebug() << "value:" << ui.slider->value();
m_index = ui.slider->value();
//ui.slider->setSliderPosition(value);
//qDebug() << "m_index:" << m_index;
//qDebug() << "positition:" << ui.slider->sliderPosition();
//qDebug() << "value:" << ui.slider->value();
//获取当前点击位置,得到的这个鼠标坐标是相对于当前QSlider的坐标
//int currentX = mouseEvent->pos().x();
//
//qDebug() <<"currentX:" << currentX;
获取当前点击的位置占整个Slider的百分比
//double per = currentX * 1.0 / ui.slider->width();
//qDebug() <<"width:" << ui.slider->width();
利用算得的百分比得到具体数字
//int value = per * (ui.slider->maximum() - ui.slider->minimum()) + ui.slider->minimum();
//
//if (value <= 0)
//{
// value = 0;
//}
//else if (value >= 10)
//{
// value = 10;
//}
//qDebug() << value;
//m_index = value;
//ui.slider->setValue(value);
}
}
else if (event->type() == QEvent::Wheel)
{
QWheelEvent* wheelEvent = static_cast<QWheelEvent*>(event);
//滚轮向前
if (wheelEvent->delta() > 0)
{
if (m_index1 >= 10)
{
m_index1 = 10;
}
else if (m_index1 < 10)
{
m_index1 += 1;
}
}
else if (wheelEvent->delta() < 0)
{
if (m_index1 <= 0)
{
m_index1 = 0;
}
else if (m_index1 > 0)
{
m_index1 -= 1;
}
}
ui.lineEdit1->setText(QString::number(m_index1));
//m_index1 = ui.slider->sliderPosition();
//ui.lineEdit2->setText(QString::number(ui.slider->value()));
//ui.lineEdit3->setText(QString::number(ui.slider->sliderPosition()));
//qDebug() << "m_index:" << m_index1;
//qDebug() << "value:" << ui.slider->value();
//qDebug() << "position:" << ui.slider->sliderPosition();
//ui.slider->setValue((int)m_index1);
//qDebug() << "value:" << ui.slider->value();
//qDebug() << "value:" << ui.slider->value();
//ui.slider->setSliderPosition(m_index);
//qDebug() << ui.slider->sliderPosition();
}
}
return QWidget::eventFilter(watched, event);
}
void SliderWidget::on_btn1_clicked()
{
ui.slider->setValue(m_index1);
}
void SliderWidget::on_btn2_clicked()
{
ui.slider->setValue(m_index2);
}
参考博客:
QSlider设置滚动块定位到鼠标点击的地方
Qt之QSlider介绍(属性设置、信号、实现滑块移动到鼠标点击位置)
Qt滑动条解决点击和拖动问题