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

qt 双缓冲案例对比

双缓冲

1.双缓冲原理

单缓冲:在paintEvent中直接绘制到屏幕,绘制过程被用户看到
双缓冲:先在redrawBuffer绘制到缓冲区,然后一次性显示完整结果
代码结构
单缓冲:所有绘制逻辑在paintEvent中
双缓冲:绘制逻辑分离到redrawBuffer,paintEvent仅负责显示缓冲区
性能影响
单缓冲:每次更新需要重复计算和绘制
双缓冲:可以优化为只在必要时重绘缓冲区(如数据变化时)

减少的时间是重绘的那部分时间,单缓冲是逐个绘制,双缓冲是整体绘制。

测试案例

1.Qt 实现绘制 5000 个小球移动,单缓冲和双缓冲效果对比

双缓冲和单缓冲效果对比

2.代码

关键代码对比:
单缓冲绘制: paintEvent 中通过 painter 绘制每一个 circle,一次 paintEvent 绘制 5000 次
双缓冲绘制: paintEvent 中直接绘制提前赋好像素值的成员变量 buffer 中的像素

doublebufferwidget.h

#include <QWidget>
#include <QPainter>
#include <QTimer>
#include <QPixmap>
#include <QPointF>
#include <QVector>
#include <cmath>
#include <QTime>
#include <QDebug>class DoubleBufferWidget : public QWidget {Q_OBJECT
public:DoubleBufferWidget(QWidget *parent = nullptr) : QWidget(parent) {// 初始化缓冲区setWindowTitle("DoubleBuffer");buffer = QPixmap(size());buffer.fill(Qt::white);// 初始化动画数据for (int i = 0; i < 5000; ++i) {circles.append({QPointF(rand() % width(), rand() % height()),5.f + rand() % 10,QColor(rand() % 256, rand() % 256, rand() % 256),QPointF((rand() % 100 - 50) / 100.0, (rand() % 100 - 50) / 100.0)});}// 设置定时器更新动画QTimer *timer = new QTimer(this);connect(timer, &QTimer::timeout, this, &DoubleBufferWidget::updateAnimation);timer->start(16);}void resizeEvent(QResizeEvent *event) override {buffer = QPixmap(size());buffer.fill(Qt::white);QWidget::resizeEvent(event);}void paintEvent(QPaintEvent *event) override {QTime doublePaint;doublePaint.start();Q_UNUSED(event);QPainter painter(this);painter.drawPixmap(0, 0, buffer);qInfo() << "void paintEvent(QPaintEvent *event) doublePaint cost times:" << doublePaint.elapsed() << "ms";}private slots:void updateAnimation() {// 更新所有圆形位置for (auto &circle : circles) {circle.pos += circle.velocity;if (circle.pos.x() - circle.radius < 0 || circle.pos.x() + circle.radius > width())circle.velocity.setX(-circle.velocity.x());if (circle.pos.y() - circle.radius < 0 || circle.pos.y() + circle.radius > height())circle.velocity.setY(-circle.velocity.y());}// 重新绘制到缓冲区redrawBuffer();update();}private:struct Circle {QPointF pos;qreal radius;QColor color;QPointF velocity;};QPixmap buffer;QVector<Circle> circles;void redrawBuffer() {buffer.fill(Qt::white);QPainter bufferPainter(&buffer);bufferPainter.setRenderHint(QPainter::Antialiasing);// 模拟长时间绘制过程for (int i = 0; i < 1000; ++i) {double temp = std::sin(i);Q_UNUSED(temp);}// 绘制所有圆形for (const auto &circle : circles) {bufferPainter.setPen(Qt::NoPen);bufferPainter.setBrush(circle.color);bufferPainter.drawEllipse(circle.pos, circle.radius, circle.radius);}}
};

singlebufferwidget.h

