Qt关于平滑滚动的使用QScroller及QScrollerProperties类说明

news2025/2/28 21:37:10

一、触控时代的滚动工具:QScroller类设计介绍

1.1 从机械滚轮到数字惯性

在触控设备普及前,滚动操作如同老式打字机的滚轴,只能通过鼠标滚轮或滚动条进行离散式控制。QScroller的出现如同给数字界面装上了"惯性飞轮",通过模拟物理上的动量守恒定律,让滚动操作具备以下特性:

  • 速度传递:滑动速度决定滚动距离;
  • 动态衰减:摩擦系数影响停止时间;
  • 边界弹性:类似橡皮筋的越界回弹效果;

1.2 类关系拓扑图

QScroller ────┬── QScrollerProperties 
              ├── QScrollEvent 
              └── QScrollPrepareEvent 

QScroller作为控制器,通过QScrollerProperties配置物理参数,生成QScrollEvent事件以驱动界面的刷新。

二、核心类深度解析

2.1 QScroller类:滚动引擎

关键方法说明:

// 启用控件手势支持(核心入口)
static QScroller *QScroller::grabGesture(
    QObject *target, 
    QScroller::GestureType gestureType = TouchGesture 
);

//检查指定的目标对象是否已经关联了 QScroller 实例
static bool hasScroller(QObject *target) ;

//使指定的目标对象停止捕获指定类型的滚动手势
static void ungrabGesture(QObject *target, 
QScroller::ScrollerGestureType gestureType);

// 获取当前滚动状态 
QScroller::State state() const; 
 
// 滚动到指定区域(带动画)
void scrollTo(const QVector2D &pos, 
             qreal scrollTime = 0);
 
// 确保子控件可见(自动计算滚动路径)
void ensureVisible(const QRectF &rect, 
                  qreal xmargin = 0.1, 
                  qreal ymargin = 0.1);

//设置滚动器的属性,如滚动速度、摩擦力、弹性等
void setScrollerProperties(const QScrollerProperties &properties);

//启动滚动器,开始滚动操作
void start();

//停止滚动器,终止滚动操作
void stop();

//设置水平方向的捕捉位置。当滚动到这些位置时,滚动器会自动对齐到这些位置。
void setSnapPositionsX(const QList<qreal> &positions);

//设置垂直方向的捕捉位置。当滚动到这些位置时,滚动器会自动对齐到这些位置。
void setSnapPositionsY(const QList<qreal> &positions);

手势类型枚举:

enum GestureType {
    TouchGesture,        // 触摸手势 
    LeftMouseButtonGesture, // 左键拖拽
    RightMouseButtonGesture // 右键拖拽(特殊场景)
};

2.2 QScrollerProperties:设置和调整配置参数

这个类就像汽车的"悬挂调校系统"调节汽车引擎一样,专门调整设置QScroller类的配置参数,包含几十个可配置参数,主要有:

QScrollerProperties properties;

