一、概要

Qt中提供了强大的2D绘图系统,可以使用相同的API在屏幕和绘图设备上进行绘制,它主要基于QPainterQPaintDeviceQPaintEngine这三个类。其中QPainter用来执行绘图操作;QPaintDevice提供绘图设备,它是一个二维空间的抽象,可以使用QPainter在其上进行绘制;QPaintEngine提供了一些接口,可以用于QPainter在不同的设备上进行绘制。

QPaintEngine类由QPainter和QPaintDevice内部使用,应用程序一般无需和QPaintEngine打交道,除非要创建自己的设备类型。

在绘图系统中由QPainter来完成具体的绘制操作,QPainter类提供了大量高度优化的函数来完成GUI编程所需要的大部分绘制工作。QPainter可以绘制一切想要的图形,从最简单的一条直线到其他任何复杂的图形,它还可以用来绘制文本和图片。QPainter可以在继承自QPaintDevice类的任何对象上进行绘制操作。

QPainter一般在一个部件的重绘事件(Paint Event)的处理函数paintEvent()中进行绘制,首先要创建QPainter对象,然后进行图形的绘制,最后销毁QPainter对象。

注:从QWidget类继承的类都有paintEvent()事件,要在设备上绘图,只需要重写此事件函数,并在函数内编写相应的绘图代码就可以了,一般的绘图设备包括QWidget、QPixmap、QImage等,这些绘图设备为QPainter提供了一个“画布”,QPainter可以在这些设备上进行绘图。

二、窗口各类位置相关函数的区别

其中:

  • x()、y()和pos()函数都是获得整个窗体左上角的坐标位置。
  • frameGeometry()与geometry()相对应。frameGeometry()是获得整个窗体的左上顶点和长、宽值,而geometry()函数获得的是窗体内中央区域的左上顶点坐标以及长、宽值。
  • 直接调用width()和height()函数获得的是中央区域的长、宽值。
  • rect()、size()函数获得的结果也都是对于窗体的中央区域而言的。size()获得的是窗体中央区域的长、宽值,rect()与geometry()一样返回一个QRect对象,这两个函数获得的长、宽值是一样的,都是窗体中央区域的长、宽值,只是左上顶点的坐标值不一样,geometry()获得的左上顶点坐标是相对于父窗体而言的坐标,而rect()获得的左上顶点坐标始终为(0,0)。在实际应用中需根据情况使用正确的位置信息函数以获得准确的位置尺寸信息,尤其是在编写对位置精度要求较高的程度时(如地图浏览程序),更应注意函数的选择,避免产生不必要的误差。

三、绘图操作的一般步骤

方式1:

QPainter painter(this)//! 配置相关属性
setPen(); //设置画笔,
setFont(); //设置字体格式
setBrush(); //设置画刷setRenderHint(QPainter::Antialiasing); //设置反锯齿
//设置组合模式,即后面绘制的图与前面绘制的图叠加模式,参数是一个QPainter::CompositionMode枚举类型(类型很多,有40多种,详情见QT帮助文档)
void QPainter::setCompositionMode(CompositionMode mode)绘图操作

方式2

QPainter painter;
painter.begin(this);//! 配置相关属性
setPen(); //设置画笔,
setFont(); //设置字体格式
setBrush(); //设置画刷setRenderHint(QPainter::Antialiasing); //设置反锯齿
//设置组合模式,即后面绘制的图与前面绘制的图叠加模式,参数是一个QPainter::CompositionMode枚举类型(类型很多,有40多种,详情见QT帮助文档)
void QPainter::setCompositionMode(CompositionMode mode)绘图操作painter.end();

四、一般绘图演示

