QPainter绘图

QPainter 提供了高度优化的功能来完成大多数绘图 GUI 程序所需的工作。它可以绘制从简单的线条到复杂的形状(如馅饼和弦)的所有内容。它还可以绘制对齐的文本和像素图。通常,它在“自然”坐标系中绘制,但它也可以进行视图和世界变换。QPainter 可以对任何继承QPaintDevice类的对象进行操作。

设置QPainter

您可以自定义几个设置以根据您的喜好绘制 QPainter

font () 是用于绘制文本的字体。如果painter isActive (),您可以分别使用fontInfo ()fontMetrics () 函数检索有关当前设置的字体及其度量的信息。
Brush () 定义用于填充形状的颜色或图案。
pen () 定义用于绘制线条或边界的颜色或点画。
backgroundMode () 定义是否有背景(),即它是Qt::OpaqueMode还是Qt::TransparentMode
background () 仅在backgroundMode ()Qt::OpaqueMode并且pen () 是点画时适用。在这种情况下,它描述了点画中背景像素的颜色。
BrushOrigin () 定义平铺画笔的原点,通常是小部件背景的原点。
viewport ()window ()worldTransform ()组成了painter的坐标变换系统。有关详细信息,请参阅坐标变换部分和坐标系文档。
hasClipping () 告诉画家是否剪辑。(paint device 也剪辑。)如果painter 剪辑,它剪辑到
clipRegion ()

layoutDirection () 定义了画家在绘制文本时使用的布局方向。
worldMatrixEnabled () 告诉世界变换是否启用。
viewTransformEnabled () 告诉是否启用视图转换。
请注意,其中一些设置反映了某些绘图设备中的设置,例如QWidget::font ()QPainter ::begin () 函数(或等效的 QPainter 构造函数)从绘图设备复制这些属性。

您可以随时通过调用save () 函数保存 QPainter 的状态,该函数将所有可用设置保存在内部堆栈中。restore () 函数将它们弹回。

绘画

QPainter提供了绘制大部分图元的函数:drawPoint ()drawPoints ()drawLine ()drawRect ()drawRoundedRect ()drawEllipse ()drawArc ()drawPie ()drawChord ()drawPolyline ()drawPolygon ()drawConvexPolygon ()drawCubicBezier()。两个便捷函数drawRects ()drawLines (),使用当前画笔和画笔在给定的QRectsQLines数组中绘制给定数量的矩形或线条。

QPainter 类还提供了使用给定QBrush填充给定QRectfillRect () 函数,以及擦除给定矩形内区域的eraseRect () 函数。

所有这些函数都有整数和浮点版本。

如果你需要绘制一个复杂的形状,尤其是如果你需要重复这样做,可以考虑创建一个QPainterPath并使用 drawPath () 来绘制它。

QPainter 还提供了用给定的QBrush填充给定的QPainterPathfillPath () 函数,以及绘制给定路径的轮廓(即描边路径)的strokePath () 函数。

文本绘制

文本绘制是使用drawText () 完成的。当您需要细粒度定位时,boundingRect () 会告诉您给定的drawText () 命令将在哪里绘制。

绘制像素图和图像

有绘制像素图/图像的函数,即drawPixmap ()、drawImage ()和drawTiledPixmap ()。drawPixmap () 和drawImage () 产生相同的结果,除了drawPixmap () 在屏幕上更快,而drawImage ( ) 在QPrinter或其他设备上可能更快。

有一个drawPicture () 函数可以绘制整个QPicture的内容。drawPicture () 函数是唯一一个忽略所有画家设置的函数,因为QPicture有自己的设置。

绘制像素图和图像的高分辨率版本
高分辨率版本的像素图具有大于 1的设备像素比值(参见QImageReaderQPixmap::devicePixelRatio ())。如果它与底层QPaintDevice的值匹配,它会直接绘制到设备上,而不应用额外的转换。

例如,将设备像素比为 2 的 64x64 像素大小的QPixmap绘制到设备像素比为 2 的高 DPI 屏幕上时就是这种情况。请注意,像素图在用户空间中实际上是 32x32 像素。Qt 中根据像素图大小计算布局几何的代码路径将使用此大小。这样做的最终效果是像素图显示为高 DPI 像素图而不是大像素图。

渲染质量

使用 QPainter 获得最佳渲染效果,应使用平台无关的QImage作为绘图设备;即使用QImage将确保结果在任何平台上都具有相同的像素表示。

QPainter 类还通过其RenderHint枚举和对浮点精度的支持提供了一种控制渲染质量的方法:所有用于绘制图元的函数都有一个浮点版本。这些通常与QPainter::Antialiasing渲染提示结合使用。

RenderHint枚举为 QPainter 指定标志,这些标志可能会或可能不会被任何给定引擎尊重。QPainter::Antialiasing表示引擎应该尽可能对图元的边缘进行抗锯齿,QPainter::TextAntialiasing表示引擎应该尽可能对文本进行抗锯齿,QPainter::SmoothPixmapTransform表示引擎应该使用平滑像素图变换算法。

renderHints () 函数返回一个标志,该标志指定为此绘制器设置的呈现提示。使用setRenderHint () 函数设置或清除当前设置的RenderHints

坐标变换

通常,QPainter 在设备自己的坐标系(通常是像素)上运行,但 QPainter 对坐标变换有很好的支持。
最常用的变换是缩放、旋转、平移和剪切。使用scale () 函数将坐标系缩放给定的偏移量,使用rotate () 函数将其顺时针旋转,并使用translate () 函数将其平移(即向点添加给定的偏移量)。您还可以使用shear () 函数围绕原点扭转坐标系。有关剪切坐标系的可视化,请参见仿射变换示例。

另请参阅Transformations示例,该示例显示了转换如何影响 QPainter 呈现图形基元的方式。特别是它显示了转换顺序如何影响结果。

所有的转换操作都在转换worldTransform () 上进行。矩阵将平面中的一个点转换为另一个点。有关变换矩阵的更多信息,请参阅坐标系和QTransform文档。

setWorldTransform () 函数可以替换或添加到当前设置的worldTransform ( )resetTransform () 函数重置使用translate ()scale ()shear ()rotate ()setWorldTransform ()setViewport ()setWindow () 函数进行的任何转换。deviceTransform _() 返回从逻辑坐标转换为平台相关绘图设备的设备坐标的矩阵。仅当在依赖平台的句柄上使用平台绘制命令时才需要后一个功能,并且平台本身不会进行转换。

使用 QPainter 绘图时,我们使用逻辑坐标指定点,然后将其转换为绘图设备的物理坐标。逻辑坐标到物理坐标的映射由QPaintercombinedTransform () 处理,它是viewport ()window () 以及worldTransform () 的组合。viewport () 表示指定任意矩形的物理坐标,window ( ) 在逻辑坐标中描述相同的矩形,worldTransform () 与变换矩阵相同。

剪裁

QPainter 可以将任何绘图操作裁剪为矩形、区域或矢量路径。当前剪辑可使用函数clipRegion ()clipPath () 获得。首选路径还是区域(更快)取决于底层的paintEngine ()。例如,QImage绘制引擎更喜欢路径,而 X11 绘制引擎更喜欢区域。设置剪辑是在画家的逻辑坐标中完成的。

QPainter 的剪辑之后,绘画设备也可能会被剪辑。例如,大多数小部件会剪掉子小部件使用的像素,而大多数打印机会剪掉靠近纸张边缘的区域。clipRegion () 或**hasClipping ()**的返回值不会反映这种额外的裁剪。

构图模式

QPainter 提供了CompositionMode枚举,它定义了数字图像合成的 Porter-Duff 规则;它描述了一个模型,用于将一个图像(源)中的像素与另一图像(目标)中的像素组合起来。

两种最常见的组合形式是SourceSourceOver。源用于将不透明对象绘制到绘图设备上。在这种模式下,源中的每个像素都会替换目标中的相应像素。在SourceOver合成模式下,源对象是透明的并绘制在目标之上。

请注意,合成变换是按像素进行的。出于这个原因,使用图形基元本身及其边界矩形之间存在差异:边界矩形包含 alpha == 0 的像素(即基元周围的像素)。这些像素将覆盖其他图像的像素,从而有效地清除这些像素,而图元仅覆盖其自己的区域。

限制

如果您在 Qt 的基于光栅的绘制引擎中使用坐标,请务必注意,虽然可以使用大于 +/- 2 15的坐标,但不能保证显示使用超出此范围的坐标执行的任何绘制;绘图可能会被剪裁。这是由于short int在实现中使用了。

