Qt 2D绘图之一:基本图形绘制和渐变填充

Qt中提供了强大的2D绘图系统,可以使用相同的API在屏幕和绘图设备上进行绘制,它主要基于QPainter、QPaintDevice和QPaintEngine这三个类。它们三者的关系如下图所示:

img

  • QPainter用来执行绘图操作;
  • QPaintEngine提供了一些接口,可以用于QPainter在不同的设备上进行绘制;
  • QPaintDevice提供绘图设备,它是一个二维空间的抽象,可以使用QPainter在其上进行绘制。

绘图系统中由QPainter来完成具体的绘制操作,提供了大量髙度优化的函数来完成GUI编程所需要的大部分绘制工作。QPainter可以绘制一切想要的图形,从最简单的一条直线到其他任何复杂的图形,还可以用来绘制文本和图片。QPainter可以在继承自QPaintDevice类的任何对象上进行绘制操作。

QPainter—般在一个部件重绘事件( PaintEvent )的处理函数paintEvent ()中进行绘制,首先要创建QPainter对象(画笔),然后进行图形的绘制, 最后销毁QPainter对象。



一、基本图形的绘制

在QPainter中提供了一些方便的函数来绘制常用的图形,而且还可以设置线条和边框的画笔以及进行填充的画刷。

新建Qt Gui应用,项目名称为 myDrawing,基类选择QMainWindow,类名为MainWindow。建立完成后,在MainWindow.h文件中声明重绘事件处理函数:

protected:
    void paintEvent(QPaintEvent *event);

然后到MainWindow.cpp文件中添加头文件#include <QPainter>。



1.1 绘制图形

在MainWindow.cpp文件中对paintEvent()函数进行如下定义:

void Widget::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    //绘制线条
    painter.drawLine(QPoint(0, 0), QPoint(100, 100));
}

这里先创建了—个QPainter 对象,使用了QPainter::QPainter(QPaintDevice *device)构造函数,并指定了this为绘图设备,即表明在该部件上进行绘制。使用这个构造函数创建的对象会立即开始在设备上绘制,自动调用begin()函数,然后在QPainter的析构函数中调用end()函数结束绘制。

如果在构建QPainter对象时不想指定绘制设备,那么可以使用不带参数的构造函数,然后使用QPainter:: begin (QPaintDevice *device)在开始绘制时指定绘制设备,等绘制完成后再调用end()函 数结束绘制。上面函数中的代码等价于:

QPainter painter;
painter.begin(this);
painter.drawLine(QPoint(0, 0), QPoint(100, 100));
painter.end();

这两种方式都可以完成绘制,无论使用哪种方式,都要指定绘图设备,否则将无法进行绘制。第二行代码使用drawLine()函数绘制了一条线段,这里使用了该函数的一种重载形式QPainter::drawLine ( const QPoint & p1, const QPoint & p2 )其中p1和p2分别是线段的起点和终点。这里的QPoint(0, 0)就是窗口的原点,默认是窗口的左上角(不包含标题栏)。效果如下图所示。

11-1.jpg



除了绘制简单的线条以外,QPainter中还提供了一些绘制其他常用图形的函数, 其中最常用的几个如下表所示。

函数 功能
drawArc() 绘制圆弧
drawChord() 绘制弦
drawConvexPolygon() 绘制凸多边形
drawEllipse() 绘制椭圆
drawLine() 绘制线条
drawPie() 绘制扇形
drawPoint() 绘制点
drawPolygon() 绘制多边形
drawPolyline() 绘制折线
drawRect() 绘制矩形
drawRoundedRect() 绘制圆角矩形

另外我们将光标定位到QPainter类名上,然后按下键盘上的F1按键,这时会自动跳转到该类的帮助页面。当然,也可以到帮助模式,直接索引查找该类名。在帮助里面我们可以看到很多相关的绘制函数,如下图所示。

11-2.jpg

我们任意点击一个函数名,就会跳转到该函数的介绍段落。例如我们点击drawEllipse()函数,就跳转到了该函数的介绍处,上面还提供了一个例子。如下图所示。我们可以直接将例子里面的代码复制到paintEvent()函数里面,测试效果。

11-3.jpg



1.2 使用画笔

QPen定义了用于QPainter应该怎样画线或者轮廓线。画笔具有样式style() 、宽度width() 、画刷brush() 、笔帽样式capStyle()和连接样式joinStyle()等属性。先介绍QPen类的构造函数:

