在 Qt 2D 世界中,图形基本都由点、线、矩形、多边形、椭圆、圆、折线、曲线、文本、贴图等基本元素辅以着色而构成,而且 QPainter 类已经提供了这些元素的绘制方法,花点时间掌握这些方法,也就掌握了 Qt 2D图形控件的制作,余下的就是勤学多练、孰能生巧了。

一、点

在 Qt 中使用 QPoint 或 QPointF 类型表示一个点的坐标。

QPoint 和 QPointF 的区别在于:QPoint 使用整型表示 X 和 Y 坐标,而 QPointF 使用 qreal 浮点类型表示X和Y坐标。下面如无特殊说明,所介绍的方法都适用于两个类型。

QPoint 类型虽然提供了 isNull 方法来判断对象是否为空,在 X 和 Y 坐标均为 0 时,isNull 返回 true,其他情况返回 false。在使用 QPoint::isNull 方法时要留意这个情况。

可以使用 QPoint::manhattanLength 方法返回 x 和 y 坐标的绝对值之和(也叫曼哈顿距离),如:

1
2
QPoint pt(-2, 4);
pt.manhattanLength(); // 6

1.1 两点距离

使用两点间的距离公式可以快速计算两点的距离:

1
2
3
4
5
6
#include <QtMath>

QPointF pt1(-2, 4);
QPointF pt2(4, 8);

qreal distance = qSqrt(qPow(pt1.x() - pt2.x(), 2.0) + qPow(pt1.y() - pt2.y(), 2.0)); // 7.21

1.2 drawPoint 与 drawPoints

drawPoint 用于绘制单个点:

1
2
3
void drawPoint(const QPointF &position)
void drawPoint(const QPoint &position)
void drawPoint(int x, int y)

drawPoints 用于一次性绘制多个点:

1
2
3
4
void drawPoints(const QPointF *points, int pointCount)
void drawPoints(const QPolygonF &points)
void drawPoints(const QPoint *points, int pointCount)
void drawPoints(const QPolygon &points)

QPolygon继承自 QVector<QPoint>,而QPolygonF继承自 QVector<QPointF>

二、折线

折线是由多个点相连组成的非闭合线条(相邻的两个点连接成直线,但首位不相连)。

1
2
3
4
void drawPolyline(const QPointF *points, int pointCount)
void drawPolyline(const QPolygonF &points)
void drawPolyline(const QPoint *points, int pointCount)
void drawPolyline(const QPolygon &points)

下面示例演示了折线的一种绘制方法,为了使线条更加圆润,我们还设置了线条的起落笔样式和相交点样式。

1
2
3
4
5
6
7
8
9
10
11
void Qt2DSample::paintEvent(QPaintEvent* e) {
QPainter painter(this);
painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);

painter.setPen(QPen(Qt::red, 6, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));

QPolygon pg;
pg << QPoint(20, 200) << QPoint(80, 10) << QPoint(140, 200) << QPoint(200, 10);

painter.drawPolyline(pg);
}

三、多边形

多边形是在折线的基础上首尾相连而来,并且可以使用画刷对多边形的闭合区域进行填充。

仍然使用上面示例中定义的点来绘制多边形,设置 QPainter 画刷颜色为蓝色:

1
2
3
4
5
6
7
8
9
10
11
12
void Qt2DSample::paintEvent(QPaintEvent* e) {
QPainter painter(this);
painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);

painter.setPen(QPen(Qt::red, 6, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));

QPolygon pg;
pg << QPoint(20, 200) << QPoint(80, 10) << QPoint(140, 200) << QPoint(200, 10);

painter.setBrush(Qt::blue);
painter.drawPolygon(pg);
}

四、线

两点(QPoint 或 QPointF)可以确定一条直线,Qt 提供了 QLine 和 QLineF 类型来描述线段。

使用 drawLine 方法可以绘制一条直线,使用 drawLines 方法则可以一次性绘制多条直线。