Qt 的描边器生成的轮廓只是在处理弯曲形状时的近似值。在大多数情况下,不可能用另一条贝塞尔曲线段来表示一条贝塞尔曲线段的轮廓,因此 Qt 通过使用几条较小的曲线来近似曲线轮廓。出于性能原因,Qt 对这些轮廓使用多少曲线是有限制的,因此当使用较大的笔宽或比例时,轮廓误差会增加。要生成具有较小错误的轮廓,可以使用QPainterPathStroker类,它具有 setCurveThreshold 成员函数,让用户指定容错。另一种解决方法是先将路径转换为多边形,然后再绘制多边形。

表现

QPainter 是一个丰富的框架,允许开发人员进行各种各样的图形操作,例如渐变、合成模式和矢量图形。QPainter 可以在各种不同的硬件和软件堆栈上做到这一点。自然地,硬件和软件的底层组合对性能有一定的影响,并且确保每个单独的操作与合成模式、画笔、剪辑、转换等的所有各种组合结合起来都是快速的,这几乎是一项不可能完成的任务,因为排列的数量。作为折衷方案,我们选择了 QPainter API 和后端的一个子集,在给定的硬件和软件组合下,我们可以保证性能尽可能好。

作为高性能引擎,我们关注的后端是:
Raster - 这个后端在纯软件中实现所有渲染,并且总是用于渲染到 QImages 中。为了获得最佳性能,请仅使用格式类型QImage::Format_ARGB32_PremultipliedQImage::Format_RGB32QImage::Format_RGB16。任何其他格式,包括QImage::Format_ARGB32,性能明显较差。该引擎默认用于QWidgetQPixmap
OpenGL 2.0 (ES) - 此后端是硬件加速图形的主要后端。它可以在支持 OpenGL 2.0 或 OpenGL/ES 2.0 规范的台式机和嵌入式设备上运行。这包括过去几年生产的大多数图形芯片。可以通过在QOpenGLWidget上使用 QPainter 来启用引擎。

