当前位置: 首页 > news >正文

Qt在Linux嵌入式开发过程中复杂界面滑动时卡顿掉帧问题分析及解决方案

Qt在Linux嵌入式设备开发过程中,由于配置较低,加上没有GPU,我们有时候会遇到有些组件比较多的复杂界面,在滑动时会出现掉帧或卡顿的问题。要讲明白这个问题还得从CPU和GPU的分工说起。

一、硬件层面核心问题根源剖析

  • CPU:CPU主要是用来处理复杂的逻辑事务的;
  • GPU:GPU有大量核心单元,GPU主要是用来处理并行计算的;

在实际软件的用户界面渲染中,CPU准备数据,提交给GPU处理,GPU来计算并绘制界面图形。这就像快递公司的分拣中心。快递员(CPU)收集包裹,贴上地址,然后交给自动分拣机(GPU)快速处理。这样就比较明白两者的协作流程。那对于一些嵌入式设备都没有GPU的情况时,比如用软渲染,这就像没有自动分拣机,快递员自己分拣,效率低下。所以,没有GPU的嵌入式设备经常会出现复杂界面卡顿,来回刷的话CPU占用燃爆。
再举个例子,CPU就像精通学识的大学教授,GPU就像菜市场卖菜的老板。要他们计算微积分,大学教授肯定信手拈来,而卖菜老板则完全不会;但如果是计算一些简单的加法乘法,那天天算菜钱的菜老板肯定超厉害,而大学教授则由于不够熟练,可能就会出现卡顿。
回到实际设备上,比如我们在刷手机滑动页面时,CPU快速判断你的手指移动方向(交互逻辑),然后告诉GPU:“顶部区域需要产生模糊效果,底部列表要滚动100个像素”。GPU立刻调动上千个小核心,像喷漆一样瞬间完成整个屏幕的重新绘制。

二、软件层面核心问题根源剖析

1. CPU单核渲染架构的局限性

如果设备硬件资源有限,没有GPU,不支持 OpenGL ES可以选择 linuxfb 插件。它不需要 OpenGL ES 支持,对硬件要求较低,能够在一些简单的嵌入式设备上正常工作渲染,那这时候Qt默认采用软件渲染引擎(如linuxfb),所有图形计算(几何变换、像素填充、图层合成)均由CPU串行处理,这就会出现管线阻塞。

// 典型软件渲染模式配置 
qputenv("QT_QPA_PLATFORM", "linuxfb");  // 强制使用帧缓冲 
QApplication::setAttribute(Qt::AA_UseSoftwareOpenGL); // 禁用硬件加速 

影响:在800x480分辨率下,滑动含50个复杂项的QListWidget时:
单次全屏渲染需执行百万次浮点运算,这就导致主线程阻塞时间超过上百毫秒每帧。

2. 阴影效果等一些复杂渲染导致CPU计算暴增

由于没有GPU,所有逻辑计算和界面处理都要靠着CPU来扛,对于QGraphicsDropShadowEffect这种复杂渲染,实时高斯模糊算法复杂度为O(n²),单个20px模糊阴影的CPU消耗是纯色填充的十倍以上。

 // 错误示例:实时阴影计算 QGraphicsDropShadowEffect *shadow = new QGraphicsDropShadowEffect;// 触发高斯模糊计算 ,而且每帧重绘时重复计算shadow->setBlurRadius(20);  widget->setGraphicsEffect(shadow);

内存占用飙升:每个阴影需要独立缓存位图,500个列表项将额外占用30MB内存。

3. 布局计算与样式表解析

嵌套布局重算风暴:复杂控件的QGridLayout或QHBoxLayout会触发级联尺寸计算。

 // 低效布局示例 void createItemWidget() {QWidget *container = new QWidget;QVBoxLayout *mainLayout = new QVBoxLayout;for (int i=0; i<5; i++) { // 多级嵌套 QHBoxLayout *subLayout = new QHBoxLayout;subLayout->addWidget(new QLabel(...));mainLayout->addLayout(subLayout);}container->setLayout(mainLayout); // 触发invalidate()}

样式表性能损耗:动态QSS解析会让样式表性能大量损耗,占用CPU时间。

三、多维度优化策略和解决方案

1. 渲染管线优化(核心突破点)

异步渲染分离:将数据加载与UI渲染解耦

 // 使用QtConcurrent实现后台加载 QFuture<QList<ItemData>> future = QtConcurrent::run([]{QList<ItemData> items;for (int i=0; i<500; i++) {items.append(generateItemData(i));  // 在工作线程生成数据 }return items;});// 主线程批量更新 QFutureWatcher<QList<ItemData>> *watcher = new QFutureWatcher;connect(watcher, &QFutureWatcher::finished, [this]{listWidget->setUpdatesEnabled(false);foreach (const ItemData &data, watcher->result()) {addOptimizedItem(data); // 预先处理好的控件 }listWidget->setUpdatesEnabled(true);});

预渲染与缓存:

 // 阴影贴图预生成 QPixmap shadowCache = QPixmap(":/shadow.png").scaled(40,40); // 绘制时直接复用 void drawItemShadow(QPainter *painter, const QRect &rect) {painter->drawPixmap(rect.adjusted(-10,-10,10,10),  shadowCache);}

2 渲染优化:降低绘制复杂度

阴影效果替代方案:

// 方案1:使用QSS内置阴影(CPU消耗降低70%)
QListView::item {border: 1px solid #ccc;//阴影box-shadow: 2px 2px 5px rgba(0,0,0,0.3);background: qlineargradient(x1:0,y1:0,x2:0,y2:1, stop:0 #ffffff, stop:1 #f0f0f0);
}// 方案2:预渲染阴影使用贴图的方式,让UI直接给你画好带阴影的图 
QPixmap createCachedShadow(int radius) {QPixmap pixmap(radius*2, radius*2);pixmap.fill(Qt::transparent); QPainter painter(&pixmap);painter.setBrush(QColor(0,0,0,80)); painter.setPen(Qt::NoPen); painter.drawEllipse(0,  0, radius*2, radius*2);return pixmap;
}void drawItemShadow(QPainter* painter, const QRect& rect) {static QPixmap shadowCache = createCachedShadow(10);painter->drawPixmap(rect.topLeft()  - QPoint(10,10), shadowCache);
}

3.样式与布局重构

QSS性能优化:

 /* 错误:动态计算渐变 */QListView::item { background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #FFF, stop:1 #DDD);}/* 正确:预定义纯色 */QListView::item { background: #EEE;border: 1px solid #CCC; /* 替代阴影效果 */}

4.控件级深度调优

QListWidget替代方案:

 // 改用QListView + 自定义模型 class ListModel : public QAbstractListModel {Q_OBJECT public:int rowCount(const QModelIndex&) const override { return m_data.count();  }QVariant data(const QModelIndex &index, int role) const override {if (role == Qt::DecorationRole) return m_data[index.row()].icon;// 其他角色处理...}private:QVector<ItemData> m_data;};// 启用视图优化 listView->setViewMode(QListView::IconMode);listView->setUniformItemSizes(true);  // 统一尺寸提升性能 

动态加载可见区域:

 // 仅渲染可视项 void FastListView::paintEvent(QPaintEvent *e) {QModelIndex startIdx = indexAt(rect().topLeft());QModelIndex endIdx = indexAt(rect().bottomRight());for (int i=startIdx.row();  i<=endIdx.row();  ++i) {drawRow(i); // 按需绘制 }}

5.Qt环境调优

关键参数配置:

 qputenv("QT_NO_FT_CACHE", "1");      // 关闭字体缓存 qputenv("QT_MM_POOL_SIZE", "2097152"); // 2MB内存池防碎片 QApplication::setAttribute(Qt::AA_DisableWindowContextHelpButton);

6.内存管理优化

# 配置Qt内存池防止碎片化
export QT_MM_POOL_SIZE=2097152  # 2MB固定内存池
export QT_MM_POOL_COUNT=4       # 4个独立内存分区 

总之,在这几个方面如果处理不好,会显著增加CPU消耗:

  • QGraphicsDropShadowEffect的渲染开销
    在嵌入式设备无GPU的情况下,使用QGraphicsDropShadowEffect实现阴影效果会导致显著的性能问题。该效果完全依赖CPU进行实时模糊计算和像素混合,尤其在复杂界面中多个控件叠加阴影时,会造成渲染管线阻塞。建议改用预生成的阴影贴图替代实时阴影计算,或调整模糊半径至最低可接受值(如1px)。

  • 复杂布局的CPU计算负担
    深度嵌套的布局结构和频繁的样式表更新会加剧CPU负载。Qt样式表解析和布局重新计算在嵌入式场景中会消耗大量时钟周期,特别是在showEvent等关键事件中执行复杂逻辑。应简化布局层级,避免使用私有样式,将样式预处理为QSS文件,并延迟非必要控件的初始化加载。

  • 列表控件的滑动优化
    QListWidget/QTableView在触屏滑动时容易出现帧率骤降,这与其默认的滚动机制和渲染方式有关。建议启用QScroller控制滚动行为,设置overshootPolicy为QSensorScroller::OvershootAlwaysOff关闭物理回弹效果。在控件析构前调用QScroller::ungrabGesture()确保滚动状态机正确释放,防止内存泄漏导致的异常卡顿。

  • 视窗系统选择与渲染模式
    优先选用LinuxFB插件替代EGLFS,通过设置QT_QPA_PLATFORM=linuxfb强制使用帧缓冲模式。调整环境变量QT_MAX_CACHED_GLYPH=100限制字形缓存大小,启用QT_NO_FT_CACHE=1关闭字体缓存优化内存使用。对于表格类控件,建议关闭antialiasing属性并设置Qt::WA_OpaquePaintEvent减少混合计算。

  • 通用性能优化策略
    采用分层渲染技术,将静态界面元素缓存为QPixmap。启用QWidget::setAttribute(Qt::WA_StaticContents)标记静态内容区域,使用QPainter::setRenderHint(QPainter::Antialiasing, false)关闭抗锯齿。对于频繁更新的列表项,实现自定义代理并在paintEvent中使用预渲染位图,避免实时绘制复杂图形元素

相关文章:

Qt在Linux嵌入式开发过程中复杂界面滑动时卡顿掉帧问题分析及解决方案

Qt在Linux嵌入式设备开发过程中&#xff0c;由于配置较低&#xff0c;加上没有GPU&#xff0c;我们有时候会遇到有些组件比较多的复杂界面&#xff0c;在滑动时会出现掉帧或卡顿的问题。要讲明白这个问题还得从CPU和GPU的分工说起。 一、硬件层面核心问题根源剖析 CPU&#x…...

AI学习第六天-python的基础使用-趣味图形

在 Python 编程学习过程中&#xff0c;turtle库是一个非常有趣且实用的工具&#xff0c;它可以帮助我们轻松绘制各种图形。结合for循环、random模块以及自定义方法等知识点&#xff0c;能够创作出丰富多彩的图案。下面就来分享一下相关的学习笔记。 一、基础知识点回顾 &…...

[VMware]卸载VMware虚拟机和Linux系统ubuntu(自记录版)

记录一下,不是教程,只是防止我做错了可以回溯一下 我打开vscode,就会跳出下图 虚拟机,Linux还是很久之前学习安装的,种途可能卸载过(不太记得了),现在尝试彻底卸载 彻底卸载VMware虚拟机的详细步骤-CSDN博客虚拟机Vmware 转移 克隆 卸载及移除Linux系统_克隆的虚拟机怎么移除-…...

J-LangChain,用Java实现LangChain编排!轻松加载PDF、切分文档、向量化存储,再到智能问答

Java如何玩转大模型编排、RAG、Agent&#xff1f;&#xff1f;&#xff1f; 在自然语言处理&#xff08;NLP&#xff09;的浪潮中&#xff0c;LangChain作为一种强大的模型编排框架&#xff0c;已经在Python社区中广受欢迎。然而&#xff0c;对于Java开发者来说&#xff0c;能…...

Cuppa CMS v1.0 任意文件读取(CVE-2022-25401)

漏洞简介&#xff1a; Cuppa CMS v1.0 administrator/templates/default/html/windows/right.php文件存在任意文件读取漏洞 漏洞环境&#xff1a; 春秋云镜中的漏洞靶标&#xff0c;CVE编号为CVE-2022-25401 漏洞复现 弱口令行不通 直接访问administrator/templates/defau…...

可以免费无限次下载PPT的网站

前言 最近发现了一个超实用的网站&#xff0c;想分享给大家。 在学习和工作的过程中&#xff0c;想必做PPT是一件让大家都很头疼的一件事。 想下载一些PPT模板减少做PPT的工作量&#xff0c;但网上大多精美的PPT都是需要付费才能下载使用。 即使免费也有次数限制&#xff0…...

STM32中使用PWM对舵机控制

目录 1、硬件JIE 2、PWM口配置 3、角度转换 4、main函数中应用 5、工程下载连接 1、硬件介绍 单片机&#xff1a;STM32F1 舵机&#xff1a;MG995 2、PWM口配置 20毫秒的PWM脉冲占空比&#xff0c;对舵机控制效果较好 计算的公式&#xff1a; PSC、ARR值的选取&#xf…...

使用插件 `vue2-water-marker`添加全局水印

使用插件 vue2-water-marker添加全局水印 效果图 1、安装插件 npm install vue2-water-marker --save2、全局注册 // main.js import Vue from vue import Vue2WaterMarker from vue2-water-markerVue.use(Vue2WaterMarker)3、在组件中使用 <template><div id&q…...

MySQL表约束的种类与应用

在MySQL数据库中&#xff0c;表约束是确保数据完整性的关键。约束限制了可以在表中插入或更新的数据类型&#xff0c;保证数据的准确性和可靠性。了解MySQL中的各种表约束对于数据库设计和数据维护至关重要。以下是MySQL支持的主要表约束类型及其应用的详细介绍。 1. 主键约束…...

【大模型+知识图谱】大模型与知识图谱融合:技术演进、实践应用与未来挑战

【大模型+知识图谱】大模型与知识图谱融合:技术演进、实践应用与未来挑战 大模型与知识图谱融合:技术演进、实践应用与未来挑战引言:为什么需要融合?一、技术融合的三重路径1.1 知识图谱增强大模型1.2 大模型赋能知识图谱1.3 协同推理框架二、工业级应用场景落地2.1 智能问…...

MS SQL 2008 技术内幕:T-SQL 语言基础

《MS SQL 2008 技术内幕&#xff1a;T-SQL 语言基础》是一部全面介绍 Microsoft SQL Server 2008 中 T-SQL&#xff08;Transact-SQL&#xff09;语言的书籍。T-SQL 是 SQL Server 的扩展版本&#xff0c;增加了编程功能和数据库管理功能&#xff0c;使得开发者和数据库管理员能…...

MySQL-MATCH ... AGAINST工具

在MySQL中&#xff0c;MATCH……AGAINST是全文索引&#xff08;Full-Text index&#xff09;的查询语法&#xff0c;它允许你对文本进行高效的全文搜素&#xff0c;支持自然语言搜索和布尔搜索模式。以下是MATCH……AGAINST的详细用法和示例 一、全文索引的基本概念 全文索引适…...

微服务合并

有的团队为了节约机器成本、有的团队为了提升研发效率、有的团队为了降低人均服务数 微服务合并&#xff0c;可以从多个角度入手 代码重构融合&#xff1a;人工拷贝代码、解决冲突&#xff0c;然后分阶段实施迁移重构。代码合并打包&#xff1a;将多个代码仓库&#xff0c;拉取…...

Shell脚本基础:用Bash自动化任务

Shell脚本基础&#xff1a;用Bash自动化任务 在Linux运维中&#xff0c;手动执行重复性任务既耗时又容易出错&#xff0c;而Shell脚本则为自动化提供了强大支持。 从基础概念到实用案例&#xff0c;逐步掌握用Bash实现自动化的核心技能。Shell脚本是Linux自动化的基石&#xf…...

基于W2605C语音识别合成芯片的智能语音交互闹钟方案-AI对话享受智能生活

随着科技的飞速发展&#xff0c;智能家居产品正逐步渗透到我们的日常生活中&#xff0c;其中智能闹钟作为时间管理的得力助手&#xff0c;也在不断进化。基于W2605C语音识别与语音合成芯片的智能语音交互闹钟&#xff0c;凭借其强大的联网能力、自动校时功能、实时天气获取、以…...

【Java项目】基于Spring Boot的网上商城购物系统

【Java项目】基于Spring Boot的网上商城购物系统 技术简介&#xff1a;采用Java技术、Spring Boot框架、MySQL数据库等实现。 系统简介&#xff1a;系统实现管理员&#xff1a;首页、个人中心、用户管理、商品分类管理、商品信息管理、订单评价管理、系统管理、订单管理&#x…...

开放标准(RFC 7519):JSON Web Token (JWT)

开放标准&#xff1a;JSON Web Token 前言基本使用整合Shiro登录自定义JWT认证过滤器配置Config自定义凭证匹配规则接口验证权限控制禁用session缓存的使用登录退出单用户登录Token刷新双Token方案单Token方案 前言 JSON Web Token &#xff08;JWT&#xff09; 是一种开放标准…...

JBoltAI_SpringBoot如何基于Deepseek官网API区分 R1大模型深度思考和具体回答的内容?

R1大模型推出后&#xff0c;Deepseek官网的API也更新了&#xff0c;我们可以看到 chat 接口的响应数据结果里多了一个reasoning_content 字段 于是我们的JBoltAI SDK 以及 SpringBoot版以及Jfinal版JBoltAI Platform 迅速跟进&#xff0c;提供了对深度思考的支持&#xff1a;…...

YOLOv11-ultralytics-8.3.67部分代码阅读笔记-model.py

model.py ultralytics\models\yolo\model.py 目录 model.py 1.所需的库和模块 2.class YOLO(Model): 3.class YOLOWorld(Model): 1.所需的库和模块 # Ultralytics &#x1f680; AGPL-3.0 License - https://ultralytics.com/licensefrom pathlib import Pathfrom ult…...

MySQL 事务笔记

MySQL 事务笔记 目录 事务简介事务操作事务四大特性并发事务问题事务隔离级别总结 事务简介 事务&#xff08;Transaction&#xff09;是数据库操作的逻辑单元&#xff0c;由一组不可分割的SQL操作组成。主要用于保证&#xff1a; 多个操作的原子性&#xff08;要么全部成功…...

浅谈 React Hooks

React Hooks 是 React 16.8 引入的一组 API&#xff0c;用于在函数组件中使用 state 和其他 React 特性&#xff08;例如生命周期方法、context 等&#xff09;。Hooks 通过简洁的函数接口&#xff0c;解决了状态与 UI 的高度解耦&#xff0c;通过函数式编程范式实现更灵活 Rea…...

应用升级/灾备测试时使用guarantee 闪回点迅速回退

1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间&#xff0c; 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点&#xff0c;不需要开启数据库闪回。…...

<6>-MySQL表的增删查改

目录 一&#xff0c;create&#xff08;创建表&#xff09; 二&#xff0c;retrieve&#xff08;查询表&#xff09; 1&#xff0c;select列 2&#xff0c;where条件 三&#xff0c;update&#xff08;更新表&#xff09; 四&#xff0c;delete&#xff08;删除表&#xf…...

Oracle查询表空间大小

1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...

Frozen-Flask :将 Flask 应用“冻结”为静态文件

Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是&#xff1a;将一个 Flask Web 应用生成成纯静态 HTML 文件&#xff0c;从而可以部署到静态网站托管服务上&#xff0c;如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...

React19源码系列之 事件插件系统

事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序

一、开发环境准备 ​​工具安装​​&#xff1a; 下载安装DevEco Studio 4.0&#xff08;支持HarmonyOS 5&#xff09;配置HarmonyOS SDK 5.0确保Node.js版本≥14 ​​项目初始化​​&#xff1a; ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

《基于Apache Flink的流处理》笔记

思维导图 1-3 章 4-7章 8-11 章 参考资料 源码&#xff1a; https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...

3-11单元格区域边界定位(End属性)学习笔记

返回一个Range 对象&#xff0c;只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意&#xff1a;它移动的位置必须是相连的有内容的单元格…...

React---day11

14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store&#xff1a; 我们在使用异步的时候理应是要使用中间件的&#xff0c;但是configureStore 已经自动集成了 redux-thunk&#xff0c;注意action里面要返回函数 import { configureS…...