Qt2D绘图详解

2D绘图简介

为什么要2D绘图

在Qt界面编程中,通常会遇到使用Qt自带控件不能解决的问题,这时2D绘图给我们提 供了专用定制化的工具

QPainter介绍

2D绘图离不开QPainter,可以把QPainter想象成一个画笔,开发人员拿着画笔理论上 是可以绘制任何你想要的图形。QPainter 一般在一个部件(widget)重绘事件( PaintEvent )的处理函数paintEvent ()中进行绘制,首先要创建QPainter 对象(画 笔),然后进行图形的绘制

QPainter中常用的图形绘制函数

  • drawArc() 弧
  • drawChord()弦
  • drawConvexPolygon() 凸多边形
  • drawEllipse() 椭圆,注意椭圆是先整个框,然后逼近…
  • drawImage() 图像
  • drawLine() 线
  • drawLines() 多条线
  • drawPath() 路径; 想到哪就去哪,但是必须是直的
  • drawPicture() 按QPainter指令绘制 区分drawImage、drawPixmap,大家可以试一把
  • drawPie() 扇形
  • drawPixmap() 图像
  • drawPoint() 点
  • drawPoints() 多个点
  • drawPolygon() 多边形
  • drawPolyline() 多折线
  • drawRect() 矩形
  • drawRects() 多个矩形
  • drawRoundRect() 圆角矩形
  • drawText() 文字
  • drawTiledPixmap() 平铺图像
  • drawLineSegments() 绘制折线

画笔(QPen)与画刷(QBrush)

QPen

QPen定义了用于QPainter应该怎样画线或者轮廓线。画笔具有样式style() 、宽 度width() 、画刷brush() 、笔帽样式capStyle()和连接样式joinStyle()等属性。画笔的样式style()定义了线的样式。画刷brush()用于填充画笔所绘制的线条。笔帽 样式capStyle()定义了使用QPainter绘制的线的末端;连接样式joinStyle()则定义 了两条线如何连接起来。画笔宽度width()或widthF()定义了画笔的宽。注意,不 存在宽度为 0 的线。假设你设置 width 为 0,QPainter依然会绘制出一条线,而 这个线的宽度为 1 像素。也就是说,画笔宽度通常至少是 1 像素。

QBrush

QBrush 类提供了画刷来对图形进行填充, 一个画刷具有样式(style)、颜色 (color)、渐变( gradient )、文理(texture)四个可设置属性。 可能用到Brush的样式、颜色、填充方式 (后两者是重点) const QColor &QBrush::color() const 获取当前Brush颜色 void QBrush::setColor(const QColor &color) 设置当前Brush颜色
渐变( gradient )定义了渐变填充。当创建Qbrush时,可以在构造函数中传入一个渐变 画笔对象用于构建画刷的渐变样式

paintEvent调用时机

什么时候paintEvent时间会产生?

  • 窗口隐藏 显示 show
  • 窗口放大 缩小 resize
  • 调用update
  • 调用repaint

坐标系及窗口移动原理

三个坐标系的关系

  • windowDeskTopLeft 是指窗口到显示器左上角的坐标
    windowDeskTopLeft = this‐>geometry().topLeft()
  • mouseDeskTopLeft 是指鼠标(光标)到显示器左上角的坐标
    mouseDeskTopLeft = event‐>globalPos();
  • mouseWindowTopLeft 是指鼠标(光标)到窗口左上角的坐标
    mouseWindowTopLeft = event‐>pos();

它们三者的关系是(矢量相减): windowDeskTopLeft = mouseDeskTopLeft ­ mouseWindowTopLeft;

窗口移动的坐标系关系
  • step1 记录鼠标左键按下时的mouseWindowTopLeft (响应mousePressEvent事件)
  • step2 鼠标移动时实时记录mouseWindowTopLeft (实时响应mouseMoveEvent事件, 需要setMouseTracking(true))
  • step3 在mouseMoveEvent中实时算出windowDeskTopLeft,并将窗口移动到该位置
    通过公式 windowDeskTopLeft = mouseDeskTopLeft ­ mouseWindowTopLeft; 计 算而来。 PS:在 中需要使用if (event­>buttons() & Qt::LeftButton)对左键进行过滤,不然鼠 标移动到哪里,不用按下左键窗口都会跟着走