#include <QWidget>
#include <QTime>
#include <QPainter>
#include <QTimer>
#include <math.h>
#include <qmath.h>
#include <QDebug>QT_BEGIN_NAMESPACE
namespace Ui { class SingleBufferWidget; }
QT_END_NAMESPACEclass SingleBufferWidget : public QWidget {Q_OBJECT
public:SingleBufferWidget(QWidget *parent = nullptr) : QWidget(parent) {// 初始化动画数据for (int i = 0; i < 5000; ++i) {circles.append({QPointF(rand() % width(), rand() % height()),5.f + rand() % 10,QColor(rand() % 256, rand() % 256, rand() % 256),QPointF((rand() % 100 - 50) / 100.0, (rand() % 100 - 50) / 100.0)});}// 设置定时器更新动画QTimer *timer = new QTimer(this);connect(timer, &QTimer::timeout, this, &SingleBufferWidget::updateAnimation);timer->start(16);}void paintEvent(QPaintEvent *event) override {QTime SingpaintTimer;SingpaintTimer.start();Q_UNUSED(event);QPainter painter(this);painter.setRenderHint(QPainter::Antialiasing);// 模拟长时间绘制过程for (int i = 0; i < 1000; ++i) {// 这个循环会延长绘制时间,加剧闪烁现象double temp = std::sin(i);Q_UNUSED(temp);}// 绘制所有圆形for (const auto &circle : circles) {painter.setPen(Qt::NoPen);painter.setBrush(circle.color);painter.drawEllipse(circle.pos, circle.radius, circle.radius);}qInfo() << "void paintEvent(QPaintEvent *event) SingpaintTimer cost times:" << SingpaintTimer.elapsed() << "ms";}private slots:void updateAnimation() {// 更新所有圆形位置for (auto &circle : circles) {circle.pos += circle.velocity;if (circle.pos.x() - circle.radius < 0 || circle.pos.x() + circle.radius > width())circle.velocity.setX(-circle.velocity.x());if (circle.pos.y() - circle.radius < 0 || circle.pos.y() + circle.radius > height())circle.velocity.setY(-circle.velocity.y());}update();}private:struct Circle {QPointF pos;qreal radius;QColor color;QPointF velocity;};QVector<Circle> circles;
};

3.工程文件资源

http://www.xdnf.cn/news/951661.html

相关文章:

  • 面试高频问题
  • 魔兽世界正式服插件与宏-敏锐盗贼实用宏探索(1)-宏命令制作入门与基本知识
  • 从面试角度回答Android中ContentProvider启动原理
  • android13 app的触摸问题定位分析流程
  • 邮科ODM摄像头:多维度护航高铁安全系统方案解析
  • Kubernetes ClusterIP 端口深度解析:虚拟服务与流量转发机制
  • 我的世界Java版1.21.4的Fabric模组开发教程(十三)自定义方块状态
  • 椭圆曲线密码学(ECC)
  • 基于ADMM的MRI-PET高质量图像重建算法
  • 【Linux】进程间通讯-消息队列
  • PHP:Web 开发的经典利器
  • 我如何使用 CodeMCP 进行开发并控制其他编程助手的预算
  • nodejs express 打包部署
  • VR 技术赋能南锣鼓巷的多元发展潜力与前景​
  • 多模态图像修复系统:基于深度学习的图片修复实现
  • Android Kotlin 协程详解
  • Python 中的加密库:守护数据安全的利刃
  • 8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
  • 拟合问题处理
  • C# dll版本冲突解决方案
  • 运放——单电源供电和双电源供电
  • 商品中心—1.B端建品和C端缓存的技术文档一
  • 消息队列系统设计与实践全解析
  • 规则与人性的天平——由高考迟到事件引发的思考
  • NSS-DAY12
  • 2.2.2 ASPICE的需求分析
  • CopyQ | 在命令中使用正则表达式并实现匹配指定字符串的方法
  • 大话软工笔记—需求分析概述
  • 安宝特案例丨又一落地,Vuzix AR眼镜助力亚马逊英国仓库智能化升级!
  • games101 hw1