1
2
3
4
5
6
7
8
9
10
11
12
13
void drawLine(const QLineF &line)
void drawLine(const QLine &line)
void drawLine(int x1, int y1, int x2, int y2)
void drawLine(const QPoint &p1, const QPoint &p2)
void drawLine(const QPointF &p1, const QPointF &p2)
void drawLines(const QLineF *lines, int lineCount)
void drawLines(const QVector<QLineF> &lines)
void drawLines(const QPointF *pointPairs, int lineCount)
void drawLines(const QVector<QPointF> &pointPairs)
void drawLines(const QLine *lines, int lineCount)
void drawLines(const QVector<QLine> &lines)
void drawLines(const QPoint *pointPairs, int lineCount)
void drawLines(const QVector<QPoint> &pointPairs)

五、椭圆与圆

5.1 椭圆

椭圆有长轴、短轴、焦点等概念,建议在学习绘制椭圆之前先了解椭圆的这些概念,可以参考之前的文章 回顾2D绘图的数学知识 中的“椭圆”章节。

Qt提供了 QPainter::drawEllipse 方法绘制椭圆,方法原型如下:

1
2
3
4
5
void drawEllipse(const QRectF &rectangle)
void drawEllipse(const QRect &rectangle)
void drawEllipse(int x, int y, int width, int height)
void drawEllipse(const QPointF &center, qreal rx, qreal ry)
void drawEllipse(const QPoint &center, int rx, int ry)

drawEllipse 方法虽然有5种重载形式,但总体来说,都是传递一个矩形区域给 drawEllipse方法,因为根据传入的矩形可以确定椭圆的长轴、短轴和焦点,其中长轴等于矩形的长,短轴等于矩形的高,2个焦点分别位于2个长半轴的中间。

下面示例先绘制了一个浅灰色的矩形(用于观察椭圆的绘制),然后在使用该矩形绘制椭圆。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void Qt2DSample::paintEvent(QPaintEvent* e) {
QPainter painter(this);
painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);

QRectF rect(50, 50, 300, 200);

// 浅灰色的矩形
painter.setPen(Qt::lightGray);
painter.drawRect(rect);

// 红色椭圆
painter.setPen(Qt::red);
painter.drawEllipse(rect);
}

5.2 圆

圆是椭圆的一种特殊情况,当椭圆的长轴等于短轴时,所绘制出来的就是圆了。

1
2
3
4
5
6
7
8
9
void Qt2DSample::paintEvent(QPaintEvent* e) {
QPainter painter(this);
painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);

// 宽 = 高
QRectF rect(50, 50, 300, 300);

painter.drawEllipse(rect);
}

六、矩形

在 Qt中使用 QRect 和 QRectF 类型来表示矩形,在使用 QRect 时需要关注 QRect 的历史遗留问题,详见:玩转Qt 2D绘图之坐标系 的“QRect遗留问题”章节。

6.1 矩形的合法性

QRect和QRectF类型均提供了isEmpty、isNull、isValid方法,但 QRect 由于历史遗留问题,官方文档中对各个方法的定义看起来比较怪异,进行逻辑下面对其进行了逻辑运算,方便理解。

QRect

1
2
3
4
5
6
7
8
9
10
11
isEmpty() == left() > right() || top() > bottom()
== left() > left() + width() - 1 || top() > top() + height() - 1
== 1 > width() || 1 > height()

isNull() == (right() == left() - 1 && bottom() == top() - 1)
== (left() + width() - 1 == left() - 1 && top() + height() - 1 == top() - 1)
== (width() == 0 && height() == 0)

isValid() == left() <= right() && top() <= bottom()
== left() <= left() + width() - 1 && top() <= top() + height() - 1
== 1 <= width() && 1 <= height()

QRectF

1
2
3
isEmpty() == width() <= 0 || height() <= 0
isNull() == width() == 0 && height() == 0
isValid() == width() > 0 && height() > 0

从上述定义可以发现,当前矩形的宽或高为负数时,isNull 返回的却是 false。

6.2 drawRect 与 drawRects

使用 drawRect 方法绘制单个矩形,使用 drawRects 方法一次性绘制多个矩形。

