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
实现的。
QWidget
类是Qt Widgets
模块中用户界面元素的基类。它接收来自窗口系统的鼠标、键盘和其他事件,并在屏幕上描绘自己的表示。
QImage
类提供了一个独立于硬件的图像表示,它是为I/O和直接的像素访问和操作而设计和优化的。QImage
支持多种图像格式,包括单色,8位,32位和alpha混合图像。
使用QImage
作为绘图设备的一个优点是,它可以以与平台无关的方式保证任何绘图操作的像素准确性。另一个好处是,绘制可以在当前GUI线程之外的另一个线程中执行。
QPixmap
类是一个屏幕外的图像表示,它被设计和优化为在屏幕上显示图像。与QImage
不同,像素图中的像素数据是内部的,由底层窗口系统管理,即像素只能通过QPainter
函数或将QPixmap
转换为QImage
来访问。
为了使用QPixmap
优化绘图,Qt
提供了QPixmapCache类
,它可以用于存储生成昂贵的临时像素图,而不会使用超过缓存限制的存储空间。
Qt
还提供了QBitmap
便利类,继承了QPixmap
。QBitmap
保证单色(1位深度)像素图,主要用于创建自定义QCursor
和QBrush
对象,构造QRegion
对象。
OpenGL
绘制设备如前所述,Qt提供了一些类,使在Qt应用程序中使用OpenGL
变得很容易。例如,QOpenGLPaintDevice
启用OpenGL API
来Picture
QPicture
类是一个记录和回放QPainter
命令的绘图设备。图片以平台无关的格式将画工命令序列化到IO设备。QPicture
也是独立于分辨率的,即一个QPicture
可以显示在不同的设备上(例如svg, pdf, ps,打印机和屏幕),看起来是一样的。
Qt提供了QPicture::load()
和QPicture::save()
函数以及用于加载和保存图片的流操作符。
可以通过派生QPaintDevice
类并重新实现虚拟QPaintDevice:: paintenengine()
函数来实现对新后端的支持,以告诉QPainter
应该使用哪个绘制引擎在这个特定的设备上绘制。要真正能够在设备上绘图,这个绘图引擎必须是从qpaintenengine
类派生出来的自定义绘图引擎。
QPainter
提供了高度优化的功能,以完成大多数绘图GUI程序所需的功能。它可以绘制从简单的图形基元(由QPoint, QLine, QRect, QRegion和QPolygon类表示)到复杂形状(如矢量路径)的一切。在Qt矢量路径是由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();
使用画刷还可以进行渐变填充。
渐变有三种:
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();
人生就是这样,有欢笑也有泪水。一部分人主要负责欢笑,另一部分人主要负责泪水
。