//设置滚轮滚动过程中画面的帧率,帧率越高看着越舒服,帧率越低画面越跳动
properties.setScrollMetric(QScrollerProperties::FrameRate,QScrollerProperties::Fps30);
//设置平滑速度,当滑动完手离开屏幕后,进行平滑滑动的速度,此值应介于0和1之间。值越小,速度越慢。但我试过实际没太明显的区别
properties.setScrollMetric(QScrollerProperties::DragVelocitySmoothingFactor,0.3);
//设置鼠标释放后滚动到停止时的运动曲线,参数为QEasingCurve类型,不能设置为QEasingCurve::Type类型,不会隐式转换
properties.setScrollMetric(QScrollerProperties::ScrollingCurve,QEasingCurve::OutQuad);
//设置移动阀值(按下后需要移动最少距离后,触发滑动),用来避免误操作
properties.setScrollMetric(QScrollerProperties::DragStartDistance,0.003);
//设置减速因子,值越大,减速越快,进而会影响点击释放后滚动的距离。对于大多数类型,该值应在0.1到2.0的范围内
properties.setScrollMetric(QScrollerProperties::DecelerationFactor,0.4);
//设置当运动方向与某一个轴的角度小于该设定值(0~1)时,则限定只有该轴方向的滚动,一般就用0.5,两个轴都是,不然要么区域重叠,要么区域漏掉
properties.setScrollMetric(QScrollerProperties::AxisLockThreshold,0.5);
//自动滚动过程中,鼠标点击操作会停止当前滚动,当速度大于该设定(m/s)时,鼠标事件不会传递给目标即不会停止滚动
properties.setScrollMetric(QScrollerProperties::MaximumClickThroughVelocity,0.5);
//与AcceleratingFlickSpeedupFactor配合使用。设置时间及加速因子
properties.setScrollMetric(QScrollerProperties::AcceleratingFlickMaximumTime ,3);
//与AcceleratingFlickMaximumTime配合使用,应>=1
properties.setScrollMetric(QScrollerProperties::AcceleratingFlickSpeedupFactor,2);
//设置自动滑动的最小速度,m/s,如果手势的速度小于该速度,则不会触发自动滚动,所以可以设置得小一些,防止手指轻微移动引起屏幕滚动
properties.setScrollMetric(QScrollerProperties::MinimumVelocity,0.2);
//设置自动滚动能达到得最大速度,m/s
properties.setScrollMetric(QScrollerProperties::MaximumVelocity,0.2);
//设置当拖拽过量时,释放后位置恢复所用时间(s)
properties.setScrollMetric(QScrollerProperties::OvershootScrollTime,0.2);
//设置滚动曲线的时间因子。设置滚动的时长,值越小,滚动时间越长
properties.setScrollMetric(QScrollerProperties::SnapTime,0.2);
//设置过量拖拽的距离占页面的比例,0~1,比如设置0.2,过量拖拽垂直最多移动高度的1/5
properties.setScrollMetric(QScrollerProperties::OvershootDragDistanceFactor,0.2);
//设置垂直向允许过量拖拽的策略,可以设置滚动条出现时开启、始终关闭、始终开启三种策略
properties.setScrollMetric(QScrollerProperties::VerticalOvershootPolicy,QScrollerProperties::OvershootWhenScrollable);
//设置过量拖拽的移动距离与鼠标移动距离的比例,0~1,值越小表现出的阻塞感越强
properties.setScrollMetric(QScrollerProperties::OvershootDragResistanceFactor,0.2);
//设置自动滚动时允许的过量滚动距离比例
properties.setScrollMetric(QScrollerProperties::OvershootScrollDistanceFactor,0.2);
//设置鼠标事件延迟时间,单位s。
properties.setScrollMetric(QScrollerProperties::MousePressEventDelay,1);

QScroller::scroller(ui->scrollArea)->setScrollerProperties(properties);

三、实现原理揭秘

3.1 事件处理流水线

sequenceDiagram 
    participant User 
    participant QScroller 
    participant Widget 
    
    User->>QScroller: 触摸/鼠标按下 
    QScroller->>Widget: 发送ScrollPrepare事件 
    Widget->>QScroller: 返回内容尺寸等信息 
    loop 每帧更新 
        QScroller->>QScroller: 计算物理运动参数 
        QScroller->>Widget: 发送ScrollEvent 
        Widget->>Widget: 更新显示位置 
    end 
    User->>QScroller: 释放操作 
    QScroller->>Widget: 触发惯性滚动 

3.2 物理模型公式

滚动位置计算采用改进型牛顿运动方程:

当前位置 = 初始位置 + 初速度 * t - 0.5 * 摩擦系数 * t²

其中摩擦系数通过QScrollerProperties::DecelerationFactor动态调整


四、实用代码示例

4.1 基础滑动实现

// 为QListWidget启用触控滑动 
QListWidget *list = new QListWidget(this);
QScroller *scroller = QScroller::scroller(list->viewport());
QScroller::grabGesture(list->viewport(), QScroller::TouchGesture);
 
// 配置滑动参数(类似手机APP的流畅感)
QScrollerProperties prop = scroller->scrollerProperties();
prop.setScrollMetric(QScrollerProperties::DragVelocitySmoothingFactor,  0.6);
prop.setScrollMetric(QScrollerProperties::OvershootScrollDistanceFactor,  0.3);
scroller->setScrollerProperties(prop);

4.2 高级分页滚动

// 相册浏览分页效果 
QScrollArea *gallery = new QScrollArea(this);
QScroller::grabGesture(gallery, QScroller::LeftMouseButtonGesture);
 
QScrollerProperties prop;
prop.setScrollMetric(QScrollerProperties::SnapPositionRatio,  1.0); // 整页吸附 
prop.setScrollMetric(QScrollerProperties::SnapTime,  0.5);         // 过渡动画时长 
QScroller::scroller(gallery)->setScrollerProperties(prop);

五、性能优化指南

  1. 渲染优化
// 启用像素级滚动(避免跳跃感)
listWidget->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
  1. 内存管理
// 及时释放不再使用的滚动器
QScroller::ungrabGesture(scrollArea); // 类似断开刹车系统
  1. 动态调参技巧
// 根据设备类型切换参数 
#ifdef Q_OS_ANDROID 
    prop.setScrollMetric(...);  // 移动端优化参数 