1
2
3
4
5
6
7
void drawRect(const QRectF &rectangle)
void drawRect(int x, int y, int width, int height)
void drawRect(const QRect &rectangle)
void drawRects(const QRectF *rectangles, int rectCount)
void drawRects(const QVector<QRectF> &rectangles)
void drawRects(const QRect *rectangles, int rectCount)
void drawRects(const QVector<QRect> &rectangles)

下面是一个简单的使用示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
void Qt2DSample::paintEvent(QPaintEvent* e) {
QPainter painter(this);
painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);

painter.drawRect(QRect(20, 20, 200, 200));

painter.setPen(Qt::red);

QVector<QRect> rects;
rects << QRect(60, 60, 200, 200)
<< QRect(100, 100, 200, 200);
painter.drawRects(rects);
}

6.3 圆角矩形

上面绘制的矩形都不是圆角,在Qt中绘制圆角矩形有两种方式:

  • QPainter::drawRoundedRect,本节主要介绍这种方法,这种方法绘制的圆角矩形的4个角的曲度一样。

    QPainter还提供了 drawRoundRect 方法也可以绘制圆角矩形,但该方法已经被标记为弃用,因此不建议继续使用。

  • QPainter::drawPath 通过路径的方式来绘制圆角矩形,这种方法绘制的圆角矩形的4个角的曲度可以不一样,该方法会在下面章节介绍。

1
void QPainter::drawRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode = Qt::AbsoluteSize)

下面示例为了演示圆角矩形和普通的直角矩形的不同,先绘制了一个浅灰色直角矩形,然后再相同区域绘制了一个红色圆角矩形。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void Qt2DSample::paintEvent(QPaintEvent* e) {
QPainter painter(this);
painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);

QRectF rect(50, 50, 300, 200);

// 先绘制一个浅灰色的矩形
painter.setPen(Qt::lightGray);
painter.drawRect(rect);


// 然后绘制一个红色圆角矩形
//
qreal xRadius = 20;
qreal yRadius = 40;

painter.setPen(QPen(Qt::red, 1, Qt::DashDotLine));
painter.drawRoundedRect(rect, xRadius, yRadius);
}

7.4 xRadius 与 yRadius

xRadius 与 yRadius 参数决定了圆角的曲度,drawRoundedRect 方法绘制的圆角矩形的四个角采用同一个曲度。那么 xRadius 与 yRadius 参数是如何决定圆角的曲度的呢?

xRadius 参数实际为椭圆的长半轴,yRadius 参数实际为椭圆的短半轴。

关于椭圆的相关知识,可以参考之前的文章 回顾2D绘图的数学知识 中的“椭圆”章节。

通过 xRadius 和 yRadius 参数确定了椭圆的长轴和短轴,那么在什么位置画椭圆呢?答案是:贴着四个顶角分别画 4 个椭圆来确定曲度。

下面代码在上面示例的基础上,分别在左上角和右下角位置画了2个深黄色的椭圆,可以看到椭圆与圆角是刚好重合的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void Qt2DSample::paintEvent(QPaintEvent* e) {
QPainter painter(this);
painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);

QRectF rect(50, 50, 300, 200);

// 先绘制一个浅灰色的矩形
painter.setPen(Qt::lightGray);
painter.drawRect(rect);


// 然后绘制一个红色圆角矩形
//
qreal xRadius = 20;
qreal yRadius = 40;

painter.setPen(QPen(Qt::red, 1, Qt::DashDotLine));
painter.drawRoundedRect(rect, xRadius, yRadius);

// ~~~ 新增如下代码 ~~~
painter.setPen(QPen(Qt::darkYellow, 1, Qt::DashLine));
painter.drawEllipse(QRectF(rect.left(), rect.top(), xRadius * 2, yRadius * 2));

painter.drawEllipse(QRectF(rect.right() - xRadius * 2, rect.bottom() - yRadius * 2, xRadius * 2, yRadius * 2));
}

七、椭圆上的一段线

7.1 弧线(Arc)

使用 drawArc 方法可以绘制一段弧线:

1
2
3
4

