注:學習自《Qt Creator 快速入門》第三版。
文檔中的示例參考
Qt Example推薦:Painter Paths Example和Vector Deformation
大綱:
繪制文字
繪制路徑
path的填充規則
QPainter中與path有關的常用函數
本篇涉及的Qt類: QPainter QFont QPainterPath
繪制文字 (QPainter::darwText())
除了繪制圖形以外,還可以使用QPainter::darwText()函數來繪制文字,
還可以使用QPainter::setFont()設置文字所使用的字體,使用QPainter::fontInfo()函數可以獲取字體的信息,它返回QFontInfo類對象。
繪制文字時會默認使用抗鋸齒。
drawText()函數有很多重載。這里演示一個:
void QPainter::drawText(const QRectF &rectangle, int flags, const QString &text, QRectF *boundingRect = nullptr)
-
第一個參數指定了繪制文字所在的矩形;
-
第二個參數指定了文字在矩形中的對齊方式,它由Qt::AlignmentFlag枚舉類型進行定義,不同對齊方式也可以使用按位或“|”操作符同時使用,這里還可以使用Qt::TextFlag定義的其他一些標志,比如自動換行等;
-
第三個參數就是所要繪制的文字,這里可以使用“\n”來實現換行;
-
第四個參數一般不用設置。
如果繪制的文字和它的布局不用經常改動,那么也可以使用drawStaticText。
painter.drawStaticText(QPoint(120, 120), QStaticText(QString("hello use drawStaticText")));
繪制路徑 (QPainter::drawPath(path))
如果要繪制一個復雜的圖形,尤其是要重復繪制復雜的圖形,可以使用
QPainterPath類,並使用QPainter: :drawPath()進行繪制。
QPainterPath類為繪制操作提供了一個容器,可以用來創建圖形並且重復使用。
一個繪圖路徑就是由多個矩形、橢圓、線條或者曲線等組成的對象,一個路徑可以是封閉的,如矩形和橢圓;也可以是非封閉的,如線條和曲線。
void Widget::paintEvent(QPaintEvent *event) { QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); QPainterPath path; // 創建一個QPainterPath對象后就會以坐標原點為當前點進行繪制, // 可以使用moveTo()函數改變當前點,移動當前點到點(50,250) path.moveTo(50, 250); // 從當前點即(50,250)繪制一條直線到點(50,230).完成后當前點更改為(50,230) path.lineTo(50, 230); //從當前點和點(120,60)之間繪制一條三次貝塞爾曲線 path.cubicTo(QPointF(105, 40), QPointF(115, 80), QPointF(120, 60)); path.lineTo(130, 130); //向路徑中添加一個橢圓 path.addEllipse(QPointF(130.0, 130.0), 30, 30); // 繪制path painter.drawPath(path); //平移坐標系統后再次繪制路徑 path.translate(200, 0); painter.setPen(Qt::darkBlue); painter.drawPath(path); }
關於path路徑"制作",主要是QpainterPath類的使用.
常用的方法:
可以使用lineTo()、arcTo()、cubicTo( )和quadTo()等函數將直線或者曲線添加到路徑中;
cubicTo (const QPointF &cl, const QPointF &c2, const QPointF &endPoint)函數可以在當前點和endPoint點之間添加一個3次貝塞爾曲線;
quadTo()函數可以繪制一個二次貝塞爾曲線;
可以使用addEllipse()、addPath()、addRect()、addRegion()、addText()和addPolygon()來向路徑中添加一些圖形或者文字。
它們都從當前點開始進行繪制,繪制完成后以結束點作為新的當前點。這些圖形都是由一組直線或者曲線組成.
currentPosition()函數獲取當前點;
使用moveTo()函數改變當前點;
當組建好路徑后可以使用drawPath()函數來繪制路徑;
可以使用translate()函數將路徑平移。
這也是QPainterPath的主要作用。
注:關於貝塞爾曲線來看一個書上的圖:
path的填充規則 (Qt::FillRule)
path的填充有兩個填充規則:
Qt::OddEvenFill(默認)和Qt::WindingFill。
QPainter painter(this); QPainterPath path; // 此path沒有設置fillrule。則使用默認的Qt::OddEvenFill path.addEllipse(10,50,100,100); path.addRect(50,100,100,100); painter.setBrush(Qt::cyan); painter.drawPath(path); //此path手動設置填充規則 painter.translate(180,0); path.setFillRule(Qt::WindingFill); painter.drawPath(path);
運行結果:

FillRule的理論部分:
Qt::OddEvenFill使用的是奇偶填充規則.
具體來說就是:如果要判斷一個點是否在圖形中,那么可以從該點向圖形外引一條水平線,如果該水平線與圖形的交點的個數為奇
數,那么該點就在圖形中。這個規則是默認值;
Qt::WindingFill使用的是非零彎曲規則.
具體來說就是:如果要判斷一個點是否在圖形中,那么可以從該點向圖形外引一條水平線,
如果該水平線與圖形的邊線相交,這個邊線是順時針繪制的,就記為1;是逆時針繪制的就記為一1。然后將所有數值相加,如果結果不為0,那么該點就在圖形中。
圖10- 19是這兩種規則的示意圖,對於Qt::OddEvenFill規則,第一個交點記為1,第二個交點記為2;
對於Qt::WindingFill規則,因為橢圓和矩形都是以順時針進行繪制的,所以各個交點對應的邊都使用1來代表。
關於QPainter 的與path有關的常用函數:
QPainter::fillPath()來填一個路徑;
QPainter::strokePath()函數來繪制路徑的輪廓;
QPainterPath::elementAt()來獲取路徑中的一個元素;
QPainterPath::elementCount()獲取路徑中元素的個數;
QPainterPath::contains()函數來判斷一個點是否在路徑中;
QPainterPath::toFillPolygon()函數將路徑轉換為一個多邊形。
...
本篇筆記的源代碼
代碼會整理到GitHub,如果沒有請等待:
https://github.com/tudouloveloli/QtExampleCode