概述
Qt的绘图系统可以使用相同的API在屏幕和打印设备上进行绘图,并且主要基于QPainter, QPaintDevice和QPaintEngine类。QPainter用于执行绘图操作,QPaintDevice是一个二维空间的抽象,可以使用QPainter在其上绘制,QPaintEngine提供了QPainter用于在不同类型的设备上绘制的接口。QPaintEngine类在QPainter和QPaintDevice内部使用,并且对应用程序程序员是隐藏的,除非他们创建自己的设备类型。
这种方法的主要好处是,所有的绘制都遵循相同的绘制方式,从而很容易添加对新特性的支持,并为不支持的特性提供默认实现。
以下类为QPainter绘制提供了支持:
类 | 描述 |
QBitmap | 单色(1位深度)像素图 |
QBrush | 定义由QPainter绘制的形状的填充模式 |
QColor | 基于RGB, HSV或CMYK值的颜色 |
QColormap | 将与设备无关的QColors映射到与设备相关的像素值 |
QConicalGradient | 与QBrush结合使用,指定锥形梯度刷 |
QFont | 指定用于绘制文本的字体 |
QFontMetrics | 字体度量信息 |
QFontMetricsF | 字体度量信息 |
QGenericMatrix | 模板类,表示有N列和M行的NxM变换矩阵 |
QGradient | 与QBrush结合使用来指定渐变填充 |
QIcon | 不同模式和状态下的可伸缩图标 |
QIconEngine | QIcon渲染器的抽象基类 |
QImage | 独立于硬件的图像表示,允许直接访问像素数据,并且可以用作绘画设备 |
QImageReader | 格式独立的接口,读取图像从文件或其他设备 |
QImageWriter | 用于将图像写入文件或其他设备的格式独立接口 |
QLine | 二维矢量采用整数精度 |
QLineF | 二维矢量使用浮点精度 |
QLinearGradient | 与QBrush结合使用,指定线性梯度刷 |
QMargins | 定义矩形的四个边距 |
QMarginsF | 定义矩形的四个边距 |
QPagedPaintDevice | 表示支持多个页面的绘图设备 |
QPaintDevice | 可以用QPainter绘制的对象的基类 |
QPaintEngine | QPainter如何在给定平台上绘制给定设备的抽象定义 |
QPainter | 在小部件和其他绘制设备上执行低级绘制 |
QPainterPath | 用于绘制操作的容器,使图形形状能够被构造和重用 |
QPainterPathStroker | 用于为给定的画家路径生成可填充的轮廓 |
QPdfWriter | 类生成可用作绘图设备的pdf |
QPen | 定义QPainter应该如何绘制形状的线条和轮廓 |
QPixmap | 可以用作绘画设备的屏幕外图像表示 |
QPlatformFontDatabase | 可以自定义字体的发现方式和呈现方式 |
QPoint | 使用整数精度在平面上定义一个点 |
QPointF | 使用浮点精度在平面上定义一个点 |
QPolygon | 向量点使用整数精度 |
QPolygonF | 向量点使用浮点精度 |
QRadialGradient | 与QBrush结合使用,指定径向梯度刷 |
QRect | 使用整数精度在平面上定义一个矩形 |
QRectF | 使用浮点精度在平面中定义一个矩形 |
QRegion | 指定绘图器的剪辑区域 |
QSize | 使用整数点精度定义二维对象的大小 |
QSizeF | 使用浮点精度定义二维对象的大小 |
QStylePainter | 用于在小部件内绘制QStyle元素的方便类 |
QSupportedWritingSystems | 在使用内部Qt字体数据库注册字体时使用 |
QSvgGenerator | 用于创建SVG绘图的绘图设备 |
QSvgRenderer | 用于将SVG文件的内容绘制到绘图设备上 |
QSvgWidget | 小部件,用于显示可缩放矢量图形(SVG)文件的内容 |
QTransform | 指定坐标系统的2D转换 |
QVector2D | 表示二维空间中的向量或顶点 |
创建绘画设备
QPaintDevice类是可以绘制对象的基类,也就是说,QPainter可以在任何QPaintDevice子类上绘制。QPaintDevice的绘图功能是由QWidget、QImage、QPixmap、QPicture、QPrinter和QOpenGLPaintDevice实现的。
Widget
QWidget类是Qt Widgets模块中用户界面元素的基类。它接收来自窗口系统的鼠标、键盘和其他事件,并在屏幕上描绘自己的表示。
Image
QImage类提供了一个独立于硬件的图像表示,它是为I/O和直接的像素访问和操作而设计和优化的。QImage支持多种图像格式,包括单色,8位,32位和alpha混合图像。
使用QImage作为绘图设备的一个优点是,它可以以与平台无关的方式保证任何绘图操作的像素准确性。另一个好处是,绘制可以在当前GUI线程之外的另一个线程中执行。
Pixmap
QPixmap类是一个屏幕外的图像表示,它被设计和优化为在屏幕上显示图像。与QImage不同,像素图中的像素数据是内部的,由底层窗口系统管理,即像素只能通过QPainter函数或将QPixmap转换为QImage来访问。
为了使用QPixmap优化绘图,Qt提供了QPixmapCache类,它可以用于存储生成昂贵的临时像素图,而不会使用超过缓存限制的存储空间。Qt还提供了QBitmap便利类,继承了QPixmap。QBitmap保证单色(1位深度)像素图,主要用于创建自定义QCursor和QBrush对象,构造QRegion对象。
OpenGL绘制设备
如前所述,Qt提供了一些类,使在Qt应用程序中使用OpenGL变得很容易。例如,QOpenGLPaintDevice启用OpenGL API来PictureQPicture类是一个记录和回放QPainter命令的绘图设备。图片以平台无关的格式将画工命令序列化到IO设备。QPicture也是独立于分辨率的,即一个QPicture可以显示在不同的设备上(例如svg, pdf, ps,打印机和屏幕),看起来是一样的。
Qt提供了QPicture::load()和QPicture::save()函数以及用于加载和保存图片的流操作符。
Custom Backends
可以通过派生QPaintDevice类并重新实现虚拟QPaintDevice:: paintenengine()函数来实现对新后端的支持,以告诉QPainter应该使用哪个绘制引擎在这个特定的设备上绘制。要真正能够在设备上绘图,这个绘图引擎必须是从qpaintenengine类派生出来的自定义绘图引擎。
绘制
QPainter提供了高度优化的功能,以完成大多数绘图GUI程序所需的功能。它可以绘制从简单的图形基元(由QPoint, QLine, QRect, QRegion和QPolygon类表示)到复杂形状(如矢量路径)的一切。在Qt矢量路径是由QPainterPath类表示的。QPainterPath为绘制操作提供了一个容器,使图形形状能够被构造和重用。
QPainterPath
painter路径是由线条和曲线组成的对象。例如,矩形由直线组成,椭圆由曲线组成。
与普通绘图操作相比,绘制路径的主要优势在于,复杂的形状只需要创建一次;然后只需调用QPainter::drawPath()函数就可以多次绘制它们。QPainterPath对象可用于填充、勾勒和裁剪。要为给定的painter路径生成可填充的轮廓,可以使用QPainterPathStroker类。
线条和轮廓是使用QPen类绘制的。pen由其样式(即线条类型)、宽度、笔刷、如何绘制端点(cap-style)以及如何绘制两条连接线之间的连接(join-style)来定义。pen的笔刷是一个QBrush对象,用来填充pen生成的笔画,也就是说,QBrush类定义了填充模式。QPainter还可以绘制对齐的文本和像素图。
绘制文本时,使用QFont类指定字体。Qt将使用具有指定属性的字体,或者如果没有匹配的字体存在,Qt将使用最接近匹配的已安装字体。实际使用的字体属性可以使用QFontInfo类检索。此外,QFontMetrics类提供字体度量,QFontDatabase类提供有关底层窗口系统中可用字体的信息。
通常,QPainter在“自然”坐标系中绘制,但它能够使用QTransform类执行视图和世界坐标系转换。
反锯齿绘制
绘制时,像素渲染由QPainter::Antialiasing渲染提示控制。QPainter::RenderHint枚举用于指定QPainter的标志,这些标志可能被任何给定的引擎尊重,也可能不被尊重。QPainter::Antialiasing值表示引擎应该尽可能地消除原语的边缘,即通过使用不同的颜色强度平滑边缘。
基本图形绘制、填充
绘制线
void MainWindow::paintEvent(QPaintEvent *event)
{
QPainter p(this);
p.drawLine(50, 50, 100, 150);
}
或者,创建时不指定绘制设备,在begin()函数中设置,end时结束绘制。
QPainter p;
p.begin(this);
p.drawLine(50, 50, 100, 150);
p.end();绘制圆弧 绘制由给定矩形、startAngle和spanAngle定义的圆弧。
起始角和伸缩角必须以1/16度指定,即一个完整的圆等于5760(16 * 360)。角度的正值表示逆时针方向,负值表示顺时针方向。零度在3点钟方位。
QPainter p;
p.begin(this);
QRectF rectangle(10.0, 20.0, 80.0, 60.0);
int startAngle = 30 * 16;
int spanAngle = 120 * 16;
p.drawArc(rectangle, startAngle, spanAngle);
p.end();
绘制弦 绘制由给定矩形、startAngle和spanAngle定义的弦。弦被当前的笔刷()填充。
起始角和伸缩角必须以1/16度指定,即一个完整的圆等于5760(16 * 360)。角度的正值表示逆时针方向,负值表示顺时针方向。零度在3点钟方位。
QPainter p;
p.begin(this);
QRectF rectangle(10.0, 20.0, 80.0, 60.0);
int startAngle = 30 * 16;
int spanAngle = 120 * 16;
p.drawChord(rectangle, startAngle, spanAngle);
p.end();
绘制凸多边形
QPainter p;
p.begin(this);
static const QPointF points[4] = {
QPointF(40.0, 110.0),
QPointF(50.0, 40.0),
QPointF(110.0, 70.0),
QPointF(120.0, 100.0)
};
p.drawConvexPolygon(points, 4);
p.end();
绘制椭圆
QPainter p;
p.begin(this);
QRectF rectangle(100.0, 50.0, 80.0, 60.0);
p.drawEllipse(rectangle);
p.end();
如果宽,高一样,就是圆。
绘制扇形
QPainter p;
p.begin(this);
QRectF rectangle(100.0, 50.0, 160.0, 120.0);
int startAngle = 30 * 16;
int spanAngle = 120 * 16;
p.drawPie(rectangle, startAngle, spanAngle);
p.end();
填充
除此之外,还可以使用画笔及画刷进行绘制和填充绘制多边形
QPainter p;
p.begin(this);
QPen pen(QBrush(Qt::gray), 2, Qt::DashLine, Qt::FlatCap, Qt::RoundJoin);
p.setPen(pen);
p.setBrush(Qt::green);
static const QPointF points[4] = {
QPointF(40.0, 110.0),
QPointF(50.0, 40.0),
QPointF(110.0, 70.0),
QPointF(120.0, 100.0)
};
p.drawPolygon(points, 4);
p.end();
绘制圆角矩形
QPainter p;
p.begin(this);
QPen pen(QBrush(Qt::black), 2, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin);
p.setPen(pen);
p.setBrush(Qt::lightGray);
QRectF rectangle(10.0, 20.0, 80.0, 60.0);
p.drawRoundedRect(rectangle, 20.0, 15.0);
p.end();
渐变填充
使用画刷还可以进行渐变填充。
渐变有三种:
- 线性渐变:QLinearGradient
- 辐射渐变:QRadialGradient
- 锥形渐变:QConicalGradient

绘制矩形
QPainter p;
p.begin(this);
QPen pen(QBrush(Qt::black), 2, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin);
p.setPen(pen);
QLinearGradient linearGrad(QPointF(100, 100), QPointF(200, 200));
linearGrad.setColorAt(0, Qt::black);
linearGrad.setColorAt(1, Qt::white);
p.setBrush(linearGrad);
QRectF rectangle(100.0, 100.0, 100.0, 100.0);
p.drawRoundedRect(rectangle, 20.0, 15.0);
p.end();
结论
人生就是这样,有欢笑也有泪水。一部分人主要负责欢笑,另一部分人主要负责泪水。










