qt浏览文件支持惯性
#include <QApplication>
#include <QListWidget>
#include <QScroller>
#include <QScrollerProperties>int main(int argc, char *argv[]) {QApplication app(argc, argv);// 创建列表控件并添加示例项QListWidget listWidget;for (int i = 0; i < 100; ++i) {listWidget.addItem(QString("文件 %1").arg(i));}listWidget.resize(400, 300);listWidget.show();// 启用惯性滚动:触摸手势// QScroller::grabGesture(listWidget.viewport(), QScroller::TouchGesture);// 或者启用鼠标左键拖动惯性QScroller::grabGesture(listWidget.viewport(), QScroller::LeftMouseButtonGesture);// 获取Scroller对象并设置参数QScroller *scroller = QScroller::scroller(listWidget.viewport());QScrollerProperties properties = scroller->scrollerProperties();// 调整减速度因子(0~1,值越小惯性越长)properties.setScrollMetric(QScrollerProperties::DecelerationFactor, 0.05);// 设置最小拖动触发距离(防止误触)properties.setScrollMetric(QScrollerProperties::DragStartDistance, 0.001);scroller->setScrollerProperties(properties);return app.exec();
}
示例二:
// inertialscroller.h
#ifndef INERTIALSCROLLER_H
#define INERTIALSCROLLER_H#include <QAbstractItemView>
#include <QEvent>
#include <QMouseEvent>
#include <QObject>
#include <QPointF>
#include <QScrollBar>
#include <QTableView>
#include <QTime>
#include <QTimer>
#include <QWheelEvent>/*** @brief 惯性滚动管理器类** 为QTableView或其他QAbstractItemView子类提供惯性滚动功能。* 追踪鼠标拖拽事件并在释放后应用速度衰减算法模拟惯性滚动效果。*/
class InertialScroller : public QObject
{Q_OBJECTpublic:/*** @brief 构造函数* @param view 需要添加惯性滚动功能的视图* @param parent 父对象*/explicit InertialScroller(QAbstractItemView *view, QObject *parent = nullptr);/*** @brief 析构函数*/~InertialScroller();/*** @brief 设置衰减系数,控制惯性滚动的衰减速度* @param factor 衰减系数(0.0-1.0),越小衰减越快*/void setDecelerationFactor(qreal factor);/*** @brief 设置惯性滚动的最大初始速度* @param speed 最大速度(像素/秒)*/void setMaxSpeed(qreal speed);/*** @brief 设置停止惯性滚动的最小速度阈值* @param threshold 速度阈值(像素/秒)*/void setStopThreshold(qreal threshold);/*** @brief 设置滚轮惯性滚动的强度系数* @param factor 强度系数,数值越大惯性效果越强*/void setWheelSpeedFactor(qreal factor);/*** @brief 启用或禁用滚轮惯性滚动* @param enable 是否启用*/void setWheelInertiaEnabled(bool enable);protected:/*** @brief 事件过滤器* 拦截视图的鼠标事件处理惯性滚动*/bool eventFilter(QObject *watched, QEvent *event) override;private:QAbstractItemView *m_view; // 关联的视图QTimer m_timer; // 惯性滚动计时器QTime m_lastTime; // 上次事件时间QPointF m_lastPos; // 上次鼠标位置QPointF m_velocity; // 当前速度(x和y方向)bool m_isPressed = false; // 鼠标是否按下bool m_isScrolling = false; // 是否正在滚动qreal m_deceleration = 0.95; // 衰减系数(0.0-1.0)qreal m_maxSpeed = 2000.0; // 最大速度(像素/秒)qreal m_stopThreshold = 10.0; // 停止阈值(像素/秒)QVector<QPointF> m_positions; // 最近的鼠标位置记录QVector<qint64> m_timestamps; // 最近的鼠标位置时间戳qreal m_wheelSpeedFactor = 15.0; // 滚轮速度系数bool m_wheelInertiaEnabled = true; // 是否启用滚轮惯性private slots:/*** @brief 执行惯性滚动步骤*/void scrollStep();/*** @brief 开始惯性滚动*/void startScrolling(const QPointF &velocity);/*** @brief 停止惯性滚动*/void stopScrolling();
};#endif // INERTIALSCROLLER_H
// inertialscroller.cpp
#include <QDateTime>
#include <QDebug>
#include <QtMath>#include "inertialscroller.h"InertialScroller::InertialScroller(QAbstractItemView *view, QObject *parent) : QObject(parent), m_view(view)
{// 安装事件过滤器m_view->viewport()->installEventFilter(this);// 初始化计时器m_timer.setInterval(16); // 约60FPSconnect(&m_timer, &QTimer::timeout, this, &InertialScroller::scrollStep);// 初始化历史记录容器m_positions.reserve(10);m_timestamps.reserve(10);
}InertialScroller::~InertialScroller()
{if(m_view && m_view->viewport()){m_view->viewport()->removeEventFilter(this);}m_timer.stop();
}void InertialScroller::setDecelerationFactor(qreal factor)
{// 确保值在有效范围内m_deceleration = qBound(0.1, factor, 0.99);
}void InertialScroller::setMaxSpeed(qreal speed)
{m_maxSpeed = qMax(1.0, speed);
}void InertialScroller::setStopThreshold(qreal threshold)
{m_stopThreshold = qMax(1.0, threshold);
}void InertialScroller::setWheelSpeedFactor(qreal factor)
{m_wheelSpeedFactor = qMax(1.0, factor);
}void InertialScroller::setWheelInertiaEnabled(bool enable)
{m_wheelInertiaEnabled = enable;
}bool InertialScroller::eventFilter(QObject *watched, QEvent *event)
{if(watched != m_view->viewport())return false;switch(event->type()){case QEvent::MouseButtonPress: {QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);if(mouseEvent->button() == Qt::LeftButton){stopScrolling();m_isPressed = true;m_lastPos = mouseEvent->pos();m_lastTime.start();// 清空历史记录m_positions.clear();m_timestamps.clear();// 记录初始位置和时间m_positions.append(mouseEvent->pos());m_timestamps.append(QDateTime::currentMSecsSinceEpoch());}break;}case QEvent::MouseMove: {if(m_isPressed){QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);QPointF currentPos = mouseEvent->pos();// 计算移动距离QPointF delta = m_lastPos - currentPos;// 添加到历史记录m_positions.append(currentPos);m_timestamps.append(QDateTime::currentMSecsSinceEpoch());// 仅保留最近的5个记录点while(m_positions.size() > 5){m_positions.removeFirst();m_timestamps.removeFirst();}// 滚动视图QScrollBar *vScrollBar = m_view->verticalScrollBar();QScrollBar *hScrollBar = m_view->horizontalScrollBar();if(vScrollBar && vScrollBar->isVisible()){vScrollBar->setValue(vScrollBar->value() + delta.y());}if(hScrollBar && hScrollBar->isVisible()){hScrollBar->setValue(hScrollBar->value() + delta.x());}m_lastPos = currentPos;}break;}case QEvent::MouseButtonRelease: {if(m_isPressed){QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);if(mouseEvent->button() == Qt::LeftButton){m_isPressed = false;// 如果有足够的历史数据来计算速度if(m_positions.size() >= 2){// 使用最后几个点的平均速度QPointF totalVelocity(0, 0);int count = 0;for(int i = 1; i < m_positions.size(); ++i){qint64 timeDelta = m_timestamps[i] - m_timestamps[i - 1];if(timeDelta > 0){QPointF posDelta = m_positions[i - 1] - m_positions[i];// 速度 = 距离/时间,单位为像素/秒QPointF velocity = posDelta * (1000.0 / timeDelta);totalVelocity += velocity;count++;}}if(count > 0){QPointF avgVelocity = totalVelocity / count;// 限制最大速度qreal speedX = qBound(-m_maxSpeed, avgVelocity.x(), m_maxSpeed);qreal speedY = qBound(-m_maxSpeed, avgVelocity.y(), m_maxSpeed);// 如果速度足够大,启动惯性滚动QPointF finalVelocity(speedX, speedY);qreal speed = qSqrt(speedX * speedX + speedY * speedY);if(speed > m_stopThreshold){startScrolling(finalVelocity);}}}}}break;}case QEvent::Wheel: {// 如果滚轮惯性被禁用,不拦截事件if(!m_wheelInertiaEnabled){stopScrolling();return false;}// 处理鼠标滚轮事件产生惯性滚动QWheelEvent *wheelEvent = static_cast<QWheelEvent *>(event);// 停止当前的惯性滚动stopScrolling();// 计算滚轮滚动的速度和方向QPoint pixelDelta = wheelEvent->pixelDelta();QPoint angleDelta = wheelEvent->angleDelta();// 优先使用像素增量,如果没有则使用角度增量QPointF scrollAmount;if(!pixelDelta.isNull()){scrollAmount = QPointF(pixelDelta);} else if(!angleDelta.isNull()){// 标准鼠标滚轮:角度转为像素(大约8度为一个标准滚动单位)scrollAmount = QPointF(angleDelta) / 8.0;}// 应用滚动方向(正数向下/右,负数向上/左)scrollAmount = -scrollAmount;// 缩放滚动量来创建合适的惯性效果QPointF velocity = scrollAmount * m_wheelSpeedFactor;// 如果速度足够大,开始惯性滚动qreal speed = qSqrt(velocity.x() * velocity.x() + velocity.y() * velocity.y());if(speed > m_stopThreshold){startScrolling(velocity);// 先手动执行一次滚动,让响应更快QScrollBar *vScrollBar = m_view->verticalScrollBar();QScrollBar *hScrollBar = m_view->horizontalScrollBar();if(vScrollBar && vScrollBar->isVisible() && !angleDelta.isNull()){vScrollBar->setValue(vScrollBar->value() + angleDelta.y() / 120 * vScrollBar->singleStep());}if(hScrollBar && hScrollBar->isVisible() && !angleDelta.isNull()){hScrollBar->setValue(hScrollBar->value() + angleDelta.x() / 120 * hScrollBar->singleStep());}return true; // 拦截滚轮事件,自己处理}break;}default:break;}// 继续传递事件,不拦截return false;
}void InertialScroller::scrollStep()
{if(!m_isScrolling || m_isPressed)return;// 减速m_velocity *= m_deceleration;// 计算滚动距离qreal dx = m_velocity.x() * (m_timer.interval() / 1000.0);qreal dy = m_velocity.y() * (m_timer.interval() / 1000.0);// 应用滚动QScrollBar *vScrollBar = m_view->verticalScrollBar();QScrollBar *hScrollBar = m_view->horizontalScrollBar();if(vScrollBar && vScrollBar->isVisible()){vScrollBar->setValue(vScrollBar->value() + qRound(dy));}if(hScrollBar && hScrollBar->isVisible()){hScrollBar->setValue(hScrollBar->value() + qRound(dx));}// 如果速度足够小,停止滚动qreal speed = qSqrt(m_velocity.x() * m_velocity.x() + m_velocity.y() * m_velocity.y());if(speed < m_stopThreshold){stopScrolling();}
}void InertialScroller::startScrolling(const QPointF &velocity)
{if(m_isScrolling)return;m_velocity = velocity;m_isScrolling = true;m_timer.start();
}void InertialScroller::stopScrolling()
{if(!m_isScrolling)return;m_timer.stop();m_isScrolling = false;m_velocity = QPointF(0, 0);
}
相关文章:
qt浏览文件支持惯性
#include <QApplication> #include <QListWidget> #include <QScroller> #include <QScrollerProperties>int main(int argc, char *argv[]) {QApplication app(argc, argv);// 创建列表控件并添加示例项QListWidget listWidget;for (int i 0; i <…...
Python类的力量:第六篇:设计模式——Python面向对象编程的“架构蓝图”
文章目录 前言:从“代码堆砌”到“模式复用”的思维跃迁 一、创建型模式:对象创建的“智能工厂”1. 单例模式(Singleton):全局唯一的“资源管家”2. 工厂模式(Factory):对象创建的“…...

[实战]用户系统-2-完善登录和校验以及VIP
这里写目录标题 完善登录和校验新建lib-auth创建配置引入配置和JWT完善登录基本登录单点登录多点登录校验和拦截编写守卫编写装饰器使用完善VIP修改mysql模型编写vip守卫代码进度完善登录和校验 之前我们模拟过用户的登录,本节将实现token的生成,校验,redis做黑名单。我们需…...
负载均衡笔记
并发数—同时服务的调用方的数量 吞吐量—单位时间内,能接受和返回的数据请求量 TPS。 Transaction事务 QPS。Query 请求/查询 优化点: 减少并发数—防止并非过高 低级—限流—可用的用户少了?! 多开几个口—分流 DNS 解析域…...

印度语言指令驱动的无人机导航!UAV-VLN:端到端视觉语言导航助力无人机自主飞行
作者:Pranav Saxena, Nishant Raghuvanshi and Neena Goveas单位:比尔拉理工学院(戈瓦校区)论文标题:UAV-VLN: End-to-End Vision Language guided Navigation for UAVs论文链接:https://arxiv.org/pdf/250…...

mysql都有哪些锁?
MySQL中的锁机制是确保数据库并发操作正确性和一致性的重要组成部分,根据锁的粒度、用途和特性,可以分为多种类型。以下是MySQL中常见的锁及其详细说明: 一、按锁的粒度划分 行级锁(Row-level Locks) 描述:…...
解锁未来AI:使用DACA模式和Agentic技术提高开发效率
学习Agentic AI:Dapr Agentic Cloud Ascent (DACA)设计模式的应用与演进 背景介绍 近年来,Agentic AI(代理型人工智能)的概念在学术界和产业界掀起了一阵热潮。Agentic AI指的是能够自主感知、决策和行动的智能体系统,它们不仅改变了我们与技术互动的方式,也为行业发展…...

HarmonyOS NEXT 使用 relationalStore 实现数据库操作
大家好,我是V哥。在 HarmonyOS NEXT 开发中,如何操作数据库,V 哥在测试中总结了以下学习代码,分享给你,如何想要系统学习鸿蒙开发,可以了解一下 V 哥最近刚刚上架出版的 《HarmonyOS 鸿蒙开发之路 卷2 从入…...

R语言学习--Day04--数据分析技巧
在清洗完数据,在对数据分析前,我们要懂得先梳理一下我们的逻辑,即数据是什么形式的,要进行哪种分析,有可能呈现什么特点,进而再想怎么处理数据去画图可以最大程度地凸显我们要的特点。 一般来讲࿰…...

SRS流媒体服务器之RTC播放环境搭建
环境概述 srs版本 commit 44f0c36b61bc7c3a1d51cb60be0ec184c840f09d Author: winlin <winlinvip.126.com> Date: Wed Aug 2 10:34:41 2023 0800Release v4.0-r5, 4.0 release5, v4.0.271, 145574 lines. rtc.conf # WebRTC streaming config for SRS. # see full.…...

Android 性能优化入门(三)—— ANR 问题分析
需要清楚 ANR 的概念、类型、如何产生以及如何定位分析。 1、概述 1.1 ANR 的概念 ANR(Application Not Responding)应用程序无响应。如果你应用程序在主线程被阻塞太长时间,就会出现 ANR,通常出现 ANR,系统会弹出一…...
用HTML5实现实时ASCII艺术摄像头
用HTML5实现实时ASCII艺术摄像头 项目简介 这是一个将摄像头画面实时转换为ASCII字符艺术的Web应用,基于HTML5和原生JavaScript实现。通过本项目可以学习到: 浏览器摄像头API的使用Canvas图像处理技术实时视频流处理复杂DOM操作性能优化技巧 功能亮点…...

鸿蒙Flutter实战:22-混合开发详解-2-Har包模式引入
以 Har 包的方式加载到 HarmonyOS 工程 创建工作 创建一个根目录 mkdir ohos_flutter_module_demo这个目录用于存放 flutter 项目和鸿蒙项目。 创建 Flutter 模块 首先创建一个 Flutter 模块,我们选择与 ohos_app 项目同级目录 flutter create --templatemodu…...

游戏引擎学习第302天:使用精灵边界进行排序
在 game_render_group.cpp 中:正确计算 GetBoundFor() 里的 SpriteBound 值 我们正在进行游戏的排序问题调试。虽然这是一个二维游戏,但包含一些三维元素,因此排序变得比较复杂和棘手。混合二维和三维元素时,需要依赖一些比较主观…...

SpringBoot+MyBatis
切换数据库连接词 引入数据库连接词的依赖,配置数据库连接池的类型; 编写测试类: package org.example.threelayerdecouplingdomeapplication2;import org.example.threelayerdecouplingdomeapplication2.mapper.UserMapper; import org.ex…...

wireshark: Display Filter Reference
https://www.wireshark.org/docs/dfref/// 这个里面的扩展功能还是很强大,可以帮着问题分析。支持大量的自定义化的字段读取功能,支持很多的协议。 https://www.wireshark.org/docs/dfref///f/frame.html frame.time_delta Time delta from previous ca…...

Java基础 Day19
一、泛型(JDK5引入) 1、基本概念 在编译阶段约束操作的数据类型,并进行检查 好处:统一数据类型,将运行期的错误提升到了编译期 泛型的默认类型是 Object 2、泛型类 在创建类的时候写上泛型 在创建具体对象的时候…...

VMware+Windows 11 跳过安装阶段微软账号登录
OOBE 阶段 来到这里 断开网络适配器 VMware右下角,点击网络适配器,断开连接 同时按下 Shift 和 F10 ,打开命令提示符(cmd.exe) 输入 oobe\BypassNRO.cmd 并回车 接下来正常进行即可...

HarmonyOS开发-应用间跳转
1. HarmonyOS开发-应用间跳转 在鸿蒙中,我们再开发过程当中或多或少都会遇见想要从一个App的页面跳转至另一个App的页面,这个时候我们要怎么进行跳转呢,其实在HarmonyOS开发者文档中只需要用到Want对象和startAbility()方法进行跳转就可以了。 1.1. 实现 (1)我们要先准备两个…...
网工每日一练
2025/5/22.每日一练(单选题) 路由器在查找路由表时存在最长匹配原则,这里的长度指的是以下哪个参数? A. NextHopIP地址的大小 B. 路由协议的优先级 C. Cost D. 掩码的长度 路由器在查找路由表时遵循的最长匹配原则中,“…...
使用 Navicat 17 for PostgreSQL 时,请问哪个版本支持 PostgreSQL 的 20150623 版本?还是每个版本都支持?
🧑💻 PostgreSQL 用户 使用 Navicat 17 for PostgreSQL 时,请问哪个版本支持 PostgreSQL 的 20150623 版本?还是每个版本都支持? 🧑🔧 官方技术中心 Navicat Premium 17 和 Navicat for P…...

校园二手交易系统
该交易平台分为两部分,前台和后台。用户在前台进行商品选购以及交易;管理员登录后台可以对商品进行维护,主要功能包含: 后台系统的主要功能模块如下: 登录功能、注册功能、后台首页 系统设置: 菜单管理、…...

基于pycharm,python,flask,sklearn,orm,mysql,在线深度学习sql语句检测系统
详细视频:【基于pycharm,python,flask,sklearn,orm,mysql,在线深度学习sql语句检测系统-哔哩哔哩】 https://b23.tv/JLQDwNn...
LangChain02-Agent与Memory模块
Agent与Memory模块深度解析 1. Agent模块原理 1.1 ReAct框架的实现机制 Agent是LangChain中最具智能化的组件,其核心思想基于 ReAct框架(Reasoning Acting),即通过 思维(Thought) 和 行动(Ac…...

upload-labs通关笔记-第17关文件上传之二次渲染gif格式
系列目录 upload-labs通关笔记-第1关 文件上传之前端绕过(3种渗透方法) upload-labs通关笔记-第2关 文件上传之MIME绕过-CSDN博客 upload-labs通关笔记-第3关 文件上传之黑名单绕过-CSDN博客 upload-labs通关笔记-第4关 文件上传之.htacess绕过-CSDN…...
计算机网络学习20250525
应用层协议原理 创建一个网络应用,编写应用程序,这些应用程序运行在不同的端系统上,通过网络彼此通信 不需要在网络核心设备(路由器,交换机)上写应用程序网络应用程序工作在网络层以下将应用程序限制在端系统上促进应用程序迅速研发和部署,将复杂问题放到网络边缘网络应…...

STM32中的SPI通信协议
IIC和SPI的对比 IIC是半双工的通信,无法同时收发信息;SPI是全双工通讯,可以同时收发信息;IIC的通讯协议较复杂,而SPI通讯协议较简单;IIC需要通过地址选择从机,而SPI只主要一个引脚即可选中从机…...

从版本控制到协同开发:深度解析 Git、SVN 及现代工具链
前言:在当今软件开发的浪潮中,版本控制与协同开发无疑扮演着举足轻重的角色。从最初的单兵作战到如今大规模团队的高效协作,一套成熟且得力的版本控制系统以及围绕其构建的现代工具链,已然成为推动软件项目稳步前行的关键引擎。今…...
redis Pub/Sub 简介 -16 (PUBLISH、SUBSCRIBE、PSUBSCRIBE)
Redis Pub/Sub 简介:PUBLISH、SUBSCRIBE、PSUBSCRIBE Redis Pub/Sub 是一种强大的消息传递范例,可在应用程序的不同部分之间实现实时通信。它是构建可扩展和响应式系统的基石,允许组件在没有直接依赖的情况下进行交互。本章将全面介绍 Redis…...

《黄帝内经》数学建模与形式化表征方式的重构
黄帝内经的数学概括:《黄帝内经》数学建模与形式化表征方式的重构 摘要:《黄帝内经》通过现代数学理论如动力系统、代数拓扑和随机过程,被重构为一个形式化的人体健康模型。该模型包括阴阳动力学的微分几何、五行代数的李群结构、经络拓扑与同…...