QPen(const QBrush &brush, qreal width, Qt::PenStyle s = Qt::SolidLine,
         Qt::PenCapStyle c = Qt::SquareCap, Qt::PenJoinStyle j = Qt::BevelJoin);
  • 画刷brush()用于填充画笔所绘制的线条。
  • 画笔的样式style()定义了线的样式。
  • 笔帽样式capStyle()定义了使用QPainter绘制的线的末端;
  • 连接样式joinStyle()则定义了两条线如何连接起来。
  • 画笔宽度width()或widthF()定义了画笔的宽。注意,不存在宽度为 0 的线。假设你设置 width 为 0,QPainter依然会绘制出一条线,而这个线的宽度为 1 像素。

这么多参数既可以在构造时指定,也可以使用 set 函数指定,完全取决于你的习惯。使用setWidth(),setBrush(),setCapStyle()和setJoinStyle()函数可以轻松修改各种设置。

画笔样式

11-5.jpg



再将paintEvent()函数的内容更改如下:

void MainWindow::paintEvent(QPaintEvent *event)
{
    //创建画笔
    QPen pen(Qt::green, 5, Qt::DotLine, Qt::RoundCap, Qt::RoundJoin);
    //使用画笔绘制圆弧
    painter.setPen(pen);
    QRectF rectangle(70.0, 40.0, 80.0, 60.0);
    int startAngle = 30 * 16;
    int spanAngle = 120 * 16;
    painter.drawArc(rectangle, startAngle, spanAngle);
}

上面创建完画笔后,使用了setPen()来为painter设置画笔,然后使用画笔绘制了一个圆弧。绘制圆弧函数的一种重载形式为QPainter::drawArc ( const QRectF & rectangle, int startAngle, int spanAngle ),这里的三个参数分别对应于需要指定弧线所在的矩形、起始角度和跨越角度,如下图所示。

QRectF:: QRectF (qreal x, qreal y, qreal width, qreal height)可以使用浮点数为参数来确定一个矩形,它需要指定左上角的坐标(x,y)、宽width和髙height。如果只想使用整数来确定一个矩形,那么可以使用QRect类。这里角度的数值为实际度数乘以16,在时钟表盘中,0度指向3时的位置,角度数值为正则表示逆时针旋转,角度数值为负则表示顺时针旋转,整个一圈的数值为5760(即360X16)。

img



1.3 使用画刷

QBrush类提供了画刷来填充图形,一个画刷使用它的颜色和风格(例如它的填充模式)来定义。先介绍QBrush类的构造函数:

QBrush(const QColor &color, Qt::BrushStyle bs=Qt::SolidPattern);

在Qt中使用的颜色一般都由QColor类来表示,它支持RGB、HSV和CMYK等颜色模型。里面如果是三个参数,那么分别是红、绿、蓝分量的值,也就是经常说的rgb,取值范围都是0-255,比如这里的(255, 0, 0)就表明红色分量为255,其他分量为0,那么出来就是红色。如果是四个参数,最后一个参数alpha是设置透明度的,取值范围也是0-255,0表示完全透明,而255表示完全不透明。在Qt中还提供了20种预定义的颜色,如下图所示。

11-7.jpg

QBrush样式的填充模式使用Qt::BrushStyle枚举变量来定义,包含了基本模式填充、渐变填充和纹理填充,所有枚举变量如下图所示。默认的风格是Qt :: NoBrush(取决于你如何构建画笔),不填充形状。标准的填充风格是Qt :: SolidPattern。设置画刷风格的方式有两种,一种是利用构造函数,另外一种是利用setstyle函数。

img



再将paintEvent()函数的内容更改如下:

void MainWindow::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    QPen pen; //画笔
    pen.setColor(QColor(255, 0, 0));
    QBrush brush(QColor(0, 255, 0, 125)); //画刷
    painter.setPen(pen); //添加画笔
    painter.setBrush(brush); //添加画刷
    painter.drawRect(50, 50, 200, 100); //绘制矩形
}

这里分别新建了一个画笔QPen和画刷QBrush。其中画笔使用了setColor()函数为其设置了颜色,而画刷是在构建的时候直接为其设置的颜色。然后我们将画笔和画刷设置到了painter上,并使用drawRect()绘制了一个矩形,其左上角顶点在(50, 50),宽为200,高为100。运行程序,效果如下图所示。