QPainter中scale

  • scale参数 (同比例缩放)
    scale(qreal sx, qreal sy)
    sx = x方向scale的倍数
    sy = y方向scale的倍数

QPainter中的save 和 restore

在2D绘制中经常遇到画笔坐标轴移动 画笔换色等等操作,在切换另一种操作前,需要 先save一次,完成后再restore一次。

QPainter 2D绘制基础实例

绘制文字

void Widget::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);
    painter.begin(this);
    painter.setPen(QColor(255, 10, 10)); //设置颜色
    font.setFamily("Microsoft YaHei");
    font.setPointSize(66); //字体大小
    font.setItalic(true); //斜体
    painter.setFont(font); //使字体生效
    painter.drawText(rect(), Qt::AlignCenter, "Hello Man!");
    painter.end();
}

绘制直线

void Widget::paintEvent(QPaintEvent *event)
{   // 绘制直线
    Q_UNUSED(event);
    painter.begin(this);
    painter.setPen(QColor(255, 10, 10)); //设置颜色
    painter.setPen(QPen(QColor(255,10,10), 9)); //可以设置线宽度
    painter.setRenderHint(QPainter::Antialiasing, true); //设置 反锯齿
    painter.drawLine(QPointF(0, this->height()), //画直线
                     QPointF(this->width() / 2,
                             this->height() / 2)); //QPointF 装起点坐标 终点坐标
    painter.end();
}

绘制矩形

void Widget::paintEvent(QPaintEvent *event)
{   // 绘制矩形
    Q_UNUSED(event);
    painter.begin(this);
    //设置 反锯齿
    painter.setRenderHint(QPainter::Antialiasing, true);
    //设置笔的颜色、宽度
    painter.setPen(QPen(QColor(0, 160, 230), 9));
    //设置笔刷颜色
    //    painter.setBrush(QColor(255, 160, 90));
    //画直线
    painter.drawRect(50, 50, 100, 100);
    painter.end();
}

绘制弧形

首先需要有个位置矩形,何为“位置矩形”,就是用来装这个弧的

void Widget::paintEvent(QPaintEvent *event)
{   // 绘制弧形
    Q_UNUSED(event);
    // 矩形
    QRectF rect(90.0,90.0,80.0,90.0);
    int startAngle = 30*16;
    // 跨度系数
    int spanAngle = 120 * 16;
    painter.begin(this);
    //设置 反锯齿
    painter.setRenderHint(QPainter::Antialiasing, true);
    //设置笔的颜色、宽度
    painter.setPen(QPen(QColor(0, 160, 230), 9));
    //设置笔刷颜色
    //    painter.setBrush(QColor(255, 160, 90));
    //drawArc 三个参数:起始角度、跨度、位置矩阵
    // 注意角度被分成了十六分之 一,就是说,如果要 30 度,就需是 30*16
    // 正数角度表示逆时针方向,负数表示顺时针方向,0表示正三点位置
    painter.drawArc(rect,startAngle,spanAngle);
    painter.end();
}

绘制椭圆

基本知识:椭圆也是框在矩形里面

void Widget::paintEvent(QPaintEvent *event)
{   // 绘制字体
    Q_UNUSED(event);
    painter.begin(this);

    // 设置反锯齿
    painter.setRenderHint(QPainter::Antialiasing,true);
    // 设置笔的颜色宽度
    painter.setPen(QPen(QColor(0,0,0),4));

    QRectF rect(10.0,20.0,80.0,60.0);
    painter.drawEllipse(rect); // 画圆

	// X轴Y轴 宽 高
    QRectF rect_2(60.0,80.0,100.0,100.0);
    painter.drawRect(rect_2); // 画矩形
    painter.drawEllipse(rect_2); // 画圆

    painter.end();
}

绘制多边形

void Widget::paintEvent(QPaintEvent *event)
{
    // 绘制多边形
    static const QPointF point[4] ={
        QPointF(10.0,80.0),
        QPointF(20.0,10.0),
        QPointF(80.0,30.0),
        QPointF(90.0,70.0)
    };
    
    // 代替了上面的begin 和 end
    QPainter paint(this);
    paint.drawConvexPolygon(point,4);
}

绘制路径

