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繪圖(基本繪制和填充)



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM