QT开发(十四)——QT绘图系统

一、QT绘图原理

    Qt4中的2D绘图系统称为Arthur绘图系统,可以使用相同的API在屏幕上和绘图设备上进行绘制,主要基于QPainter、QPainterDevice和 QPainterEngine。QPainter执行绘图操作,QPainterDevice提供绘图设备,是一个二维空间的抽象,QPainterEngine提供一些接口。QPainter用来执行具体的绘图相关操作如画点,画线,填充,变换,alpha通道等。QPaintDevice类是能够进行绘图的对象的基类,QWidget,QPixmap,QPicture,QImage,以及QPrinter类继承了QPaintEngine类的绘图能力QPainter类可以在一切继承QPainterDevice的子类上进行绘制操作。

    QT中Arthur绘图框架中的基本绘图元素是画笔,画刷。
    QPainter类具有GUI程序需要的绝大多数函数,能够绘制基本图形(点,线,矩形,多边形等)以及复杂的图形(如绘图路径)使用绘图路径(QPaintPath)的优点是复杂形状的图形只用生成一次,再使用的时候只需要调用QPainter::drawPath()就可以绘制。QPainterPath对象可以用来填充,绘制轮廓。
    线和轮廓都可以用画笔(QPen)进行绘制,画刷(QBrush)进行填充。画笔定义风格(线形),宽度,笔尖画刷以及端点是如何绘制的(cap-style),端点的连接方式(join-style)画刷用来填充画笔绘制的图形,可以定制不同的填充模式和颜色的画刷。
当绘制文字时,字体使用QFont类定义,Qt使用指定字体的属性,如果没有匹配的字体,Qt将使用最接近的字体。字体属性可以通过QFontInfo来获取。字体的度量(measurement)使用QFontMetrics类来获取。QFontDatabase类可以获得底层窗口系统所有可用的字体

    通常情况下QPainter以默认的坐标系统进行绘制,也可以用QMatrix类对坐标进行变换。
    当绘制时,可以使用QPainter::SetRenderHint函数设置绘图引擎是否启用锯齿功能使图变得平滑。

    QPainter::Antialiasing可能进行边的反锯齿绘制
    QPainter::TextAntialiasing       尽可能进行文字的反锯齿绘制
    QPainter::SmoothPixmapTransform  使用平滑的pixmap变换算法(双线性插值算法),而不是近邻插值算法

1、重写重绘事件处理函数实现绘图

重绘事件处理函数:

    void QWidget::paintEvent ( QPaintEvent * event )

    基础部件类Qwidget提供的paintEvent函数,是虚函数;Qwidget的子类要使用paintEvent函数必须重新实现。三种情况会发生重绘事件调用paintEvent函数:

    A、当窗口部件第一次显示时,系统会自动产生一个绘图事件

    B、repaint()与update()函数被调用时

    C、当窗口部件被其他部件遮挡,然后又再次显示出来时,就会对隐藏的区域产生一个重绘事件

    D、重新调整窗口大小时

2、通过事件过滤器实现重绘

 

 

二、绘图工具

    绘图时需要先定义一个QPainter类对象,绘图工具可以使Qpen(画笔)QBrush(画刷)Qpen(画笔)来绘制轮廓线QBrush(画刷)用来填充,使用QPen写文本时还可以指定字体(QFont类)

1、QPen画笔

画笔的属性包括线型,线宽,颜色等。