经典的贝塞尔曲线

void Widget::paintEvent(QPaintEvent *event)
{
    // 绘制路径
    QPainterPath path;
    path.addRect(20,20,60,60); // 添加矩形

    path.moveTo(0,0); // 设置起点
    path.cubicTo(99,0,50,50,99,99); // 绘制上贝塞尔曲线
    path.cubicTo(0,99,50,50,0,0); // 绘制下贝塞尔曲线
    // 两种不同的填充模式,一个是全部填充 一个是去除重复
    path.setFillRule(Qt::OddEvenFill);

    painter.begin(this);
    painter.fillRect(0,0,100,100,Qt::white); // 填充矩形
    painter.setPen(QPen(QColor(43,65,89),5,Qt::SolidLine,Qt::FlatCap
                        ,Qt::MiterJoin));// 设置画笔
    painter.setBrush(QColor(122,163,34)); // 设置笔刷颜色
    painter.drawPath(path);

    painter.end();
}

绘图的三种方式

  • drawImage
  • drawPixmap
  • drawPicture
void Widget::paintEvent(QPaintEvent *event)
{
    QPainter painter;
    // 绘制image
    QImage image(100, 100, QImage::Format_ARGB32);
    painter.begin(&image);
    painter.setPen(QPen(Qt::green, 3));
    painter.setBrush(Qt::yellow);
    painter.drawRect(10, 10, 60, 60);
    painter.drawText(10, 10, 60, 60, Qt::AlignCenter, tr("QImage"));
    painter.setBrush(QColor(0 , 0, 0, 100));
    painter.drawRect(50, 50, 40, 40);
    painter.end();
    // 绘制pixmap
    QPixmap pix(100, 100);
    painter.begin(&pix);
    painter.setPen(QPen(Qt::green, 3));
    painter.setBrush(Qt::yellow);
    painter.drawRect(10, 10, 60, 60);
    painter.drawText(10, 10, 60, 60, Qt::AlignCenter, tr("QPixmap"));
    painter.setBrush(QColor(0 , 0, 0, 100));
    painter.drawRect(50, 50, 40, 40);
    painter.end();
    // 绘制bitmap
    QBitmap bit(100, 100);
    painter.begin(&bit);
    painter.setPen(QPen(Qt::green, 3));
    painter.setBrush(Qt::yellow);
    painter.drawRect(10, 10, 60, 60);
    painter.drawText(10, 10, 60, 60, Qt::AlignCenter, tr("QBitmap"));
    painter.setBrush(QColor(0 , 0, 0, 100));
    painter.drawRect(50, 50, 40, 40);
    painter.end();
    // 绘制picture
    QPicture picture;
    painter.begin(&picture);
    painter.setPen(QPen(Qt::green, 3));
    painter.setBrush(Qt::yellow);

    painter.drawRect(10, 10, 60, 60);
    painter.drawText(10, 10, 60, 60, Qt::AlignCenter, tr("QPicture"));
    painter.setBrush(QColor(0 , 0, 0, 100));
    painter.drawRect(50, 50, 40, 40);
    painter.end();
    // 在widget部件上进行绘制
    painter.begin(this);
    painter.drawImage(50, 20, image);
    painter.drawPixmap(200, 20, pix);
    painter.drawPixmap(50, 170, bit);
    painter.drawPicture(200, 170, picture);
}

抗锯齿(反走样)

抗锯齿( Anti­aliased)又称为反锯齿或者反走样,就是对图像的边缘进行平滑处 理,使其看起来更加柔和流畅的一种技术。QPaint er 进行绘制时可以使用QPainter ::RenderHint 渲染提示来指定是否要使用抗锯齿功能,RenderHint 取值分为以下三
种。

常量描述
QPainter::Antialiasing边缘抗锯齿
QPainter::TextAntialiasing文字抗锯齿
QPainter::SmoothPixmapTransform平滑pixmap转换算法抗锯齿

ps :绘制直线演示了 Antialiasing 绘制文字可以使用 TextAntialiasing 转盘演示了 SmoothPixmapTransform

渐变与填充

QLinearGradient:显示从起点到终点的渐变

QRadialGradient:以圆心为中心显示渐变

QConicalGradient:围绕一个中心点显示渐变

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

√沫影

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值