11-4.jpg



二、渐变填充

在画刷中也可以使用渐变填充。QGradient类就是用来和QBrush一起指定渐变填充的。Qt现在支持三种类型的渐变填充:

  • 线性渐变(linear gradient)在开始点和结束点之间插入颜色;
  • 辐射渐变(radial gradient)在焦点和环绕它的圆环间插入颜色;
  • 锥形渐变(Conical)在圆心周围插入颜色。

这三种渐变分别由QGradient的三个子类来表示,QLinearGradient表示线性渐变,QRadialGradient表示辐射渐变,QConicalGradient表示锥形渐变。


(1)线性渐变

QLinearGradient::QLinearGradient ( const QPointF & start, const QPointF & finalStop )

线性渐变需要指定开始点start结束点finalStop,然后将开始点和结束 点之间的区域进行等分,开始点的位置为0.0,结束点的位置为1.0,它们之间的位置按照距离比例进行设定,然后使用
QGradient::setColorAt (qreal position, const QColorj &color)函数在指定的位置position插人指定的颜色color,当然,这里的position的值要在0〜1之间。

这里还可以使用setSpread()函数来设置填充的扩散方式,即指明在指定区域以外的区域怎样进行填充。扩散方式由QGradient::Spread枚举变量定义,它一共有3个 值,分别是QGradiem::PadSpread,使用最接近的颜色进行填充,这是默认值;QGradient:: ReflectSpread在渐变区域以外将反射渐变;QGradiem:: RepeatSpread在渐变区域以外的区域重复渐变。要使用渐变填充,可以直接在setBrush()中使用,这时画刷风格会自动设置为相对应的渐变填充。在线性渐变中这3种扩散方式的效果如下图所示。

img


(2)辐射渐变

QRadialGradient::QRadialGradient ( const QPointF & center, qreal radius, const QPointF & focalPoint )

辐射渐变需要指定圆心 center 和半径 radius,这样就确定 了一个圆,然后再指定一个焦点focalPoint。焦点的位置为0,圆环的位置为1,然后在焦点和圆环间插人颜色。辐射渐变也可以使用setSpread()函数设置渐变区域以外区域的扩散方式,3种扩散方式的效果如下图所示。

img


(3)锥形渐变

QConicalGradient::QConicalGradient ( const QPointF & center, qreal angle )

锥形渐变需要指定中心点center和一个角度angle(其值在0到360之间),然后沿逆时针从给定的角度开始环绕中心点插入颜色。这里给定的角度沿逆时针方向开始的位置为0,旋转一圈后为1。setSpread()函数对于锥形渐变没有效果。


(4)示例程序

示例程序如下:

void MainWindow::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);

    //线性渐变
    QLinearGradient linearGradient(QPointF(40, 190), QPointF(70, 190));
    //插入颜色
    linearGradient.setColorAt(0, Qt::yellow);
    linearGradient.setColorAt(0.5, Qt::red);
    linearGradient.setColorAt(1, Qt::green);
    //指定渐变区域以外的区域的扩散方式
    linearGradient.setSpread(QGradient::RepeatSpread);
    //使用渐变作为画刷
    painter.setBrush(linearGradient);
    painter.drawRect(10, 170, 90, 40);

    //辐射渐变
    QRadialGradient radialGradient(QPointF(200, 190), 50, QPointF(275, 200));
    radialGradient.setColorAt(0, QColor(255, 255, 100, 150));
    radialGradient.setColorAt(1, QColor(0, 0, 0, 50));
    painter.setBrush(radialGradient);
    painter.drawEllipse(QPointF(200, 190), 50, 50);

    //锥形渐变
    QConicalGradient conicalGradient(QPointF(340, 190), 60);
    conicalGradient.setColorAt(0.2, Qt::cyan);
    conicalGradient.setColorAt(0.9, Qt::black);
    painter.setBrush(conicalGradient);
    painter.drawEllipse(QPointF(340, 190), 50, 50);
}

执行程序,效果如下:



参考:

65 2D绘图(基本绘制和填充)

[Qt教程] 第11篇 2D绘图(一)绘制简单图形


猜你喜欢

转载自www.cnblogs.com/linuxAndMcu/p/11057347.html