这些操作是:
简单的转换,即平移和缩放,加上 0、90、180、270 度旋转。
drawPixmap() 结合简单的转换和非平滑转换模式的不透明度(QPainter::SmoothPixmapTransform未作为渲染提示启用)。
矩形填充纯色、双色线性渐变和简单变换。
具有简单变换和相交剪辑的矩形剪辑。
合成模式QPainter::CompositionMode_SourceQPainter::CompositionMode_SourceOver
圆角矩形填充使用纯色和双色线性渐变填充。
3x3 修补像素图,通过 qDrawBorderPixmap
此列表指示在性能至关重要的应用程序中可以安全使用哪些功能。对于某些设置,其他操作可能也很快,但在大量使用它们之前,建议在最终运行软件的系统上进行基准测试和验证。在某些情况下,可以使用昂贵的操作,例如当结果缓存在QPixmap中时。
另请参阅QPaintDeviceQPaintEngineQt SVG、基本绘图示例和绘图实用程序函数。

	QPainter p(this);
	if (text() == "圆")//椭圆
	{
		p.setRenderHint(QPainter::Antialiasing, true);
		p.setPen(QPen(Qt::black, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));//拐点是圆形,连接也是方形
		p.setBrush(QBrush(Qt::green, Qt::SolidPattern));
		int diameter = width() > height() ? height() - 2 : width() - 2;
		int x = (width() - diameter) / 2;
		int y = (height() - diameter) / 2;
		p.drawEllipse(x, y, diameter, diameter);
	}
	else if (text() == "椭圆")//椭圆
	{
		p.setRenderHint(QPainter::Antialiasing, true);
		p.setPen(QPen(Qt::black, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));//拐点是圆形,连接也是方形
		p.setBrush(QBrush(Qt::green, Qt::SolidPattern));
		p.drawEllipse(1, 1, width()-2, height()-2);
	}
	else if (text() == "矩形")//矩形
	{
		p.setRenderHint(QPainter::Antialiasing, true);
		p.setPen(QPen(Qt::black, 1, Qt::SolidLine, Qt::SquareCap, Qt::BevelJoin));//拐点是方形,连接也是方
		p.setBrush(QBrush(Qt::green, Qt::SolidPattern));
		p.drawRect(rect().adjusted(1,1,-1,-1));
	}
	else if (text() == "三角形")//画三角形
	{
		p.setRenderHint(QPainter::Antialiasing, true);
		p.setPen(QPen(Qt::NoPen/*, 1, Qt::SolidLine, Qt::FlatCap,Qt::MiterJoin*/));//拐点是尖角
		p.setBrush(QBrush(Qt::green, Qt::SolidPattern));
		int hlen = 120;
		int vlen = hlen / 2;
		int x = (width() - hlen) / 2;
		int y = (height() - vlen) / 2;
		QRect r = rect().adjusted(x, y, -x, -y);
		QPolygon triangle;
		triangle << r.topLeft() << r.topRight() << (r.adjusted(0, 0, -r.width() / 2, 0)).bottomRight();//三点坐标
		p.drawPolygon(triangle);    //画三角形

	}
	else if (text() == "线")//画线
	{
		p.setRenderHint(QPainter::Antialiasing, true);
		p.setPen(QPen(Qt::black, 1, Qt::SolidLine, Qt::SquareCap));
		int x1 =30;
		int x2 = width() - x1;
		QVector<QLine> lines;
		lines << QLine(x1, 1, x2, 1);
		lines << QLine(x1, height()/2, x2, height() / 2);
		lines << QLine(x1, height() - 1, x2,height()- 1);
		p.drawLines(lines);

	}
	else if (text() == "线2")//画线
	{
		p.setRenderHint(QPainter::Antialiasing, true);
		p.setPen(QPen(Qt::black, 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
		int hlen = 20;
		int vlen = hlen / 2;
		int w = (width() - hlen)/2;
		int h = (height() - vlen)/2;
		int x1 = w;
		int y1 = h;
		int x2 = width() - w;
		int y2 = h;
		int x3 = width()/2;
		int y3 = h+vlen;

		QPolygon triangle;
		triangle << QPoint(x1, y1) << QPoint(x3, y3) <<  QPoint(x2, y2) ;//三点坐标
		p.drawPolyline(triangle); //画箭头
	}
	else if (text() == "圆角矩形")//圆角矩形
	{

		p.setRenderHint(QPainter::Antialiasing, true);
		p.setPen(QPen(Qt::black, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
		p.setBrush(QBrush(Qt::green, Qt::SolidPattern));
		p.drawRoundRect(rect().adjusted(1,1,-1,-1), 8, 8);

	}
	else if (text() == "圆角矩形2")//圆角矩形
	{
		p.setRenderHint(QPainter::Antialiasing, true);
		p.setPen(QPen(Qt::NoPen/*, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin*/));
		p.setBrush(QBrush(Qt::green, Qt::SolidPattern));

		QRect r = rect().adjusted(1, 1, -1, -1);
		int radius = qMin(r.width(), r.height()) / 2;
		int diam = 2 * radius;

		int x1, y1, x2, y2;
		r.getCoords(&x1, &y1, &x2, &y2);

		QPainterPath path;
		path.moveTo(x2, y1 + radius);
		path.arcTo(QRect(x2 - diam, y1, diam, diam), 0.0, +90.0);
		path.lineTo(x1 + radius, y1);
		path.arcTo(QRect(x1, y1, diam, diam), 90.0, +90.0);
		path.lineTo(x1, y2 - radius);
		path.arcTo(QRect(x1, y2 - diam, diam, diam), 180.0, +90.0);
		path.lineTo(x1 + radius, y2);
		path.arcTo(QRect(x2 - diam, y2 - diam, diam, diam), 270.0, +90.0);
		path.closeSubpath();

		p.drawPath(path);

	}
	else if (text() == "圆角矩形3")//圆角矩形
	{
	p.setRenderHint(QPainter::Antialiasing, true);
	p.setPen(QPen(Qt::black, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
	p.setBrush(QBrush(Qt::green, Qt::SolidPattern));

	QRect r = rect().adjusted(1, 1, -1, -1);
	int radius = qMin(r.width(), r.height()) / 2;
	int diam =  radius/2;

	int x1, y1, x2, y2;
	r.getCoords(&x1, &y1, &x2, &y2);

	QPainterPath path;
	path.moveTo(x2, y1 + radius);
	path.arcTo(QRect(x2 - diam, y1, diam, diam), 0.0, +90.0);
	path.lineTo(x1 + radius, y1);
	path.arcTo(QRect(x1, y1, diam, diam), 90.0, +90.0);
	path.lineTo(x1, y2 - radius);
	path.arcTo(QRect(x1, y2 - diam, diam, diam), 180.0, +90.0);
	path.lineTo(x1 + radius, y2);
	path.arcTo(QRect(x2 - diam, y2 - diam, diam, diam), 270.0, +90.0);
	path.closeSubpath();

	p.drawPath(path);

	}

在这里插入图片描述

QPainter官方文档

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值