void drawArc(const QRectF &rectangle, int startAngle, int spanAngle)
void drawArc(const QRect &rectangle, int startAngle, int spanAngle)
void drawArc(int x, int y, int width, int height, int startAngle, int spanAngle)

在前面介绍的椭圆绘制方法中,我们通过指定一个矩形区域就可以绘制一个椭圆,而 drawArc 方法绘制曲线的则是该椭圆上的某一段弧线。通过 startAngle 参数指定弧线的起始角度,spanAngle 参数指定弧线所跨越的角度。

需要注意:

在 QPainter 的绘图函数中指定角度(不是弧度)时,以正三点钟方向为 0 度,角度按逆时针方向增长,整个圆按 5760 度计算(即 16 * 360)。

下面的示例绘制一段红色的弧线,弧线从 30 度方向开始,弧线跨越了 120 度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void Qt2DSample::paintEvent(QPaintEvent* e) {
QPainter painter(this);
painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);

QRectF rect(50, 50, 300, 200);

// 浅灰色的矩形
painter.setPen(Qt::lightGray);
painter.drawRect(rect);

// 蓝色的椭圆
painter.setPen(Qt::blue);
painter.drawEllipse(rect);

// 红色的弧线
painter.setPen(Qt::red);
painter.drawArc(rect, 30 * 16, 120 * 16);
}

实际绘制效果如下图所示:

从上图可以看到,弧线实际是椭圆上的某一段曲线。

7.2 饼状图(Pie)

使用 drawPie 可以绘制饼状图,饼状图是在上面弧线(Arc)的基础上,分别将弧线的首尾与中心点相连而来,因此 drawPie 方法的参数也与 drawArc 方法一样。

QPainter 在绘制饼状图时,会使用当前的画刷填充饼状图。

下面的示例绘制了一个具有红色轮廓、黄色填充的饼状图。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void Qt2DSample::paintEvent(QPaintEvent* e) {
QPainter painter(this);
painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);

QRectF rect(50, 50, 300, 200);

// 浅灰色的矩形
painter.setPen(Qt::lightGray);
painter.drawRect(rect);

// 蓝色的椭圆
painter.setPen(Qt::blue);
painter.drawEllipse(rect);

// 饼状图:红色的轮廓,黄色的填充
painter.setPen(Qt::red);
painter.setBrush(Qt::yellow);
painter.drawPie(rect, 30 * 16, 120 * 16);
}

7.3 和弦图(Chrod)

此处将 Chrod 按照英文直译成“和弦”可能不太准确

和弦图(Chrod)与饼状图(Pie)一样,也是在弧线的基础上变化而来,将弧线的首尾相接就可得到和弦图(Chrod)。

使用 drawChord 方法可以绘制和弦图,drawChord 方法的参数与 drawArc 一样。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void Qt2DSample::paintEvent(QPaintEvent* e) {
QPainter painter(this);
painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);

QRectF rect(50, 50, 300, 200);

// 浅灰色的矩形
painter.setPen(Qt::lightGray);
painter.drawRect(rect);

// 蓝色的椭圆
painter.setPen(Qt::blue);
painter.drawEllipse(rect);

// 和弦图:红色的轮廓,黄色的填充
painter.setPen(Qt::red);
painter.setBrush(Qt::yellow);
painter.drawChord(rect, 30 * 16, 120 * 16);
}

八、路径

前面介绍了线、矩形、椭圆、圆、弧线、饼状图等形状,路径则是由若干个这些形状(不限于这些形状)组成的一个集合,路径可以是闭合的,也可以不闭合。

在Qt中使用QPainterPath对象来定义一个路径,并使用如下方法向路径中添加形状:

  • addEllipse 添加一个椭圆或圆到路径中
  • addRect 添加一个矩形到路径中
  • addRoundedRect 添加一个圆角矩形到路径中
  • addText 将用指定字体绘制的文件所形成的闭合形状添加到路径中
  • lineTo 添加一条直线到路径中
  • arcTo 添加一段圆弧到路径中
    arcTo 的原型如下,和 drawArc 方法类似,也需要指定起始角度和跨越角度,但与drawArc 方法不同的是,arcTo 方法指定的角度是以360度整圆计算的,因此不需要乘以 16。
    1
    void QPainterPath::arcTo(const QRectF &rectangle, qreal startAngle, qreal sweepLength)
  • cubicTo 添加一个三次贝塞尔曲线到路径中
  • quadTo 添加一个二次贝塞尔曲线到路径中

