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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/369372.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Linux】Ext2 文件系统

文件系统 前言一、磁盘硬件1. 磁盘的物理存储结构2. 磁盘存储的逻辑抽象结构 二、理解 Ext2 文件系统1. 初步理解文件系统2. 深入理解文件系统&#xff08;1&#xff09;inode Table&#xff08;2&#xff09;Data blocks&#xff08;3&#xff09;inode Bitmap&#xff08;4&a…

内衣洗衣机是不是鸡肋?好用的小型洗衣机全自动推荐

随着大家工作的压力越来越大&#xff0c;下了班之后只能想躺平&#xff0c;在洗完澡之后看着还需要手洗的内衣裤真的很头疼。有些小伙伴还有会攒几天再丢进去洗衣机里面一起&#xff0c;而且这样子是非常不好的&#xff0c;用过的内衣裤长时间不清洗容易滋生细菌&#xff0c;而…

python_ACM模式《剑指offer刷题》二叉树1

题目&#xff1a; 面试tips&#xff1a; 1. 询问是否可以使用双端队列 (看后面思路就可知为什么要问这个) 思路&#xff1a; 时复和空复都为O(n) 思路一&#xff1a;利用双端队列。总体思想是利用二叉树层序遍历(二叉树的层序遍历就是用队列dq&#xff0c;且从左往右每一层…

【C++】笔试训练(八)

目录 一、选择题二、编程题1、两种排序方法2、求最小公倍数 一、选择题 1、关于重载函数&#xff0c;哪个说明是正确的&#xff08;&#xff09; A 函数名相同&#xff0c;参数类型或个数不同 B 函数名相同&#xff0c;返回值类型不同 C 函数名相同&#xff0c;函数内部实现不…

第十二篇【传奇开心果系列】Python的OpenCV技术点案例示例:视频流处理

传奇开心果短博文系列 系列短博文目录Python的OpenCV技术点案例示例短博文系列短博文目录一、前言二、视频流处理介绍三、实时视频流处理示例代码四、视频流分析示例代码五、归纳总结系列短博文目录 Python的OpenCV技术点案例示例短博文系列 短博文目录 一、前言 OpenCV视频…

机器学习_无监督学习之聚类

文章目录 介绍机器学习下的分类K均值算法K值的选取:手肘法用聚类辅助理解营销数据贴近项目实战 介绍机器学习下的分类 以下介绍无监督学习之聚类 聚类是最常见的无监督学习算法。人有归纳和总结的能力&#xff0c;机器也有。聚类就是让机器把数据集中的样本按照特征的性质分组&…

消息队列-RabbitMQ

消息队列-RabbitMQ 中间件 中间件就是帮助连接多个系统&#xff0c;能让多个系统紧密协作的技术或者组件。比如&#xff1a;redis、消息队列。 比如在分布式系统中&#xff0c;将整个系统按业务进行拆分。分成不同的子系统&#xff0c;系统A负责往 redis 存数据&#xff0c;…

ReactNative实现一个圆环进度条

我们直接看效果,如下图 我们在直接上代码 /*** 圆形进度条*/ import React, {useState, useEffect} from react; import Svg, {Circle,G,LinearGradient,Stop,Defs,Text, } from react-native-svg; import {View, StyleSheet} from react-native;// 渐变色 const CircleProgr…

Android学习之路(29) Gradle初探

前言: 大家回想一下自己第一次接触Gradle是什么时候&#xff1f; 相信大家也都是和我一样&#xff0c;在我们打开第一个AS项目的时候&#xff0c; 发现有很多带gradle字样的文件&#xff1a;setting.gradle, build.gradle,gradle.warpper,以及在gradle文件中各种配置&#xff…

基于LLM的文档搜索引擎开发【Ray+LangChain】

Ray 是一个非常强大的 ML 编排框架&#xff0c;但强大的功能伴随着大量的文档。 事实上120兆字节。 我们如何才能使该文档更易于访问&#xff1f; 答案&#xff1a;使其可搜索&#xff01; 过去&#xff0c;创建自己的高质量搜索结果很困难。 但通过使用 LangChain&#xff0c…

Open CASCADE学习|拓扑变换

