zoukankan      html  css  js  c++  java
  • Qt 2D绘图之一:基本图形绘制和渐变填充

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

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

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

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



    一、基本图形的绘制

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

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

    protected:
        void paintEvent(QPaintEvent *);
    

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



    1.1 绘制图形

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

    void Widget::paintEvent(QPaintEvent *)
    {
        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)就是窗口的原点,默认是窗口的左上角(不包含标题栏)。效果如下图所示。



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

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

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

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



    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()函数可以轻松修改各种设置。

    画笔样式



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

    void Widget::paintEvent(QPaintEvent *)
    {
        //创建画笔
        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)。



    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种预定义的颜色,如下图所示。

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



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

    void Widget::paintEvent(QPaintEvent *)
    {
        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。运行程序,效果如下图所示。



    二、渐变填充

    在画刷中也可以使用渐变填充。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种扩散方式的效果如下图所示。


    (2)辐射渐变

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

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


    (3)锥形渐变

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

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


    (4)示例程序

    示例程序如下:

    void Widget::paintEvent(QPaintEvent *)
    {
        //线性渐变
        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);
        //使用渐变作为画刷
        QPainter painter(this);
        painter.setBrush(linearGradient);
        painter.drawRect(100, 100, 90, 40);
    
        //辐射渐变
        QRadialGradient radialGradient(QPointF(100, 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(100, 200), 50, 50);
    
        //锥形渐变
        QConicalGradient conicalGradient(QPointF(250, 190), 60);
        conicalGradient.setColorAt(0.2, Qt::cyan);
        conicalGradient.setColorAt(0.9, Qt::black);
        painter.setBrush(conicalGradient);
        painter.drawEllipse(QPointF(250, 200), 50, 50);
    }
    

    执行程序,效果如下:



    参考:

    第11篇 Qt5之2D绘图(一)绘制简单图形

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


  • 相关阅读:
    团队服务器搭建(搭建php环境和安装在线mysql管理工具phpmyadmin)
    游戏交流社区的构思
    脚本实现在线黄金点游戏,支持多用户,不重复,防机器等功能
    LogFilter
    XML
    Java互联网应用和企业级应用的区别
    Java小目标
    JAVA集合类
    黄金点游戏
    WordCount
  • 原文地址:https://www.cnblogs.com/linuxAndMcu/p/11057347.html
Copyright © 2011-2022 走看看