#else 
    prop.setScrollMetric(...);  // 桌面端参数 
#endif 

结语:滚动交互的未来

随着Qt6对QScroller的持续优化,已经未来产品更趋向于实际流畅感的需求,作为开发使用人员,这几个方面的优化值得我们关注使用:

  1. 多指操作与3D滚动集成
  2. 基于AI的动态参数调优
  3. 与Vulkan渲染引擎的深度结合

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

StableDiffusion打包 项目迁移 项目分发 1

文章目录 SD项目迁移前置知识webui-user.batwebui.batlaunch_utils.py 下一篇开始实践 SD项目迁移 显卡驱动更新&#xff1a;https://www.nvidia.cn/geforce/drivers/ 下载安装三个程序&#xff1a; python3.10.6: https://www.python.org/downloads/release/python-3106/gi…

【数据结构进阶】哈希表

&#x1f31f;&#x1f31f;作者主页&#xff1a;ephemerals__ &#x1f31f;&#x1f31f;所属专栏&#xff1a;数据结构 目录 前言 一、哈希表的概念 二、哈希函数的实现方法 1. 直接定址法 2. 除留余数法 三、哈希冲突 1. 开放定址法&#xff08;闭散列&#xff0…

【蓝桥杯嵌入式】各模块学习总结

系列文章目录 留空 文章目录 系列文章目录前言一、LED模块1.1 赛题要求1.2 模块原理图1.3 编写代码1.4 赛题实战 二、LCD模块2.1 赛题要求2.2 模块原理图2.3 编写代码2.4 赛题实战 三、按键模块3.1 赛题要求3.2 模块原理图3.3 编写代码3.4 赛题实战 四、串口模块4.1 赛题要求4…

Rust学习总结之-枚举

枚举是一个很多语言都有的功能&#xff0c;不过不同语言中其功能各不相同但是要表达的意思是一致的&#xff0c;枚举就是对于一个事物可以穷举出所有可能得值。比如说人的性别就可以用枚举&#xff0c;男人和女人两种。下面我们来学习Rust中的枚举。 一&#xff1a;枚举定义 …

Linux系统管理(十七)——配置英伟达驱动、Cuda、cudnn、Conda、Pytorch、Pycharm等Python深度学习环境

文章目录 前言安装驱动下载安装Cuda编辑环境变量安装Cudnn安装conda验证安装成功配置conda镜像退出conda环境创建python环境查看当前conda环境激活环境安装python包安装pytorch 安装pycharm安装jupyter notebook 前言 深度学习和大语言模型的部署不免会用到Linux系统&#xff…

SLAM算法工程师的技术图谱和学习路径

SLAM(Simultaneous Localization and Mapping)算法工程师是负责开发和实现用于机器人、自动驾驶车辆等领域的SLAM算法的专业人士。下面是SLAM算法工程师需要掌握的基础理论知识: 机器人运动学和动力学:理解机器人在空间中的运动方式和控制方法,包括轮式、蜘蛛腿、飞行器等…

深入了解 Python 中的 MRO(方法解析顺序)

文章目录 深入了解 Python 中的 MRO&#xff08;方法解析顺序&#xff09;什么是 MRO&#xff1f;如何计算 MRO&#xff1f;C3 算法的合并规则C3 算法的合并步骤示例&#xff1a;合并过程解析 MRO 解析失败的场景使用 mro() 方法查看 MRO示例 1&#xff1a;基本用法 菱形继承与…

如何防止 Instagram 账号被盗用:安全设置与注意事项

如何防止 Instagram 账号被盗用&#xff1a;安全设置与注意事项 在这个数字化时代&#xff0c;社交媒体平台如 Instagram 已成为我们日常生活的一部分。然而&#xff0c;随着网络犯罪的增加&#xff0c;保护我们的在线账户安全变得尤为重要。以下是一些关键的安全设置和注意事…

采样算法二:去噪扩散隐式模型(DDIM)采样算法详解教程

参考 https://arxiv.org/pdf/2010.02502 一、背景与动机 去噪扩散隐式模型&#xff08;DDIM&#xff09; 是对DDPM的改进&#xff0c;旨在加速采样过程同时保持生成质量。DDPM虽然生成效果优异&#xff0c;但其采样需迭代数百至数千次&#xff0c;效率较低。DDIM通过以下关键…

各种类型网络安全竞赛有哪些 网络安全大赛的简称

本文是对入门学习的一些概念了解和一些常规场景记录 1.CTF&#xff08;capture the flag&#xff09;是夺旗赛的意思。 是网络安全技术人员之间进行攻防的比赛。 起源1996年DEFCON全球黑客大会&#xff0c;替代之前真实攻击的技术比拼。 (DEFCON极客大会诞生1993&#xff0c;…

