发布时间:2026/9/3 19:34:54
Qt QGraphicsView实战:实现流畅的滑动卡片窗体与惯性吸附效果 简介基于Qt的图形视图框架这份压缩包提供了一个可运行的滑动窗体示例工程面向入门级Qt开发者帮助理解场景、视图与图元三者协作构建可视化界面的核心机制。示例将工具栏与图片均作为场景中的图元直观演示了如何在场景中摆放元素并通过视图滚动呈现可用于学习自定义图元、场景管理和视图交互等基础技能。压缩包共25个文件以jpg、svg、png等图片资源为主同时包含qrc资源索引、cpp与pro源码工程以及txt说明文档整体约664KB轻量且结构完整便于直接编译运行并修改扩展。目前已有3306人学习或下载适合想要通过一个小型案例快速上手QGraphicsView滑动窗体效果的开发者。通过该工程可掌握从场景搭建、图元添加到视图显示的基本流程并借助附带的多类图片资源进行替换练习为后续开发更复杂的交互界面打下坚实基础。 做上位机界面的时候经常遇到一个需求用 Qt 的 QGraphicsView 把一个参数卡片面板做成可以左右滑动的窗体效果类似手机端那种手指一划就换页松手自动吸附到最近的卡片。第一次做这个功能我第一反应是用 QStackedWidget 配 QPropertyAnimation结果只有翻页动画滑动过程中间那一段根本看不着跟手感和惯性完全无从谈起后来换成 QScrollArea是能滚了但吸附到某一页、边缘回弹、循环滑动这些逻辑写起来非常别扭性能也一般。最后把方案定在 QGraphicsView 上。这篇把完整思路、代码和踩坑记录都分享出来适合正在做 Qt 界面开发、上位机、组态软件、地图类应用或者只是想把界面做得更细腻的读者参考。1. 为什么选 QGraphicsView 来做滑动窗体1.1 滑动窗体到底在解决什么问题需求本质上就是一组等宽页面按顺序排列视口一次只显示一页用户可以用鼠标、触摸或滚轮拖动让页面跟随手移动松手后要么停在原页要么吸附到相邻页。还可以延伸出惯性手甩得越快飞得越远。从实现角度拆解它由四件事组成多个页面需要独立摆放、独立绘制页面位置要能连续修改中间过程可见拖拽结束后要有平滑动画补位滑动过程要有能撑得起的渲染性能。这样拆开之后选型就清楚了。绝大多数“滑动窗体”实现得别扭不是不会写动画而是容器选错了。1.2 QStackedWidget、QScrollArea 和 QGraphicsView 的取舍方案滑动连续感惯性/吸附实现子控件交互一句话评价QStackedWidget无只有切换动画需要额外叠加贝塞尔插值天然支持只适合简单 fade/slide 换页QScrollArea有连续滚动需要自己维护 ScrollBar 位置吸附逻辑散落在各处支持但状态同步麻烦适合长内容滚动不适合页面卡扣QGraphicsView完全可控直接操作 Item 坐标或 view center吸附就是一次动画需要处理事件转发做滑动效果的上限最高QGraphicsView 在技术上更合适的原因有几个。QGraphicsItem 支持独立命中检测、绘制、父子关系一个页面就是一个 Item更新某一页不需要通知整个界面QGraphicsScene 内部用 BSP 树索引 ItemItem 数量多时也不会让场景遍历变慢QGraphicsView 的 viewport 变换scale/rotate建立在一套统一坐标系上后续想放大、裁剪都顺手QPropertyAnimation 可以直接对坐标属性做插值配合各种缓动曲线惯性、弹簧都只是换个曲线的事。1.3 我最终选型的理由选 QGraphicsView 不只是因为动画更重要的是“后续扩展”。比如想把滑动卡片做成带磁吸效果或者在卡片后面加一层背景装饰或者把整个视口缩小成缩略图导航在 Scene/View 体系下都是加 Item、改映射的事代码不需要推翻重来。如果一开始图省事用 QScrollArea这些需求基本都要重写。我见过不少项目从 QScrollArea 迁移到 QGraphicsView不是因为 QScrollArea 写不出来而是因为每加一个交互需求代码复杂度就失控一次。2. 坐标系统滑动效果背后的数学基础2.1 三套坐标别搞混QGraphicsView 里有三个坐标系场景坐标Scene、视图坐标View、视口坐标Viewport。场景坐标是整个虚拟世界的坐标Item 的位置用 setPos 设置时用的就是它视图坐标是 View 部件内部的坐标视口坐标是实际绘制窗口的坐标通常和视图坐标重合但在有边框、滚动条或 transform 时会存在偏移。滑动窗体的本质是改变视口在场景中的位置。改法有两种一是修改每个 Item 的 pos让所有页面一起动二是保持 Item 不动让 View 的“镜头”移动也就是调用 centerOn()。我更推荐第二种。理由是页面之间有关联结构时只移动一个镜头比移动所有 Item 更省事而且以后加缩放、旋转中心点不会漂移。2.2 QGraphicsItem 的绘制契约每个页面是一个 QGraphicsItem 子类至少要重写两个函数class SlidePageItem : public QGraphicsItem { public: SlidePageItem(qreal w, qreal h) : m_w(w), m_h(h) {} QRectF boundingRect() const override { return QRectF(0, 0, m_w, m_h); } void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override { // 这里画卡片背景、边框、内容等等 } private: qreal m_w 0.0; qreal m_h 0.0; };boundingRect 必须返回 Item 在局部坐标系里的绘制范围这决定了 View 何时认为它需要重绘也影响了点击命中测试。paint 里所有绘制都基于局部坐标不需要关心它在场景里的位置这让 Item 内部的代码非常干净。页面的位置完全由 setPos 控制比如第 i 页就摆到(i * pageWidth, 0)。2.3 一个简单的场景摆放auto *scene new QGraphicsScene(this); const int pageCount 6; const qreal pageW 900.0; const qreal pageH 600.0; for (int i 0; i pageCount; i) { auto *page new SlidePageItem(pageW, pageH); page-setPos(i * pageW, 0); scene-addItem(page); } auto *view new QGraphicsView(scene); view-setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); view-setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);这里有个很多教程不会讲的细节sceneRect 最好前后各留一页宽的空白。默认 sceneRect 如果刚好等于内容大小centerOn 一到边界就顶死了视觉上非常生硬留白后可以做出“拖出边界再弹回”的手感。留白的量可以这样设置scene-setSceneRect(-pageW, -pageH, (pageCount 2) * pageW, pageH * 3);Item 的绘制不会受空白影响因为它只画在局部坐标的 boundingRect 范围内空白区域只是场景的可视范围。3. 核心实现从搭建场景到惯性滚动3.1 事件处理用“镜头移动”模拟手指拖拽我建议在 QGraphicsView 的子类里重写鼠标事件。核心思路按下时把鼠标的 view 坐标通过 mapToScene 转成场景坐标记录为上一次场景坐标移动时用 mapToScene 计算当前场景坐标和上一次场景坐标的差这个差值就是手指相对场景“推”了多少然后利用 centerOn() 改变视口中心。void SlideView::mousePressEvent(QMouseEvent *event) { m_lastScenePos mapToScene(event-pos()); m_dragging true; m_frames.clear(); stopAnimation(); QGraphicsView::mousePressEvent(event); } void SlideView::mouseMoveEvent(QMouseEvent *event) { if (!m_dragging) { QGraphicsView::mouseMoveEvent(event); return; } const QPointF scenePos mapToScene(event-pos()); const qreal dx scenePos.x() - m_lastScenePos.x(); // 手指向右拖说明想看左边内容镜头中心要左移 m_centerX - dx; centerOn(m_centerX, 0); m_lastScenePos scenePos; m_frames.append(qMakePair(scenePos.x(), QDateTime::currentMSecsSinceEpoch())); if (m_frames.size() 5) m_frames.removeFirst(); QGraphicsView::mouseMoveEvent(event); }注意最后调用基类是为了让默认行为继续处理其它必要逻辑。但如果页面内部还有可点击控件这个调用时机和事件传递需要额外处理后面坑章节会展开。3.2 惯性让滑动有“甩出去”的感觉惯性不能靠硬编码的固定动画需要先估算松手瞬间速度。我用最近几帧的位移和时间差来算qreal SlideView::estimateVelocity() const { if (m_frames.size() 2) return 0; const auto last m_frames.last(); const auto first m_frames.first(); qint64 dtMs last.second - first.second; if (dtMs 0) return 0; return (last.first - first.first) * 1000.0 / dtMs; }返回值单位是“场景坐标每秒”。在 mouseReleaseEvent 中用速度预测落点再启动一个 QPropertyAnimation 飞过去void SlideView::mouseReleaseEvent(QMouseEvent *event) { m_dragging false; const qreal v estimateVelocity(); const qreal predicted m_centerX - v * 0.2; const int target clampedIndex(predicted); animateToIndex(target); QGraphicsView::mouseReleaseEvent(event); } void SlideView::animateToIndex(int index) { stopAnimation(); const qreal targetX index * m_pageWidth; auto *anim new QPropertyAnimation(this, centerX); anim-setStartValue(m_centerX); anim-setEndValue(targetX); anim-setDuration(350); anim-setEasingCur p a hrefhttps://download.csdn.net/download/huihui1988/2808505 stylecolor:#ec7500;font-size:14px; 本文还有配套的精品资源点击获取 /a img altmenu-r.4af5f7ec.gif srchttps://csdnimg.cn/release/wenkucmsfe/public/img/menu-r.4af5f7ec.gif stylewidth:16px;margin-left:4px;vertical-align:text-bottom;cursor:text; /p

相关新闻

2026/9/3 19:34:54

基于IAPWS-IF97的MATLAB水蒸气物性计算实现与工程应用

简介:面向热能、化工及电力领域工程师和科研人员的MATLAB版IAPWS-IF97计算工具包,将国际公认的水与蒸汽热力学性质标准转化为可直接调用的函数。包内完整覆盖饱和蒸气压力、密度、焓、熵等关键参数求解,适用压力温度范围从低压蒸汽延伸到超临…

2026/9/3 19:34:54

重复文本清洗全攻略:从Python脚本到Linux命令的实践指南

在采集用户留言、论坛帖子或接口返回文本时,我见过不少类似这样的样本: 你是凑企鹅你是凑企鹅你是凑企鹅 。第一次看像乱码,复制到编辑器里搜索,才发现是同一句话被连续拼了三次。它不是人写的正常表达,也不是普通口…

2026/9/3 19:34:54

基于ThinkPHP构建企业级OA系统:架构设计与核心模块实现

简介:这是一套基于ThinkPHP框架开发的企业级开源OA办公系统源码,面向PHP中级开发者、企业IT运维人员及数字化转型中的中小企业,旨在提供可二次开发、低成本落地的协同办公解决方案。资源包共1887个文件,涵盖640个PHP核心逻辑文件、…

2026/9/3 20:30:04

ESP32机甲机器人DIY:从硬件选型到代码实现全攻略

你是不是也有过这样的想法:给手办模型或者小车上装一颗“会思考的大脑”,让它能自动避开障碍、在屏幕里做出各种表情,还能听懂你从手机发来的指令?很多人觉得做 AI 机器人门槛很高,又要会 Linux,又要调神经…

2026/9/3 20:30:04

国家电网与南方电网科技项目投标、中标及履约实施全生命周期管理

国家电网与南方电网科技项目投标、中标及履约实施全生命周期管理 本文面向参与国家电网、南方电网科技研发、技术服务、软硬件开发及示范应用类项目的高校、科研院所、科技企业和联合项目团队,系统梳理从机会识别、投标策划、标书编制、中标确认,到合同履…

2026/9/3 20:30:04

UVM 约束块 Constraint:随机不是乱来,让激励符合协议规则

随机化不是“乱随机”,约束让它有章法 UVM 验证的核心是受约束的随机激励。如果让所有字段完全自由随机,那么绝大多数事务都是非法的:地址没有对齐、长度超出范围、数据大小与长度不匹配……这些无效激励不仅浪费仿真时间,还可能掩…

2026/9/3 20:30:04

java interrupt Java线程的interrupt,不是想停就能停,小心被它玩

您瞧那家面试的人, Java线程这一生命历程所对应的, 主要是.State里头的六种状况, 分别是NEW, 还有, 还有, 再有, 再有, 再有, 最后一个仍是。是新建状态的 NEW, 意思是线程对象已然被创建了, 然而却尚未调用 start() , 举例来说, new ) 之后呈现的便是此状态。在对start()进行调…

2026/9/3 20:30:04

SSM 框架本科毕业设计选题

技术栈:SpringSpringMVCMyBatisMySQLJSP/Thymeleaf,分为通用管理系统、电商交易平台、校园管理系统、预约报修与物业服务、资讯博客展示平台、行业特色业务系统六大类,难度梯度适中,包含 RBAC 权限管理、文件上传、图表统计、订单…

2026/9/3 18:28:26

vSound小提琴数字处理器实操指南:从接线到演出的完整配置

电小提琴或者原声小提琴插电演出,第一个绕不开的坎就是声音难听。原声琴的共鸣和空气感一旦进了拾音器,出来的往往是一坨干瘪、发尖、带着奇怪塑料味的信号。我当初第一次把琴接上乐队调音台,直接被主唱吐槽"你这声音像在锯钢丝"。…

2026/9/3 14:29:47

传感器接口IC如何攻克生物化学传感的微弱信号难题?

1. 从电极到比特流:为什么生物化学传感必须依赖专用接口IC 做生物化学传感的人都有过类似的经历:明明传感器本身性能很好,信号输出却一塌糊涂——噪声大、漂移明显、重复性差,怎么调都达不到预期。很多时候问题并不在传感器&#…

2026/9/3 14:30:35

STM32F411CEU6多通道ADC采集:扫描模式+DMA实现详解

1. 多通道 ADC 的用武之地把“Multichannel ADC”和“STM32F411CEU6”这两个关键字放在一起,其实就是嵌入式开发里最常遇到的一类需求:用一块不算贵的 MCU,同时采集多路模拟信号。STM32F411CEU6 是 48 引脚的 Cortex-M4F 主控,主频…

2026/9/3 0:02:06

零基础装 OpenClaw 小龙虾 AI:Windows 一键部署教程与避坑要点

Windows 部署 OpenClaw 完整教程|本地 AI 智能体 5 分钟落地,环境配置一次搞定 版本说明:Windows 3.1.0 / Mac 2.7.9 写在前面 近两年开源 AI 领域有一款被称作「数字员工」的工具持续走热,它就是 OpenClaw,圈内人更习…

2026/9/3 0:02:06

Hermes Agent 本地部署新方案:Windows 整合包减少依赖报错

Windows 本地部署 Hermes 太麻烦?这版一键包 5 分钟快速跑通 很多人想体验 Hermes Agent,但真正开始部署时,往往会卡在环境配置这一步。 需要安装各类依赖、调试运行环境、处理路径问题,还容易遇到命令行报错、系统拦截、文件缺…

2026/9/3 0:02:06

实测 OpenClaw 一键包,5 分钟完成本地自动化环境搭建

OpenClaw 本地 AI 自动化工具部署指南|使用一键包规避环境配置难题 痛点:部署 AI 自动化工具常常要处理 Python、Node.js 各类依赖,版本冲突、环境配置耗费大量时间,OpenClaw 提供一键安装包,降低部署门槛。 适配系统&…

2026/9/2 1:15:22

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/3 17:51:43

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/2 1:15:20

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…