目录 平移变换 旋转变换 组合变换 通用变换 平移变换 TopoDS_Shape out;gp_Trsf theTransformation;gp_Vec theVectorOfTranslation(0., 0.125 / 2, 0.);theTransformation.SetTranslation(theVectorOfTranslation);BRepBuilderAPI_Transform myBRepTransformation(out, th…

EAK厚膜功率电阻成功在eVTOL大量使用

eVTOL操作的特点是更高的放电曲线&#xff0c;特别是在起飞和着陆期间。 “传统上&#xff0c;电池要么被设计成提供大量能量&#xff0c;要么被设计成高功率&#xff0c;”Cuberg创始人兼首席执行官Richard Wang说。“对于eVTOL电池来说&#xff0c;在能量和功率之间保持良好…

Acwing---826.单链表

单链表 1.题目2.基本思想3.代码实现 1.题目 实现一个单链表&#xff0c;链表初始为空&#xff0c;支持三种操作&#xff1a; 向链表头插入一个数&#xff1b;删除第 k k k 个插入的数后面的数&#xff1b;在第 k k k 个插入的数后插入一个数。现在要对该链表进行 M M M 次…

中科大计网学习记录笔记(五):协议层次和服务模型

前言&#xff1a; 学习视频&#xff1a;中科大郑烇、杨坚全套《计算机网络&#xff08;自顶向下方法 第7版&#xff0c;James F.Kurose&#xff0c;Keith W.Ross&#xff09;》课程 该视频是B站非常著名的计网学习视频&#xff0c;但相信很多朋友和我一样在听完前面的部分发现信…

如何计算两个指定日期相差几年几月几日

一、题目要求 假定给出两个日期&#xff0c;让你计算两个日期之间相差多少年&#xff0c;多少月&#xff0c;多少天&#xff0c;应该如何操作呢&#xff1f; 本文提供网页、ChatGPT法、VBA法和Python法等四种不同的解法。 二、解决办法 1. 网页计算法 这种方法是利用网站给…

69.请描述Spring MVC的工作流程?描述一下 DispatcherServlet 的工作流程?

69.请描述Spring MVC的工作流程&#xff1f;描述一下 DispatcherServlet 的工作流程&#xff1f; 核心架构的具体流程步骤如下&#xff1a; 首先用户发送请求——>DispatcherServlet&#xff0c;前端控制器收到请求后自己不进行处理&#xff0c;而是委托给其他的解析器进行…

day30 window对象——BOM、定时器setTimeout

目录 JavaScript的组成BOM定时器——延时函数两种定时器对比&#xff1a;执行的次数 JavaScript的组成 ECMAScript: 规定了js基础语法核心知识。比如&#xff1a;变量、分支语句、循环语句、对象等等 Web APIs : DOM 文档对象模型&#xff0c; 定义了一套操作HTML文档的APIBOM…

【Iot】什么是串口?什么是串口通信?串口通信(串口通讯)原理,常见的串口通信方式有哪些?

串口通信原理 1. 串口2. 串口通信4. 波特率与比特率5. 帧格式3. 串口通讯的通讯协议3.1. RS2323.2. RS485 总结 1. 串口 串行接口简称串口&#xff0c;也称串行通信接口或串行通讯接口&#xff08;通常指COM接口&#xff09;&#xff0c;是采用串行通信方式的扩展接口。 串口可…

CICD注册和使用gitlab-runner常见问题

1、现象 fatal: unable to access https://github.com/homebrew/brew/: 2、解决 git config --global --unset http.proxy git config --global --unset https.proxy 查看gitlab-runner是否成功&#xff1a; userusers-MacBook-Pro ~ % gitlab-runner -h 查看gitlab-run…

Vue.js设计与实现(霍春阳)

Vue.js设计与实现 (霍春阳) 电子版获取链接&#xff1a;Vue.js设计与实现(霍春阳) 编辑推荐 适读人群 &#xff1a;1.对Vue.js 2/3具有上手经验&#xff0c;且希望进一步理解Vue.js框架设计原理的开发人员&#xff1b; 2.没有使用过Vue.js&#xff0c;但对Vue.js框架设计感兴趣…