同QMainWindow内使用QWebEngineView导致QPropertyAnimation动画卡顿问题咨询
QWebEngineView与同窗口QPropertyAnimation卡顿问题解决方案
问题复现背景
当QWebEngineView与QPropertyAnimation处于同一个QMainWindow中时,QPropertyAnimation的流畅度会受到严重影响,即便销毁QWebEngineView,卡顿问题仍然存在。
具体场景为创建15个驱动QGraphicsRectItem动效的QPropertyAnimation,同时使用QWebEngineView时,动画运行严重迟缓。
测试结论
单QMainWindow场景
创建QWebEngineView后销毁,卡顿仍然存在;将QPropertyAnimation替换为QTimer实现动画,问题无改善。
双QMainWindow场景
QWebEngineView嵌入独立QMainWindow时动画恢复流畅,确认仅当二者处于同一个窗口实例时才会出现资源抢占问题。
问题解答
1. QWebEngineView销毁方式是否正确
你的销毁逻辑整体符合Qt规范,卡顿问题并非销毁逻辑导致,仅存在两处可优化细节:
- 销毁前建议先调用
mLayoutForBrowse->removeWidget(mWebEngineView)将控件从布局中移除,避免布局持有引用导致销毁延迟 - 该卡顿为Qt5.15在Windows、Mac平台的已知Bug:QWebEngine对应的后台渲染进程
QtWebEngineProcess不会随前端View销毁立刻释放主窗口的OpenGL渲染上下文持有权,导致主窗口渲染调度优先级被拉低,因此即便View销毁后卡顿仍会存在
2. 是否可以隔离QWebEngineView与主窗口的运行线程
Qt所有UI类(包括QWebEngineView)必须运行在主线程,无法直接移动到子线程执行。但可以通过配置让QWebEngineView使用独立的渲染上下文,避免抢占主窗口资源:
给QWebEngineView所在的父容器设置setAttribute(Qt::WA_NativeWindow),让其使用独立原生窗口渲染,不和主窗口共享OpenGL上下文,效果等同于开独立QMainWindow,但视觉上仍处于当前窗口内。
3. 可落地的解决方法
- 降低WebEngine资源占用:初始化时调用
QWebEngineSettings::globalSettings()->setAttribute(QWebEngineSettings::Accelerated2dCanvasEnabled, false),或在应用启动参数中添加--disable-gpu-compositing,关闭WebEngine的硬件加速2D画布,大幅降低其对OpenGL资源的占用 - 优化动画逻辑:你当前
setPourcent方法中每次新建QPropertyAnimation没有设置销毁策略,会产生大量临时对象,建议修改为animation->start(QAbstractAnimation::DeleteWhenStopped)自动销毁动画对象;同时可将15个动画加入同一个QParallelAnimationGroup统一调度,减少主线程事件循环的调度开销 - 升级Qt版本:该Bug在Qt6.2及以上版本已被官方修复,升级后可直接解决问题
- 兼容低版本适配方案:如果无法升级Qt,可在需要显示WebEngine时动态创建独立原生子窗口,固定在主窗口指定位置,销毁时同时关闭子窗口,完全隔离渲染资源
对应复现代码优化示例
动画逻辑优化
void AnimationBar::setPourcent(qreal pourc){ QPropertyAnimation *animation = new QPropertyAnimation(bar, "rect", this); // 绑定父对象 animation->setDuration(200); animation->setStartValue(QRect(0, 0, 0, mH)); animation->setEndValue(QRect(0, 0, ww,mH)); animation->start(QAbstractAnimation::DeleteWhenStopped); // 运行结束自动销毁 }
WebEngine渲染上下文隔离配置
mWebEngineView = new QWebEngineView(); mWebEngineView->setAttribute(Qt::WA_NativeWindow, true); // 启用独立原生窗口 mWebEnginePage = new QWebEnginePage(mWebEngineView); mWebEnginePage->setView(mWebEngineView); mWebEngineView->setUrl(QUrl("http://www.google.com"));
内容的提问来源于stack exchange,提问作者Maignan Arnaud
相关产品推荐
相关产品推荐