在上面方法中,命名格式为“To”的方法,如 lineTo、arcTo、quadTo 等,都是基于“当前位置”来添加形状的,默认的当前位置为当前的*坐标原点 (0,0) 处,我们可以使用 QPainterPath::currentPosition 方法获取当前位置。

我们知道可以通过 QPainter::translate 等方法变换逻辑坐标,QPainterPath 的当前位置也会受逻辑坐标变换的影响。

在使用 lineTo 添加直线到路径中时,只有指定直线的结束点,会自动将当前位置与结束点相连,形成一条直线,并重设当前位置为该结束点。

在使用 arcTo、cubicTo、quadTo 添加曲线到到路径中时,会自动将当前位置与曲线起点相连,并重设当前位置为曲线结束点。

我们使用一个示例来说明当前位置和结束点的关系,下面示例先添加一条直线,然后添加一个曲线,最好再添加一条直线:

1
2
3
4
5
6
7
8
9
10
11
12
// 示例:当前位置
void Qt2DSample::paintEvent(QPaintEvent* e) {
QPainter painter(this);
painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);

QPainterPath path;
path.lineTo(80, 50);
path.arcTo(QRectF(50, 50, 300, 200), 30, 120);
path.lineTo(200, 200);

painter.drawPath(path);
}

实际效果如下图所示:

8.1 填充规则

路径可以是闭合的也可以是非闭合的,例如上面的当前位置示例中的路径是非闭合的,但如果为 QPainter 指定了画刷,QPainter 会自动使用一条直线连接该非闭合形状的首尾,使其闭合,进而使用画刷对其填充。

QPainterPath 有两种填充规则,可以通过QPainterPath::setFillRule方法来设置填充规则:

  • Qt::OddEvenFill

    奇偶填充规则,从一点向图形外引一条水平线,该线和图形的边线相交,如果交点的个数为奇数,则该点在图形中。

  • Qt::WindingFill
    非零弯曲规则,从一点向图形外引一条水平线,该线与图形的边线相交。如果边线是顺时针绘制的,则记为1,如果边线是逆时针绘制的,则记为-1。最后将所有结果相加的和为0则该点在图形中。(矩形和椭圆都按顺时针绘制)

九、文本

文字有颜色、字体、样式等属性。

Qt 不仅可以绘制纯色的文本,还可以使用渐变色、图片等内容来填充文字,比如下面两种方式都可以用来绘制渐变色的文字:

  1. 先将文字转变成路径(参考QPainterPath::addText),然后使用渐变画刷填充该路径。
  2. 直接为 QPen 设置渐变画刷。

通过为 QPainter 设置 QFont 对象来修改字体,字体有字体族、字号、粗体、斜体、下划线、删除线等样式或效果:

1
2
3
4
5
6
7
8
9
QFont font;
font.setFamilies({"Microsoft YaHei", "Arial"}); // 字体族
font.setPixelSize(26); // 字号
font.setBold(true); // 粗体
font.setItalic(true); // 斜体
font.setUnderline(true); // 下划线
font.setStrikeOut(true); // 删除线

painter.setFont(font);

使用 QPainter::drawText 方法绘制文本,该方法原型有很多种,但大多是通过下面2个原型进行重载而来的:

1
2
void QPainter::drawText(const QRectF &rectangle, int flags, const QString &text, QRectF *boundingRect = nullptr)
void QPainter::drawText(const QRectF &rectangle, const QString &text, const QTextOption &option = QTextOption())

9.1 间距

间距分为两种情况:

  • 每个字符的间距,如单个英文字母或单个汉字的间距,称为 Letter Spacing。
  • 每个英文单词的间距,称为 Word Spacing。

9.1.1 单词间距