void Widget::paintEvent(QPaintEvent *event)
{QPainter painter(this);//! 添加画笔QPen pen;pen.setColor( QColor(255,0,0) );pen.setStyle(Qt::DotLine);pen.setWidth(2);painter.setPen(pen);//! 添加画刷QBrush brush;brush.setColor(QColor(0,255,0,125));brush.setStyle(Qt::SolidPattern);painter.setBrush(brush);//! 画矩形框painter.drawRect(10,20,200,100);//! 画直线painter.drawLine(QPoint(0,0),QPoint(100,100));}

输出结果:

五、显示文字演示

void Widget::paintEvent(QPaintEvent *event)
{QPainter painter(this);//! 添加画笔QPen pen;pen.setColor( QColor(255,0,0) );pen.setStyle(Qt::DotLine);pen.setWidth(2);painter.setPen(pen);//! 添加画刷QBrush brush;brush.setColor(QColor(0,255,0,125));brush.setStyle(Qt::SolidPattern);painter.setBrush(brush);//! 画矩形框painter.drawRect(10,20,200,100);//! 画直线painter.drawLine(QPoint(0,0),QPoint(100,100));//! 设置字体QFont font;font.setFamily("宋体");font.setPixelSize(10);font.setBold(true);font.setUnderline(true);font.setLetterSpacing(QFont::AbsoluteSpacing,1);painter.setFont(font);//! 绘制文字painter.drawText(QPoint(100,100),"你好");painter.drawText(QRect(10,20,200,100),Qt::AlignCenter,"你好");}

六、显示图片演示

Qt提供了四个类来处理图像数据:QImageQPixmapQBitmapQPicture,它们也都是常用的绘图设备。其中QImage主要用来进行I/O处理,它对I/O处理操作进行了优化,而且也可以用来直接访问和操作像素;QPixmap主要用来在屏幕上显示图像,它对在屏幕上显示图像进行了优化;QBitmapQPixmap的子类,它是一个便捷类,用来处理颜色深度为1的图像,即只能显示黑白两种颜色;QPicture用来记录并重演QPainter命令。

void Widget::paintEvent(QPaintEvent *event)
{QPainter painter(this);QPixmap pix;pix.load("E:/work/qe/myGui3/1.png");painter.drawPixmap(QRect(0,0,pix.width(),pix.height()),pix);
}

七、绘制路径演示

如果要绘制一个复杂的图形,尤其是要重复绘制这样的图形,那么可以使用QPainterPath类,然后使用QPainter::drawPath()来进行绘制。QPainterPath类为绘制操作提供了一个容器,可以用来创建图形并且重复使用。一个绘图路径就是由多个矩形、椭圆、线条或者曲线等组成的对象,一个路径可以是封闭的,例如矩形和椭圆;也可以是非封闭的,例如线条和曲线。

void MainWidget::paintEvent(QPaintEvent *event)
{//! 设置字体QFont font;font.setFamily("宋体");font.setPixelSize(64);font.setBold(true);font.setUnderline(true);QPainterPath painterPath;painterPath.addRect(QRect(20,20,200,200));painterPath.moveTo(200,200);painterPath.lineTo(300,400);painterPath.addText(QPoint(300,400),font,"你好");QPainter painter;painter.begin(this);//! 设置画笔QPen pen;pen.setWidth(1);pen.setStyle(Qt::DotLine);pen.setColor(QColor(255,0,0));painter.setPen(pen);//! 设置画刷QBrush brush;brush.setColor(QColor(0,255,0,125));brush.setStyle(Qt::SolidPattern);painter.setBrush(brush);painter.drawPath(painterPath);painter.end();}

八、双缓冲绘图演示

双缓冲(double-buffers)绘图,就是在进行绘制时,先将所有内容都绘制到一个绘图设备(如QPixmap)上,然后再将整个图像绘制到部件上显示出来。使用双缓冲绘图可以避免显示时的闪烁现象。从Qt 4.0开始,QWidget部件的所有绘制都自动使用了双缓冲,所以一般没有必要在paintEvent()函数中使用双缓冲代码来避免闪烁。

虽然在一般的绘图中无需手动使用双缓冲绘图,不过要想实现一些绘图效果,还是要借助于双缓冲的概念。比如这个程序里,我们要实现使用鼠标在界面上绘制一个任意大小的矩形。这里需要两张画布,它们都是QPixmap实例,其中一个tempPix用来作为临时缓冲区,当鼠标正在拖动矩形进行绘制时,将内容先绘制到tempPix上,然后将tempPix绘制到界面上;而另一个pix作为缓冲区,用来保存已经完成的绘制。当松开鼠标完成矩形的绘制后,则将tempPix的内容复制到pix上。为了绘制时不显示拖影,而且保证以前绘制的内容不消失,那么在移动鼠标过程中,每绘制一次,都要在绘制这个矩形的原来的图像上进行绘制,所以需要在每次绘制tempPix之前,先将pix的内容复制到tempPix上。因为这里有两个QPixmap对象,也可以说有两个缓冲区,所以称之为双缓冲绘图。

代码详见《双缓冲绘图练习(20200217)》

九、图形视图框架

十、绘制波形图

参考资料:

1.  http://shouce.jb51.net/qt-beginning/15.html

2. QT基础:45---QPainter绘图

3. Qt之图形(QPainterPath)

4.QT基础:46---QPainter绘图之QPen、QBrush、QFont工具

5.mouseMoveEvent中判断鼠标状态

6.QT基础:47---QPainter绘图之坐标转换函数、视口和窗口

Qt学习笔记之2D绘图相关推荐

  1. Qt 学习笔记(5)绘图 五子棋游戏

    在上一篇博客C++ Qt学习笔记(4)绘图中介绍了Qt中的绘图方法,基于上一篇的博客的知识,使用QPainter设计一个五子棋的棋盘,后续会完成五子棋的游戏设计. 1. 棋盘的设计 首先需要绘制棋盘的 ...

  2. Qt学习笔记,Qt程序架构设计要旨

    Qt学习笔记,Qt程序架构设计要旨 时间过得很快,转眼学习Qt已经有一个多月了,对Qt的学习也在不断的深入中.自己手下的code也很多了,不过不得不说,还有很多的部分没有接触过,比如网络编程,2D,3 ...

  3. QT学习笔记(十三):绘制图像

    QT学习笔记(十三):绘制图像 paintEvent() 事件源码添加: #include <QPainter> #include <QImage> #include < ...

  4. Qt学习笔记,Qt国际化

    Qt学习笔记,Qt国际化 Qt国际化步骤: 第一步:设置.pro文件,加入TRANSLATIONS为国际化做准备 TRANSLATIONS = language/language_en.ts\     ...

  5. Qt学习笔记之MySQL数据库

    一.MySQL概述 MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品.MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQ ...

  6. Qt学习笔记之数据库

    一.数据库简介 1.1.数据和数据库(DB) 用计算机进行数据处理,首先就要把信息以数据形式存储到计算机中,故数据是可以被计算机接受和处理的符号.根据所表示的信息特征不同,数据有不同的类别,如数字.文 ...

  7. Qt学习笔记之文件处理

    Qt提供了通用的文件处理类QFile和处理文本的QTextStream类和处理二进制数据的QDataStream类,这些流操作极大地方便了对文件的督促存储.对文件信息和目录进行操作的类是QfileIn ...

  8. Qt学习笔记之国际化

    国际化的英文表述为Internationalization,通常简写为I18N(首尾字母加中间的字符数),一个应用程序的国际化就是使该应用程序可以让其他国家的用户使用的过程. 1. 相关的Qt类和AP ...

  9. Qt学习笔记之 字符串类型小结

    1. Qt常用字符串类型 1.1 QString QString是Unicode编码的字符串,存储一系列16位的QChar,每一个QChar对应一个Unicode 4.0编码的字符,详见<Qt学 ...

最新文章

  1. 神经网络原来这么简单,机器学习入门贴送给你 | 干货
  2. tinymce vue 部分工具不显示_2018年编程工具发展趋势
  3. Python100入门题 | 第001题
  4. matlab根据结构体数组,用邻接矩阵和序遍历创建树形结构:
  5. 【Spring-AOP-1】AOP相关概念
  6. 诊断SQLSERVER问题常用的日志
  7. linux内核字符串逆序,Linux内核中常用字符串函数实现
  8. python远程备份mysql_python3把服务器备份mysql数据库下载到本地
  9. splitpane如何设置竖条的宽度_如何用 CSS 画三角形和箭头
  10. 麦克纳姆轮运动原理_光是怎样被证明是电磁波的?麦克斯韦超凡的数学统一电学和磁学!...
  11. 200支高校无人车赛队,华科为什么能赢?
  12. 怎么查看以前的地图(卫星地图历史影像)?
  13. 破解app 在so层的密钥key
  14. python 创意编程 全国-全国青少年创意编程与智能设计大赛Python创意编程比赛
  15. 企业级自动化运维工具Ansible详解(上)
  16. 关于骨骼(Skeleton)、绑定(Rigging)、蒙皮(Skinning)、刷权重(Weight Painting)那些事儿(9月3日 更新)
  17. 2019级软件工程应用与实践-人工智能快递柜(综述)
  18. php 上传 照片流,在 iPhone 上使用“我的照片流”的方法!
  19. linux运维必备178个命令
  20. oracle收集统计信息之analyze

热门文章

  1. boost::type_index模块实现存储有关类型的信息
  2. boost::set_symmetric_difference相关的测试程序
  3. boost::insert相关的测试程序
  4. Boost.MultiIndex 使用重排工具的例子
  5. 使用 Boost.MPI 的 split() 操作对通信器的示例
  6. boost::mp11::mp_contains相关用法的测试程序
  7. boost::contract模块实现observer观察者的测试程序
  8. 基于Boost::beast模块的同步http服务器
  9. ITK:计算Sigmoid
  10. VTK:PolyData之ColorCellsWithRGB