[Qt教程] 第18篇 2D绘图(八)双缓冲绘图

楼主

 发表于 2013-5-2 22:07:23 | 查看: 789| 回复: 1
双缓冲绘图
版权声明

该文章原创于Qter开源社区(www.qter.org),作者yafeilinux,转载请注明出处!
导语

在前面一节中,讲述了如何实现简单的涂鸦板,这一次我们将实现在涂鸦板上绘制图形,这里以矩形为例进行讲解。在后面还会提出双缓冲绘图的概念。
环境:Windows Xp + Qt 4.8.4+QtCreator 2.6.2
目录

一、绘制矩形
二、双缓冲绘图
正文

一、绘制矩形
1.我们仍然在前面程序的基础上进行修改,先更改painEvent()函数:
void Dialog::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    int x,y,w,h;
    x = lastPoint.x();
    y = lastPoint.y();
    w = endPoint.x() - x;
    h = endPoint.y() - y;
    painter.drawRect(x, y, w, h);
}
这里就是通过lastPoint和endPoint两个点来确定要绘制的矩形的起点、宽和高的。运行程序,用鼠标拖出一个矩形,效果如下图所示。
2. 上面已经可以拖出一个矩形了,但是这样直接在窗口上绘图,以前画的矩形是不能保存下来的。所以我们下面加入画布,在画布上进行绘图。将paintEvent()函数更改如下:
void Dialog::paintEvent(QPaintEvent *)
{
    int x,y,w,h;
    x = lastPoint.x();
    y = lastPoint.y();
    w = endPoint.x() - x;
    h = endPoint.y() - y;
    QPainter pp(&pix);
    pp.drawRect(x, y, w, h);
    QPainter painter(this);
    painter.drawPixmap(0, 0, pix);
}
这里就是将图形先绘制在了画布上,然后将画布绘制到窗口上。我们运行程序,然后使用鼠标拖出一个矩形,发现出现了很多重影,效果如下图所示。
为什么会出现这种现象呢?大家可以尝试分别快速拖动鼠标和慢速拖动鼠标来绘制矩形,结果会发现,拖动速度越快,重影越少。其实,在我们拖动鼠标的过程中,屏幕已经刷新了很多次,也可以理解为paintEvent()函数执行了多次,每执行一次就会绘制一个矩形。知道了原因,就有方法来避免这个问题发生了。
二、双缓冲绘图
1.我们再添加一个辅助画布,如果正在绘图,也就是鼠标按键还没有释放的时候,就在这个辅助画布上绘图,只有当鼠标按键释放的时候,才在真正的画布上绘图。
首先在dialog.h文件中添加两个私有变量:
QPixmap tempPix; //辅助画布
bool isDrawing;   //标志是否正在绘图
然后到dialog.cpp的构造函数中对变量进行初始化:
isDrawing = false;
下面再更改paintEvent()函数:
void Dialog::paintEvent(QPaintEvent *)
{
    int x,y,w,h;
    x = lastPoint.x();
    y = lastPoint.y();
    w = endPoint.x() - x;
    h = endPoint.y() - y;
    QPainter painter(this);
    if(isDrawing) //如果正在绘图,就在辅助画布上绘制
    {
       //将以前pix中的内容复制到tempPix中,保证以前的内容不消失
       tempPix = pix;
       QPainter pp(&tempPix);
       pp.drawRect(x,y,w,h);
       painter.drawPixmap(0, 0, tempPix);
    } else {
       QPainter pp(&pix);
       pp.drawRect(x,y,w,h);
       painter.drawPixmap(0,0,pix);
    }
}
下面还需要更改鼠标按下事件处理函数和鼠标释放事件处理函数的内容:
void Dialog::mousePressEvent(QMouseEvent *event)
{
    if(event->button()==Qt::LeftButton) //鼠标左键按下
    {
       lastPoint = event->pos();
       isDrawing = true;   //正在绘图
    }
}
void Dialog::mouseReleaseEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton) //鼠标左键释放
    {
       endPoint = event->pos();
       isDrawing = false;    //结束绘图
       update();
    }
}
当鼠标左键按下时我们开始标记正在绘图,当按键释放时我们取消正在绘图的标记。现在运行程序,已经可以实现正常的绘图了。效果如下图所示。
2.双缓冲绘图
根据这个例子所使用的技巧,我们引出所谓的双缓冲绘图的概念。双缓冲(double-buffers)绘图,就是在进行绘制时,先将所有内容都绘制到一个绘图设备(如QPixmap)上,然后再将整个图像绘制到部件上显示出来。使用双缓冲绘图可以避免显示时的闪烁现象。从Qt 4.0开始,QWidget部件的所有绘制都自动使用了双缓冲,所以一般没有必要在paintEvent()函数中使用双缓冲代码来避免闪烁。
虽然在一般的绘图中无需手动使用双缓冲绘图,不过要想实现一些绘图效果,还是要借助于双缓冲的概念。比如这个程序里,我们要实现使用鼠标在界面上绘制一个任意大小的矩形。这里需要两张画布,它们都是QPixmap实例,其中一个tempPix用来作为临时缓冲区,当鼠标正在拖动矩形进行绘制时,将内容先绘制到tempPix上,然后将tempPix绘制到界面上;而另一个pix作为缓冲区,用来保存已经完成的绘制。当松开鼠标完成矩形的绘制后,则将tempPix的内容复制到pix上。为了绘制时不显示拖影,而且保证以前绘制的内容不消失,那么在移动鼠标过程中,每绘制一次,都要在绘制这个矩形的原来的图像上进行绘制,所以需要在每次绘制tempPix之前,先将pix的内容复制到tempPix上。因为这里有两个QPixmap对象,也可以说有两个缓冲区,所以称之为双缓冲绘图。
结语

    对于Qt基本绘图的内容,我们就讲到这里,如果大家还想更加系统深入的学习这些基础知识,可以参考《Qt Creator快速入门》的第10章。从下一节开始,我们将简单介绍一下Qt中得图形视图框架。


