草庐IT

QT笔记——QSlider滑动条滚轮事件和点击鼠标位置事件问题

lion_cxq 2023-10-15 原文

需求:我们需要对一个滑动条 滚轮事件 和 点击到滑动条的位置 实时显示
问题:其中在做的时候遇到了很多的问题,一开始感觉很简单,现在将这些问题记录下来

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);
			//static int index = 5;
			//滚轮向前 
			if (wheelEvent->delta() > 0)
			{
				if (ui.btn1->isChecked())
				{
					if (m_index1 >= 10)
					{
						m_index1 = 10;
					}
					else if (m_index1 < 10)
					{
						m_index1 += 1;
					}
				}
				else if (ui.btn2->isChecked())
				{
					if (m_index2 >= 10)
					{
						m_index2 = 10;
					}
					else if (m_index2 < 10)
					{
						m_index2 += 1;
					}
				}

			}
			else if (wheelEvent->delta() < 0)
			{
				if (ui.btn1->isChecked())
				{
					if (m_index1 <= 0)
					{
						m_index1 = 0;
					}
					else if (m_index1 > 0)
					{
						m_index1 -= 1;
					}
				}
				else if (ui.btn2->isChecked())
				{
					if (m_index2 <= 0)
					{
						m_index2 = 0;
					}
					else if (m_index2 > 0)
					{
						m_index2 -= 1;
					}
				}

			}
			if (ui.btn1->isChecked())
			{
				ui.lineEdit1->setText(QString::number(m_index1));
			}
			else if (ui.btn2->isChecked())
			{
				ui.lineEdit1->setText(QString::number(m_index2));
			}

			//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滑动条解决点击和拖动问题

有关QT笔记——QSlider滑动条滚轮事件和点击鼠标位置事件问题的更多相关文章

  1. ruby - 在 64 位 Snow Leopard 上使用 rvm、postgres 9.0、ruby 1.9.2-p136 安装 pg gem 时出现问题 - 2

    我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po

  2. ruby - 通过 rvm 升级 ruby​​gems 的问题 - 2

    尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub

  3. ruby - 通过 RVM (OSX Mountain Lion) 安装 Ruby 2.0.0-p247 时遇到问题 - 2

    我的最终目标是安装当前版本的RubyonRails。我在OSXMountainLion上运行。到目前为止,这是我的过程:已安装的RVM$\curl-Lhttps://get.rvm.io|bash-sstable检查已知(我假设已批准)安装$rvmlistknown我看到当前的稳定版本可用[ruby-]2.0.0[-p247]输入命令安装$rvminstall2.0.0-p247注意:我也试过这些安装命令$rvminstallruby-2.0.0-p247$rvminstallruby=2.0.0-p247我很快就无处可去了。结果:$rvminstall2.0.0-p247Search

  4. ruby - Fast-stemmer 安装问题 - 2

    由于fast-stemmer的问题,我很难安装我想要的任何ruby​​gem。我把我得到的错误放在下面。Buildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingfast-stemmer:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcreatingMakefilemake"DESTDIR="cleanmake"DESTDIR=

  5. ruby - 安装 Ruby 时遇到问题(无法下载资源 "readline--patch") - 2

    当我尝试安装Ruby时遇到此错误。我试过查看this和this但无济于事➜~brewinstallrubyWarning:YouareusingOSX10.12.Wedonotprovidesupportforthispre-releaseversion.Youmayencounterbuildfailuresorotherbreakages.Pleasecreatepull-requestsinsteadoffilingissues.==>Installingdependenciesforruby:readline,libyaml,makedepend==>Installingrub

  6. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

  7. ruby-on-rails - 简单的 Ruby on Rails 问题——如何将评论附加到用户和文章? - 2

    我意识到这可能是一个非常基本的问题,但我现在已经花了几天时间回过头来解决这个问题,但出于某种原因,Google就是没有帮助我。(我认为部分问题在于我是一个初学者,我不知道该问什么......)我也看过O'Reilly的RubyCookbook和RailsAPI,但我仍然停留在这个问题上.我找到了一些关于多态关系的信息,但它似乎不是我需要的(尽管如果我错了请告诉我)。我正在尝试调整MichaelHartl'stutorial创建一个包含用户、文章和评论的博客应用程序(不使用脚手架)。我希望评论既属于用户又属于文章。我的主要问题是:我不知道如何将当前文章的ID放入评论Controller。

  8. ruby-on-rails - 事件管理员日期过滤器日期格式自定义 - 2

    是否有简单的方法来更改默认ISO格式(yyyy-mm-dd)的ActiveAdmin日期过滤器显示格式? 最佳答案 您可以像这样为日期选择器提供额外的选项,而不是覆盖js:=f.input:my_date,as::datepicker,datepicker_options:{dateFormat:"mm/dd/yy"} 关于ruby-on-rails-事件管理员日期过滤器日期格式自定义,我们在StackOverflow上找到一个类似的问题: https://s

  9. 【高数】用拉格朗日中值定理解决极限问题 - 2

    首先回顾一下拉格朗日定理的内容:函数f(x)是在闭区间[a,b]上连续、开区间(a,b)上可导的函数,那么至少存在一个,使得:通过这个表达式我们可以知道,f(x)是函数的主体,a和b可以看作是主体函数f(x)中所取的两个值。那么可以有,  也就意味着我们可以用来替换 这种替换可以用在求某些多项式差的极限中。方法: 外层函数f(x)是一致的,并且h(x)和g(x)是等价无穷小。此时,利用拉格朗日定理,将原式替换为 ,再进行求解,往往会省去复合函数求极限的很多麻烦。使用要注意:1.要先找到主体函数f(x),即外层函数必须相同。2.f(x)找到后,复合部分是等价无穷小。3.要满足作差的形式。如果是加

  10. Qt Designer的简单使用 - 2

    在前面两节的例子中,主界面窗口的尺寸和标签控件显示的矩形区域等,都是用C++代码编写的。窗口和控件的尺寸都是预估的,控件如果多起来,那就不好估计每个控件合适的位置和大小了。用C++代码编写图形界面的问题就是不直观,因此Qt项目开发了专门的可视化图形界面编辑器——QtDesigner(Qt设计师)。通过QtDesigner就可以很方便地创建图形界面文件*.ui,然后将ui文件应用到源代码里面,做到“所见即所得”,大大方便了图形界面的设计。本节就演示一下QtDesigner的简单使用,学习拖拽控件和设置控件属性,并将ui文件应用到Qt程序代码里。使用QtDesigner设计界面在开始菜单中找到「Q

随机推荐