A、QPen主要成员函数如下:

    QPen(Qt::PenStyle style)

    QPen(const QColor & color)

    QPen(const QBrush & brush, qreal width, Qt::PenStyle style = Qt::SolidLine,     Qt::PenCapStyle cap = Qt::SquareCap, Qt::PenJoinStyle join = Qt::BevelJoin)

    QPen(const QPen & pen)

    void setBrush(const QBrush & brush)

    void setCapStyle (Qt::PenCapStyle style)

    void setColor (const QColor & color)

    void setJoinStyle (Qt::PenJoinStyle style)

    void setWidth (int width)

    画笔的属性可以在构造函数中指定,可以使用setStyle(setWidth(),setBrush(),setCapStyle(),setJoinStyle()等函数设定画笔的各项属性Qt中使用Qt::PenStyle定义了6种画笔风格,分别是Qt::SolidLine,Qt::DashLine,Qt::DotLine,Qt::DashDotLine,Qt::DashDotDotLine,Qt::CustomDashLine自定义线风格(Qt::CustomDashLine),需要使用QPen的setDashPattern()函数来设定自定义风格

画笔的设置代码如下:
    QPainter painter(this);  

   QPen pen(Qt::green, 3, Qt::DashDotLine, Qt::RoundCap, Qt::RoundJoin); 

   painter.setPen(pen);  

等价于如下代码:

      QPainter painter(this);  

    QPen pen;  // creates a default pen    

    pen.setStyle(Qt::DashDotLine);  

    pen.setWidth(3);  

    pen.setBrush(Qt::green);  

    pen.setCapStyle(Qt::RoundCap);  

    pen.setJoinStyle(Qt::RoundJoin);      

    painter.setPen(pen); 

B、画笔风格

    画笔风格使用Qt::PenStyle枚举定义。

QT开发(十四)——QT绘图系统_QT

    C、画笔的端点风格( Qt::PenCapStyle)
    画笔端点风格决定了线的端点样式,只对线宽大于1的线有效。Qt使用枚举定义了三种端点风格分别为Qt::SqureCap,QT::FlatCap,Qt::RoundCap

QT开发(十四)——QT绘图系统_QT_02

    D、画笔连接风格(Qt::PenJoinStyle)
    画笔连接风格是两条线如何连接,连接风格对线宽大于等于1的线有效。Qt使用枚举定义了四种连接类型分别Qt::MiterJoinQt::BevelJoinQt::RoundJoinQt::SvgMiterJoin

QT开发(十四)——QT绘图系统_绘图系统_03

2、QBrush画刷

    在Qt中图形使用QBrush进行填充,画刷包括填充颜色和填充模式(风格)。

    A、QBrush主要成员函数

    QBrush(Qt::BrushStyle style)

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

    QBrush(Qt::GlobalColor color,Qt::BrushStyle style = Qt::SolidPattern)

    QBrush(const QColor & color, const QPixmap & pixmap)

    QBrush(Qt::GlobalColor color, const QPixmap & pixmap)

    QBrush(const QPixmap & pixmap)

    QBrush(const QImage & p_w_picpath)

    QBrush(const QBrush & other)

    QBrush(const QGradient & gradient)

    const QColor &color() const

    const QGradient *gradient() const

    const QMatrix &matrix() const

        void setColor(const QColor & color)

        void setColor(Qt::GlobalColor color)

        void setMatrix(const QMatrix & matrix)

        void setStyle(Qt::BrushStyle style)

        void setTexture(const QPixmap & pixmap)

        void setTextureImage(const QImage & p_w_picpath)

        void setTransform(const QTransform & matrix)

    Qt::BrushStyle style() const

    QPixmap texture() const

    QImage textureImage() const

    QTransform transform() const

    B、填充颜色

    在Qt中,颜色使用QColor类表示,QColor支持RGB,HSV,CMYK颜色模型。QColor还支持alpha混合的轮廓和填充。RGB是面向硬件的模型颜色由红绿蓝三种基色混合而成HSV模型比较符合人对颜色的感觉,由色调(0-359),饱和度(0-255),亮度(0-255)组成CMYK由青,洋红,黄,黑四种基色组成主要用于打印机等硬件拷贝设备上每个颜色分量的取值是0-255

    C、填充模式

    填充模式通过枚举类型Qt::BrushStyle来实现,默认值是Qt::NoBrush,不进行任何填充;填充模式包括基本填充模式,渐变填充,和纹理填充模式。不同的填充模式显示效果如下:

QT开发(十四)——QT绘图系统_QT_04

    Qt4中,QBrush提供了三种渐变填充:线性(QLinearGradient),圆形(QRadialGradient)和圆锥渐变(QConicalGradient)所有的类都从QGradient类继承

线性渐变填充
    线性渐变填充指定两个控制点,画刷在两个控制点之间进行颜色插值。通过创建QLinearGradient对象来设置画刷
    QLinearGradient linearGradient(0,0,200,100);
    linearGradient.setColorAt(0,Qt::red);
    linearGradient.setColorAt(0.5,Qt::green);
    linearGradient.setColorAt(1,Qt::blue);
    painter.setBrush(linearGradient);
    painter.drawRect(0,0,200,100);
    在QGradient构造函数中指定线行填充的两点分别为(0,0),(100,100)             setColorAt()函数在0-1之间设置指定位置的颜色。
圆形渐变填充
    圆形渐变填充需要指定圆心,半径和焦点。画刷在焦点和圆上的所有点之间进行颜色插值,通过创建QRadialGradient对象设置画刷
    QRadialGradient radialGradient(50,50,50,30,30);
    radialGradient.setColorAt(0.2,Qt::cyan);
    radialGradient.setColorAt(0.8,Qt::yellow);
    radialGradient.setColorAt(1,Qt::magenta);
    painter.setBrush(radialGradient);
    painter.drawEllipse(0,0,100,100);
圆锥渐变填充
    圆锥渐变填充指定圆心和开始角,画刷沿圆心逆时针对颜色进行插值,通过创建QConicalGradient对象并设置画刷
    QConicalGradient conicalGradient(60,40,30);
    conicalGradient.setColorAt(0,Qt::gray);
    conicalGradient.setColorAt(0.4,Qt::darkGreen);
    conicalGradient.setColorAt(0.6,Qt::darkMagenta);
    conicalGradient.setColorAt(1,Qt::drakBlue);
    painter.setBrush(conicalGradient);
    painter.drawEllipse(0,0,100,100);

其他填充模式

    其他填充模式通过setStyle(Qt::BrushStyle style)函数进行设置。

    如果实现自定义填充,可以使用QPixmap或者QImage对象进行纹理填充。两种图像分别使用setTexture()和setTextureImage()函数加载纹理

    D、alpha通道
    在windows,Mac OSX和有XRender扩展的X11系统上,Qt4能够支持Alpha通道,通过使用Alpha通道,可以实现半透明效果,QColor类中定义了Alpha通道的透明度,0表示完全透明255表示完全不透明。QWidget类有一个属性windowOpacity,通过setWindowOpacity(qreal level)可以设置窗口的透明度。但该属性和Alpha通道的原理并不相同,Qt4在Windows和Mac OS X平台上才支持该属性,但在X11平台上却需要Composite扩展才能工作。(alpha通道使用的是X11的xRender扩展)

3双缓冲绘图

Qt4中,所有的窗口部件默认都使用双缓冲进行绘图。使用双缓冲,可以减轻绘制的闪烁感。在有些情况下,用户要关闭双缓冲,自己管理绘图。下面的语句设置了窗口部件的Qt::WA_PaintOnScreen属性 ,就关闭了窗口部件的双缓冲
    widget->setAttribute(Qt::WA_PaintOnScreen);
    Qt4不再提供异或笔,组合模式QPainter::CompostionMode_Xor()并不是异或笔,Qt4只提供了QRubberBand实现矩形和直线的绘图反馈。要实现在绘图中动态反馈必须使用其他方法。程序中使用双缓冲来解决这个问题。在绘图过程中,一个缓冲区绘制临时内存,一个缓冲区保存绘制好的内容,最后进行合并。
    在交互绘图过程中,程序将图像缓冲区复制到临时缓冲区,并在临时缓冲区上绘制,绘制完毕在将结果复制到图像缓冲区,如果没有交互复制,则直接将图像缓冲区绘制显示到屏幕上。

4、绘图路径

    绘图路径(painter path)由基本图元(矩形,椭圆,直线,曲线)组成,绘图路径可以是闭合的路径,如矩形和圆,或者是非闭合的路径,如直线和曲线。绘图路径在Qt中使用QPainterPth类表示,提供了绘图操作的容器,可以使图形能够复用。绘图路径可以进行填充,显示轮廓和裁剪。要生成可填充的轮廓的绘图路径,可以使用QPainterPathStroker类使用QPainterPath的优点是复杂的图形只需创建一次,就可以多次使用。QPainterPath对象可以只有起点的空路径,或者从其他QPainterPath对象复制,创建了QPainterPath对象后,可以使用lineTo(),cubicTo(),quadTo() 函数将直线和曲线添加到路径中来,直线和曲线从currentPosition()开始绘制。currentPosition()总是返回最后的子路经绘制的终点。使用moveTo()函数可以在不增加路径的情况下移动currentPositon(),它关闭了一个子路经,开始一个新的子路经。 closeSubPath()也可以关闭当前路径,并从currentPosition()连接一条直线到绘图路径的起点。QPainter可以使用 addEllipse(),addPath(),addRect(),addRegion(),

addText()将Qt的一些基本图元加入绘图路径。一个已有的绘图路径可以通过connectPath()函数加入到另一个绘图路径中。
箭头的绘制代码如下:
      QPainterPath path;

    path.moveTo(10,100);

    path.cubicTo(10,100,100,10,200,70);

    path.lineTo(200,50);

    path.lineTo(220,80);

    path.lineTo(200,110);

    path.lineTo(200,90);

    path.cubicTo(200,100,100,50,50,100);

    QPainter painter(this);

    QPen pen(QColor(255,0,0),2);

    painter.setPen(pen);

    painter.drawPath(path);

    Qt提供了两种填充方式,Qt::OddEventFill和Qt::WindingFillQt::OddEvent默认的填充规则,指定QPainterPath使用奇偶填充规则,奇偶填充规则判断一个点是否在路径图形内的方法是从该画一条水平线到路径外,计算水平线和路径的交点数,如果交点奇数个则说明该点在路径图形内。QPainterPath还有一些函数可以获取路径信息,如elementAt()函数可以取出指定的子路经元素,isEmpty()函数判断当前路径是否为空。controlPointRect()函数返回路径中所有的点和控制点的矩形,controlPointRect函数运行速度比返回精确包容框boundingRect()函数快得多。contains()函数判断一个点或一个矩形是否在路径内。intersects()判断指定的矩形与路径是否相交QPainterPath可以将矩形图形转换为其他图形,如使用toFillPolygon(),toFillPolygon(),toSubpathPOlygons()函数将路径转化为多边形。
QPainterPath还可以使用文字作为路径

使用线性渐变填充文字路径实现代码:
     QPainter painter(this);

    QLinearGradient linearGrad(QPointF(200,0),QPointF(1000,0));

    linearGrad.setColorAt(0,Qt::black);

    linearGrad.setColorAt(1,Qt::white);

    QFont font("隶书",80);

    font.setBold(true);

    QPainterPath textPath;

    textPath.addText(200,300,font,tr("电子工业出版社"));

    painter.setBrush(linearGrad);

    painter.drawPath(textPath);

三、绘图设备

    QPaintDevice类是绘制设备的基类QPainter能够在QPaintDevice子类QWidget,QImage,QPixmap,QGLWidget,QGLPixelBuffer,QPicture,QPrinter
QSvgGenerator上进行绘制。要实现自定义的绘图设备,必须从QPaintDevice类继承并实现其虚函数QPaintDevice::paintEngine()paintEngine()将通知QPainter能够在自定义的设备上绘制图形,同时还需要从QPaintEngine类继承自定义的图形绘制引擎。

1QWidget

QWidget是所有用户界面元素的基类,窗口部件用户界面的原子元素,接受鼠标键盘窗口系统的其他事件并在屏幕上绘制自己。

2QImage

QImage类提供了与硬件无关的图像表示,为直接操作像素提供优化,QImage支持单色8-bit32-bit和alpha混合图像,使用QImage的优点在于可以获得平台无关的绘制操作,同时图像可以不必在GUI线程中处理。

3QPixmap

QPixmap后台显示的图像,为在屏幕上显示图像提供优化,不同于QImage,QPixmap的图像数据用户不可见,由底层窗口系统管理,为了优化QPixmap图像,Qt提供了QPixmapCache类来存储临时的pixmapQt还提供了QPixmap的继承类QBitmap类,QBitmap表示单色的pixmap,主要用来创建自定义的QCursor和QBrush对象,构造QRegion对象,设置pixmap和窗口部件的掩码。

4OPenGLWidget

Qt提供了QtOpenGL模块来实现OpenGL操作,QGLWidget允许使用OpenGL API进行绘制。QGLWidgetQWidget的子类,QPainter可以在上面绘制,因此Qt能够利用OpenGL完成绘制操作,如变换和绘制pixmap

5QGLPixelBuffer

QGLPixelBuffer从QPaintDevice继承,封装了OpenGL pbuffer使用pbuffer绘制通常全硬件加速,比使用QPixmap绘制更迅速。

6QGLFrameBufferObject

QGLFrameBufferObject从QPaintDevice继承,QGLFrameBufferObject封装了OpenGL frameBuffer对象,FrameBuffer用来实现后台屏幕绘制,比pixel buffer更好。

7QPicture

QPicture类能够记录和重演QPainter命令的绘图设备,picture串行化painter的命令为平台无关的格式,QPicture同时也分辨率无关,如QPicuture能够在不同的设备上(svg,pdf,ps打印机和屏幕)有一样的显示。QPicture::load()和QPicture::save()函数分别完成载入和存储图像。

8QPrinter

QPrinter类在打印机上绘制的绘图设备,在Windows和MAC OS X上,QPrinter使用内建的打印机驱动程序,在X11上,QPrinter上传postscript代码并发送给lpr,lp或者其他打印程序,QPrinter可以在任意其他QPrintEngine对象上打印,也可以直接生成PDF文件。
    QPrintEngine类定义了QPrinter如何和其他打印机系统交互的接口,主要创建自己的打印引擎时,可以从QPaintEngine和QPaintEngine上继承。

四、QPainter类成员函数

    主要的绘图成员函数如下:

    drawArc()                                  弧
    drawChord()                                弦
    drawConvexPolygon()                        凸多边形
    drawEllipse()                              椭圆
    drawImage()                                QImage表示的图像
    drawLine()                                 线
    drawLines()                                多条线
    drawPath()                                 路径
    drawPicture()                              按QPainter指令绘制
    drawPie()                                  扇形
    drawPixmap()                               QPixmap表示的图像
    drawPoint()                                点
    drawPoints()                               多个点
    drawPolygon()                              多边形
    drawPolyline()                             多折线
    drawRect()                                 矩形
    drawRects()                                多个矩形
    drawRoundRect()                            圆角矩形
    drawText()                                 文字
    drawTiledPixmap()                          平铺图像
    drawLineSegments()                         绘制折线

    设置好画笔、画刷就可以使用绘图函数进行绘图。