使用 QFont::setWordSpacing 和 QFont::wordSpacing 方法设置和获取单词的间距。

1
void QFont::setWordSpacing(qreal spacing)

当 setWordSpacing 参数大于0时,单词间距增加相应的像素;小于0时,间距减少相应的像素。

9.1.2 字符间距

使用 QFont::setLetterSpacing 和 QFont::letterSpacing 方法设置和获取字符的间距。

1
void QFont::setLetterSpacing(QFont::SpacingType type, qreal spacing)

字符间距支持百分比和绝对值两种设置方法,通过QFont::SpacingType枚举类型指定。

  • QFont::PercentageSpacing

    百分比方式。值为100时表示不做任何改变,200表示间距扩大到原来的一倍,-200表示间距缩小到原来的一倍。

  • QFont::AbsoluteSpacing

    绝对值方式,与设置单词间距的方式一样。

9.2 小型大写字母

小型大写字母(英语:small capitals,简称 small caps)是西文字体设计中的一种字符形式。这些字母的形状(字形)和大写字母相同但尺寸较小,比如在表示键盘快捷键的时候也常用小型大写字母。

在 Qt 中通过设置 QFont 的 Capitalization 样式为 SmallCaps 风格来使用小型大写字母样式,如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void Qt2DSample::paintEvent(QPaintEvent* e) {
QPainter painter(this);
painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);

QPen pen;
pen.setBrush(Qt::red);
pen.setWidthF(20);

QFont font;
font.setPixelSize(26);
font.setCapitalization(QFont::SmallCaps);
^^^^^^^^^^^^^

painter.setFont(font);
painter.drawText(10, 30, "The Keyboard Shortcut is Ctrl + Shift + K");
}

效果如下图所示(留意全小写的“is”和其他首字母大写的单词):

Capitalization 还支持设置如下风格:

  • QFont::MixedCase 默认,不做更改
  • QFont::AllUppercase 全部小写
  • QFont::AllLowercase 全部大写
  • QFont::Capitalize 首字母大写

9.3 计算绘制文本所需空间

有两种方式可以计算按指定字体绘制文本所需的空间。

方式一:使用 QPainter::drawText

使用如下函数原型:

1
void QPainter::drawText(const QRectF &rectangle, int flags, const QString &text, QRectF *boundingRect = nullptr)

将参数 rectangle 的 宽和高都设置为 0,函数会通过 boundingRect 参数返回绘制文本所需要的宽和高。

方式二:使用 QFontMetricsF

QFontMetrics 或 QFontMetricsF 可以按照指定字体来计算给定字符和字符串的宽和高。

这种方式的弊端在于:不能将绘制风格(如居中对齐、多行文本)带入其中进行计算,只能计算给定的单行字符串按照指定的字体显示所需的宽高。

1
2
3
4
5
6
QFont font;
font.setPixelSize(36);

QFontMetricsF fm(font);
qDebug() << fm.horizontalAdvance("Hello World"); // 字符串所占宽度
qDebug() << fm.height(); // 字体的高度

十、贴图

QPainter 提供了 drawPixmap 和 drawImage 两个常用的贴图函数,drawPixmap 用于绘制 QPixmap 对象,而 drawImage 用于绘制 QImage 对象,QImage 与 QPixmap 间是可以相互转化,因此 drawPixmap 和 drawImage 方法的效果是一样的。

drawPixmap 方法在屏幕上绘制速度更快,而 drawImage 方法则在 QPrinter 和其他设备上绘制的更快。

需要注意:QPicture 对象用于记录绘制步骤,而 QPainter::drawPicture 方法用于重复 QPicture 对象所记录的步骤。

drawPixmap 和 drawImage 方法有多个重载的原型,其参数从左到右依次为:

1
目标区域 -> QPixmap/QImage -> 源区域

目标区域会应用当前 QWidget 的 devicePixelRatio,而源区域则与 devicePixelRatio 无关,具体参考 QPixmap使用要点


限于政策原因,在您看到该文章时,博客可能已经关闭了评论功能🥺

您可以通过在 blog-comment 项目中提交Issue来间接地发表评论🍀