包子凑数——蓝桥杯真题Python

包子凑数 输入输出样例 示例 1 输入 2 4 5输出 6样例说明 凑不出的数目包括&#xff1a;1, 2, 3, 6, 7, 11。 示例 2 输入 2 4 6输出 INF样例说明 所有奇数都凑不出来&#xff0c;所以有无限多个 运行限制 最大运行时间&#xff1a;1s最大运行内存: 256M 最大公约数 最大公…

网络通信/IP网络划分/子网掩码的概念和使用

文章目录 概述子网的考题子网掩码的历史有/无类地址子网划分!子网掩码超网技术/CIDR子网掩码和路由IP子网掩码定义 网络规划网络规划-拆子网网络规划-组超网子网划分案例 区分于其他特殊IP地址IP地址和网络地址子网掩码和网络地址子网掩码和广播地址 子网间的通信其他 概述 本…

MySQL--》如何在MySQL中打造高效优化索引

目录 初识索引 索引结构 性能分析 索引使用 最左前缀法则 SQL提示使用 覆盖索引使用 前缀索引使用 索引失效情况 初识索引 索引(index)&#xff1a;是帮助MySQL高效获取数据的数据结构(有序)&#xff0c;在数据之外数据库系统还维护着满足特定查找算法的数据结构&…

盛京开源社区加入 GitCode,书写东北开源生态新篇章

在数字化转型与开源技术蓬勃发展的浪潮下&#xff0c;开源社区已成为推动技术创新的核心力量。盛京开源社区&#xff08;SJOSC&#xff09;作为沈阳地区的开源交流平台&#xff0c;始终致力于连接开发者、企业及高校&#xff0c;构建区域技术生态圈。 现在&#xff0c;盛京开源…

网络运维学习笔记(DeepSeek优化版)005网工初级(HCIA-Datacom与CCNA-EI)链路层发现协议与VLAN技术

文章目录 一、链路层发现协议1.1 思科CDP协议1.2 华为LLDP协议 二、VLAN&#xff08;Virtual Local Area Network&#xff0c;虚拟局域网&#xff09;技术详解2.1 基本概念2.2 技术特性2.3 接口工作原理2.3.1 Access模式2.3.2 Trunk模式 2.4 厂商配置对比思科配置华为配置 2.5 …

DeepSeek开源周Day4:三连发!突破 AI 训练瓶颈的立体解决方案,并行计算三剑客DualPipe、EPLB与Profile-data

项目地址&#xff1a; https://github.com/deepseek-ai/DualPipehttps://github.com/deepseek-ai/eplbhttps://github.com/deepseek-ai/profile-data 开源日历&#xff1a;2025-02-24起 每日9AM(北京时间)更新&#xff0c;持续五天 (4/5)&#xff01; ​ ​ 一、背景概述 …

树莓百度百科更新!宜宾园区业务再添新篇

树莓集团宜宾园区业务不断拓展&#xff0c;主要体现在以下几个方面&#xff1a; 产业布局 -聚焦数字经济核心领域&#xff1a;涵盖软件开发、人工智能、大数据等&#xff0c;吸引众多上下游企业入驻&#xff0c;形成从芯片研发、软件开发到系统集成的完整产业链条。 -推进“双…

RabbitMQ操作实战

1.RabbitMQ安装 RabbitMQ Windows 安装、配置、使用 - 小白教程-腾讯云开发者社区-腾讯云下载erlang&#xff1a;http://www.erlang.org/downloads/https://cloud.tencent.com/developer/article/2192340 Windows 10安装RabbitMQ及延时消息插件rabbitmq_delayed_message_exch…

OpenWebUI配置异常的外部模型导致页面无法打开

一、使用Ollama关闭OpenAI OpenWebUI自带OpenAI的API设置&#xff0c;且默认是打开的&#xff0c;默认情况下&#xff0c;启动后&#xff0c;会不断的去连https://api.openai.com/v1&#xff0c;但是无法连上&#xff0c;会报错&#xff0c;但是不会影响页面&#xff0c;能正常…

鸿蒙兼容Mapbox地图应用测试

鸿蒙Next已经发布一段时间了&#xff0c;很多之前的移动端地图应用&#xff0c;纷纷都要求适配鸿蒙Next。作为开发者都清楚&#xff0c;所谓的适配其实都是重新开发&#xff0c;鸿蒙的开发语言和纯前端的Javascript不同&#xff0c;也可以Android原始开发的语言不同。鸿蒙自带的…