涉及到的源码:  painter_3.zip (2.74 KB, 下载次数: 9)

[Qt教程] 第18篇 2D绘图(八)双缓冲绘图相关推荐

  1. [Qt教程] 第48篇 进阶(八) 3D绘图简介

    [Qt教程] 第48篇 进阶(八) 3D绘图简介 楼主  发表于 2013-10-7 09:44:37 | 查看: 184| 回复: 0 3D绘图简介 版权声明 该文章原创于作者yafeilinux, ...

  2. [Qt教程] 第20篇 2D绘图(十)图形视图框架(下)

    [Qt教程] 第20篇 2D绘图(十)图形视图框架(下) 楼主  发表于 2013-5-4 15:43:02 | 查看: 861| 回复: 0 图形视图框架(下) 版权声明 该文章原创于Qter开源社 ...

  3. [Qt教程] 第19篇 2D绘图(九)图形视图框架(上)

    [Qt教程] 第19篇 2D绘图(九)图形视图框架(上) 楼主  发表于 2013-5-4 15:26:20 | 查看: 1798| 回复: 26 图形视图框架(上) 版权声明 导语 在前面讲的基本绘 ...

  4. [Qt教程] 第17篇 2D绘图(七)涂鸦板

    [Qt教程] 第17篇 2D绘图(七)涂鸦板 楼主  发表于 2013-5-2 21:37:41 | 查看: 1255| 回复: 16 涂鸦板 版权声明 该文章原创于Qter开源社区(www.qter ...

  5. [Qt教程] 第16篇 2D绘图(六)坐标系统

    [Qt教程] 第16篇 2D绘图(六)坐标系统 楼主  发表于 2013-5-2 20:08:12 | 查看: 738| 回复: 0 坐标系统 版权声明 该文章原创于Qter开源社区(www.qter ...

  6. [Qt教程] 第15篇 2D绘图(五)绘制图片

    [Qt教程] 第15篇 2D绘图(五)绘制图片 楼主  发表于 2013-5-2 17:59:00 | 查看: 886| 回复: 3 绘制图片 版权声明 该文章原创于Qter开源社区(www.qter ...

  7. [Qt教程] 第14篇 2D绘图(四)绘制路径

    [Qt教程] 第14篇 2D绘图(四)绘制路径 楼主  发表于 2013-4-27 12:40:52 | 查看: 611| 回复: 0 绘制路径 版权声明 该文章原创于Qter开源社区(www.qte ...

  8. [Qt教程] 第13篇 2D绘图(三)绘制文字

    [Qt教程] 第13篇 2D绘图(三)绘制文字 楼主  发表于 2013-4-25 23:04:46 | 查看: 720| 回复: 0 绘制文字 版权声明 该文章原创于Qter开源社区,作者yafei ...

  9. [Qt教程] 第12篇 2D绘图(二)渐变填充

    [Qt教程] 第12篇 2D绘图(二)渐变填充 楼主  发表于 2013-4-23 17:59:31 | 查看: 689| 回复: 1 渐变填充 版权声明 该文章原创于Qter开源社区,作者yafei ...

最新文章

  1. 方立勋_30天掌握JavaWeb_Servlet
  2. (poj)1064 Cable master 二分+精度
  3. JS手动实现一个new操作符
  4. 微课|中学生可以这样学Python(5.6.1节):列表推导式2
  5. 【干货】2021微信生态下的营销洞察.pdf(附下载链接)
  6. [SecureCRT] 解决 securecrt failed to open the host key database file 的问题
  7. java多态机制优点_java面向对象多态性有什么好处?能说的简单易懂点,最好有代码实现结果信息,麻烦各位java大神回答一下?...
  8. 个人学习进度(第四周)
  9. mini LED光学仿真
  10. 用PS将照片背景变成白色
  11. SpringBoot 如何执行定时任务
  12. 有没有谁做过完整的ptf上传下载
  13. 原创:职场最忌讳的几大“想当然”
  14. DB2活动日志满的原因、分析、处理与避免
  15. 关于浏览器被劫持主页的处理方法(完结版)
  16. jQuery实现瀑布流布局(1+X Web前端开发初级 例题)
  17. Cubase Pro 10.0.50 PC 完整版音乐制作宿主软件下载
  18. 2021年目标,我打算这样去实现
  19. Mutual Supervision for Dense Object Detection
  20. 数字动漫平台之集群渲染技术解决方案

热门文章

  1. java: 十六进制转八进制
  2. 常用计算机服务,常用计算机端口对应的服务(The commonly used computer port corresponding service).doc...
  3. 浙江大华2011.10.10校园招聘会笔试题
  4. c++ STL find search
  5. 随手练——HDU-2037 、P-2920 时间安排(贪心)
  6. 关于Unity实现AR功能(四)设置相机的对焦
  7. python学习笔记(12)--程序设计方法学
  8. php$_GET 变量
  9. python下各种包的安装
  10. 【LeetCode】191. Number of 1 Bits