Qt技巧笔记(十):QPainter 详解与实践指南
1. QPainter 概述
QPainter是Qt框架中用于二维图形绘制的核心类,其提供了一套完整、强大的API来在各种绘制设备上进行图形操作。无论是简单的线条绘制还是复杂的图形变换,广泛用于自定义控件、绘制背景、图形编辑器等场景。由QPainter、QPaintDevice 、QPaintEngine三类共同构成了Qt强大的二维绘图系统。
- QPainter 用于执行绘图操作,其提供的API在GUI或QImage、QOpenGLPaintDevice、QWidget和QPaintDevice 显示图形(线、形状、渐变等),文本和图形。
- QPaintDevice 不直接绘制物理显示画图,而利用逻辑界面的中间媒介。例如,绘制矩形图形时,为了将对象绘制到QWidget、QGLPixelBuffer、QImage 、QPixmap、QPicture等多种界面中间,必须使用QPaintDevice。
- QPaintEngine 提供了一些接口,可用于QPainter在不同的设备上进行绘制。
绘图系统由 QPainter 完成具体的绘制操作,QPainter 类提供了大量高度优化的函数来完成 GUI 编程所需要的大部分绘制工作。它可以绘制一切想要的图形,从最简单的一条直线到其他任何复杂的图形,例如:点、线、矩形、弧形、饼状图、多边形、贝塞尔弧线等。此外,QPainter 也支持一些高级特性,例如反走样(针对文字和图形边缘)、像素混合、渐变填充和矢量路径等,QPainter 也支持线性变换,例如平移、旋转、缩放。
2. QPainter 绘制图形的常用方法
QPainter 的常用方法按照功能分类进行总结,方便你快速查阅和使用。
类别API接口参数含义功能说明基本类型drawPoint(int x, int y)x: 点的X坐标;
y: 点的Y坐标绘制单个点void drawPoint(const QPoint &p)p: 包含X和Y坐标的点对象绘制单个点void drawLine(int x1, int y1, int x2, int y2)x1,y1: 起点坐标;
x2,y2: 终点坐标绘制直线void drawLine(const QPoint &p1, const QPoint &p2)p1: 起点;p2: 终点绘制直线void drawLine(const QLine &line)line: 包含起点和终点的直线对象绘制直线void drawRect(int x, int y, int w, int h)x,y: 左上角坐标;w: 宽度;h: 高度绘制矩形 void drawRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode = Qt::AbsoluteSize)rect: 矩形区域;xRadius: X轴圆角半径;
yRadius: Y轴圆角半径;
mode: 半径单位模式(绝对尺寸或相对尺寸)绘制圆角矩形void drawEllipse(const QRectF &rect)center: 椭圆中心;rx: X轴半径;ry: Y轴半径绘制椭圆void drawEllipse(const QRectF &rect)rect: 椭圆的外接矩形绘制椭圆void drawEllipse(const QRect &rect)rect: 椭圆的外接矩形绘制椭圆void drawEllipse(int x, int y, int w, int h)x,y,w,h: 外接矩形的参数绘制椭圆void drawArc(const QRectF &rect, int startAngle, int spanAngle)ct: 弧所在椭圆的外接矩形;
startAngle: 起始角度(1/16度);
spanAngle: 跨越角度(1/16度)绘制弧线void drawPie(const QRectF &rect, int startAngle, int spanAngle)参数同上绘制扇形(包含圆心)void drawChord(const QRectF &rect, int startAngle, int spanAngle)rect: 弧所在椭圆的外接矩形;
startAngle: 起始角度(1/16度);
spanAngle: 跨越角度(1/16度)绘制弦(弧两端连线封闭)void drawChord(int x, int y, int w, int h, int startAngle, int spanAngle)同上绘制弦void drawPolygon(const QPolygonF &polygon, Qt::FillRule fillRule = Qt::OddEvenFill)polygon: 多边形顶点列表;
fillRule: 填充规则(
奇偶填充或弯曲填充)绘制多边形void drawPolygon(const QPolygon &polygon, Qt::FillRule fillRule = Qt::OddEvenFill)同上绘制多边形void drawConvexPolygon(const QPolygonF &polygon)polygon: 凸多边形顶点列表绘制凸多边形(效率更高)void drawConvexPolygon(const QPolygon &polygon)同上绘制凸多边形文本void drawText(const QPointF &pos, const QString &text)pos: 文本基线左端点;
text: 要绘制的文本绘制文本void drawText(int x, int y, const QString &text)x,y: 文本基线左端点坐标;
text: 文本绘制文本void drawText(const QRectF &rect, int flags, const QString &text, QRectF *boundingRect = nullptr)rect: 文本绘制区域;
flags: 对齐标志(如Qt::AlignCenter);
text: 文本;
boundingRect: 返回实际文本边界在矩形内绘制文本void drawText(const QRect &rect, int flags, const QString &text, QRect *boundingRect = nullptr)同上,使用整数矩形在矩形内绘制文本void drawText(int x, int y, int w, int h, int flags, const QString &text, QRect *boundingRect = nullptr)x,y,w,h: 矩形参数;
其余同上在矩形内绘制文本QRectF boundingRect(const QRectF &rect, int flags, const QString &text)参数同上,无boundingRect输出参数;
返回计算出的文本边界矩形计算文本边界QRect boundingRect(const QRect &rect, int flags, const QString &text)同上计算文本边界图像与像素图void drawImage(const QPointF &point, const QImage &image)point: 图像左上角放置位置;
image: 要绘制的图像绘制QImage的指定区域到目标区域void drawImage(const QRectF &target, const QImage &image, const QRectF &source, Qt::ImageConversionFlags flags = Qt::AutoColor)target: 目标区域(可能缩放); image: 源图像;
source: 源图像中要绘制的子区域;flags: 颜色转换选项绘制QPixmapvoid drawPixmap(const QRectF &target, const QPixmap &pixmap, const QRectF &source)target: 目标区域;pixmap: 源像素图;source: 源图像中要绘制的子区域绘制QPixmap指定区域到目标区域void drawTiledPixmap(const QRectF &rect, const QPixmap &pixmap, const QPointF &offset = QPointF())rect: 要平铺填充的目标区域;
pixmap: 平铺用的像素图;
offset: 平铺起始偏移平铺绘制像素图复杂路径void drawPath(const QPainterPath &path)path: 包含直线、曲线等子路径的路径对象绘制复杂路径填充与擦除void fillRect(const QRectF &rect, const QBrush &brush)rect: 要填充的矩形;
brush: 画刷(定义颜色、样式、渐变等)填充矩形void fillRect(int x, int y, int w, int h, const QColor &color)x,y,w,h: 矩形参数;color: 填充颜色填充矩形void fillRect(const QRect &rect, Qt::GlobalColor color)rect: 矩形;color: 全局颜色枚举(如Qt::red)填充矩形void eraseRect(const QRectF &rect)rect: 要擦除的矩形区域擦除矩形(用背景色填充)void eraseRect(int x, int y, int w, int h)x,y,w,h: 矩形参数擦除矩形状态与变换void save()无参数保存当前画家状态(画笔、画刷、变换等)void restore()无参数恢复上次保存的画家状态void translate(qreal dx, qreal dy)dx: X轴偏移量;dy: Y轴偏移量平移坐标系void translate(const QPointF &offset)offset: 包含dx和dy的偏移向量平移坐标系void rotate(qreal angle)angle: 旋转角度(度,顺时针为正)旋转坐标系void scale(qreal sx, qreal sy)sx: X轴缩放因子;sy: Y轴缩放因子缩放坐标系void shear(qreal sh, qreal sv)sh: 水平剪切因子;sv: 垂直剪切因子剪切坐标系void setRenderHint(RenderHint hint, bool on = true)hint: 渲染提示枚举(如Antialiasing);on: 启用或禁用设置渲染选项注意:在默认情况下,QPainter 使用的坐标系非常简单直接:
- 原点 (Origin):位于绘图设备(如QWidget窗口、QPixmap等)的左上角 (0, 0)。
- X轴方向:水平向右,数值递增。
- Y轴方向:垂直向下,数值递增。
- 单位 (Unit):在基于像素的设备(如屏幕)上,1个单位代表 1个像素;在打印机上,1个单位代表1个点(1/72 英寸)。
这种设计符合屏幕显示的常规认知。
3. QPainter 的基本使用详解
3.1 初始化与资源管理
QPainter 必须在绘制设备(QPaintDevice 的子类,如 QWidget、QPixmap、QImage 等)上工作。初始化即建立 QPainter 与设备的关联。- // 在QPixmap上绘制
- QPixmap pixmap(200, 200);
- pixmap.fill(Qt::white);
- {
- QPainter painter(&pixmap); // 自动开始绘制
- // 绘制操作
- } // 自动结束绘制,资源释放
- // 在QWidget的paintEvent中
- void MyWidget::paintEvent(QPaintEvent *event)
- {
- QPainter painter(this); // this指向当前widget
- // 绘制操作
- }
复制代码 3.2 通过Qpen 画笔设置样式的例子
在 Qt 中,QPen 定义了绘制线条和轮廓线的样式。通过 QPen 可以设置线的颜色、宽度、线型(实线、虚线等)、笔帽样式(端点形状)以及连接样式(折线连接处的形状)。下面通过完整的示例展示如何使用 QPen 设置各种样式。- QPen pen;
- pen.setColor(QColor(255, 0, 0)); // 红色
- pen.setWidth(3); // 3像素宽度
- pen.setStyle(Qt::DashLine); // 虚线样式
- pen.setCapStyle(Qt::RoundCap); // 线端圆角
- painter.setPen(pen);
复制代码 完整案例:绘制不同笔样式的线段- #include <QPainter>
- #include <QWidget>
- #include <QApplication>
- class PenDemoWidget : public QWidget
- {
- protected:
- void paintEvent(QPaintEvent *event) override
- {
- QPainter painter(this);
- painter.setRenderHint(QPainter::Antialiasing); // 抗锯齿让线条平滑
- // 设置坐标和间隔
- int y = 30;
- int step = 30;
- // 1. 默认实线
- QPen pen1;
- painter.setPen(pen1);
- painter.drawLine(20, y, 300, y);
- painter.drawText(310, y+5, "SolidLine (default)");
- y += step;
- // 2. 红色虚线,宽度2
- QPen pen2(Qt::red, 2, Qt::DashLine);
- painter.setPen(pen2);
- painter.drawLine(20, y, 300, y);
- painter.drawText(310, y+5, "DashLine");
- y += step;
- // 3. 蓝色点线,宽度3,圆帽
- QPen pen3;
- pen3.setColor(Qt::blue);
- pen3.setWidth(3);
- pen3.setStyle(Qt::DotLine);
- pen3.setCapStyle(Qt::RoundCap);
- painter.setPen(pen3);
- painter.drawLine(20, y, 300, y);
- painter.drawText(310, y+5, "DotLine + RoundCap");
- y += step;
- // 4. 绿色点划线,宽度2,方形帽
- QPen pen4(QBrush(Qt::green), 2, Qt::DashDotLine);
- pen4.setCapStyle(Qt::SquareCap);
- painter.setPen(pen4);
- painter.drawLine(20, y, 300, y);
- painter.drawText(310, y+5, "DashDotLine + SquareCap");
- y += step;
- // 5. 自定义虚线模式
- QPen pen5;
- pen5.setColor(Qt::magenta);
- pen5.setWidth(2);
- QVector<qreal> dashes;
- dashes << 5 << 2 << 10 << 2; // 画5空2画10空2
- pen5.setDashPattern(dashes);
- pen5.setStyle(Qt::CustomDashLine);
- painter.setPen(pen5);
- painter.drawLine(20, y, 300, y);
- painter.drawText(310, y+5, "CustomDash (5,2,10,2)");
- y += step;
- // 6. 连接样式演示:绘制折线
- y += 30;
- painter.setPen(QPen(Qt::darkYellow, 8, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin));
- drawPoly(&painter, y, "MiterJoin"); y += 80;
- painter.setPen(QPen(Qt::darkYellow, 8, Qt::SolidLine, Qt::FlatCap, Qt::BevelJoin));
- drawPoly(&painter, y, "BevelJoin"); y += 80;
- painter.setPen(QPen(Qt::darkYellow, 8, Qt::SolidLine, Qt::FlatCap, Qt::RoundJoin));
- drawPoly(&painter, y, "RoundJoin");
- }
- void drawPoly(QPainter *painter, int yOffset, const QString &label)
- {
- QPolygon poly;
- poly << QPoint(50, yOffset) << QPoint(150, yOffset+30) << QPoint(250, yOffset-20);
- painter->drawPolyline(poly);
- painter->drawText(260, yOffset+5, label);
- }
- };
- int main(int argc, char *argv[])
- {
- QApplication app(argc, argv);
- PenDemoWidget w;
- w.resize(500, 500);
- w.show();
- return app.exec();
- }
复制代码 6. QPainter 总结
QPainter作为Qt图形系统的核心,提供了强大而灵活的二维图形绘制能力。通过掌握其基本用法和高级特性,开发者可以实现从简单的UI元素到复杂的数据可视化等各种图形需求。关键在于理解其状态机模型和坐标系变换机制,结合合理的优化策略,就能创造出既美观又高效的图形应用程序。无论是桌面应用、嵌入式界面还是数据可视化项目,QPainter都是Qt开发者不可或缺的强大工具。希望本文能帮助读者深入理解并有效运用这一重要的图形绘制框架。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |