【Qt筆記】Qt 繪製系統簡介

Qt 的繪圖系統容許使用相同的 API 在屏幕和其它打印設備上進行繪製。整個繪圖系統基於QPainterQPainterDeviceQPaintEngine三個類。函數

QPainter用來執行繪製的操做;QPaintDevice是一個二維空間的抽象,這個二維空間容許QPainter在其上面進行繪製,也就是QPainter工做的空間;QPaintEngine提供了畫筆(QPainter)在不一樣的設備上進行繪製的統一的接口。QPaintEngine類應用於QPainterQPaintDevice之間,一般對開發人員是透明的。除非你須要自定義一個設備,不然你是不須要關心QPaintEngine這個類的。咱們能夠把QPainter理解成畫筆;把QPaintDevice理解成使用畫筆的地方,好比紙張、屏幕等;而對於紙張、屏幕而言,確定要使用不一樣的畫筆繪製,爲了統一使用一種畫筆,咱們設計了QPaintEngine類,這個類讓不一樣的紙張、屏幕都能使用一種畫筆。this

 

下圖給出了這三個類之間的層次結構(出自 Qt API 文檔):翻譯

上面的示意圖告訴咱們,Qt 的繪圖系統其實是,使用QPainterQPainterDevice上進行繪製,它們之間使用QPaintEngine進行通信(也就是翻譯QPainter的指令)。設計

下面咱們經過一個實例來介紹QPainter的使用:指針

//!!! Qt4/Qt5

class PaintedWidget : public QWidget
{
    Q_OBJECT
public:
    PaintedWidget(QWidget *parent = 0);
protected:
    void paintEvent(QPaintEvent *);
};

注意咱們重寫了QWidgetpaintEvent()函數。這或許是咱們在理解了 Qt 事件系統以後首次實際應用。接下來就是PaintedWidget的源代碼:code

//!!! Qt4/Qt5

PaintedWidget::PaintedWidget(QWidget *parent) :
    QWidget(parent)
{
    resize(800, 600);
    setWindowTitle(tr("Paint Demo"));
}

void PaintedWidget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.drawLine(80, 100, 650, 500);
    painter.setPen(Qt::red);
    painter.drawRect(10, 10, 100, 400);
    painter.setPen(QPen(Qt::green, 5));
    painter.setBrush(Qt::blue);
    painter.drawEllipse(50, 150, 400, 200);
}

在構造函數中,咱們僅僅設置了窗口的大小和標題。而paintEvent()函數則是繪製的代碼。首先,咱們在棧上建立了一個QPainter對象,也就是說,每次運行paintEvent()函數的時候,都會重建這個QPainter對象。注意,這一點可能會引起某些細節問題:因爲咱們每次重建QPainter,所以第一次運行時所設置的畫筆顏色、狀態等,第二次再進入這個函數時就會所有丟失。有時候咱們但願保存畫筆狀態,就必須本身保存數據,不然的話則須要將QPainter做爲類的成員變量。對象

QPainter接收一個QPaintDevice指針做爲參數。QPaintDevice有不少子類,好比QImage,以及QWidget。注意回憶一下,QPaintDevice能夠理解成要在哪裏去繪製,而如今咱們但願畫在這個組件,所以傳入的是 this 指針。接口

QPainter有不少以 draw 開頭的函數,用於各類圖形的繪製,好比這裏的drawLine()drawRect()以及drawEllipse()等。當繪製輪廓線時,使用QPainterpen()屬性。好比,咱們調用了painter.setPen(Qt::red)將 pen 設置爲紅色,則下面繪製的矩形具備紅色的輪廓線。接下來,咱們將 pen 修改成綠色,5 像素寬(painter.setPen(QPen(Qt::green, 5))),又設置了畫刷爲藍色。這時候再調用 draw 函數,則是具備綠色 5 像素寬輪廓線、藍色填充的橢圓。事件

運行一下咱們的程序,能夠看到最終效果:ip

咱們會在後面的章節詳細介紹畫筆QPen和畫刷QBrush的屬性。

另外要說明一點,請注意咱們的繪製順序,首先是直線,而後是矩形,最後是橢圓。按照這樣的繪製順序,能夠看到直線是第一個繪製,位於最下一層;矩形是第二個繪製,在中間一層;橢圓是最後繪製,在最上層。

若是瞭解 OpenGL,確定據說過這麼一句話:OpenGL 是一個狀態機。所謂狀態機,就是說,OpenGL 保存的只是各類狀態。好比,將畫筆顏色設置成紅色,那麼,除非你從新設置另外的顏色,它的顏色會一直是紅色。QPainter也是這樣,它的狀態不會本身恢復,除非你使用了各類設置函數。所以,若是在上面的代碼中,咱們在橢圓繪製以後再畫一個矩形,它的樣式還會是綠色 5 像素的輪廓線以及藍色的填充,除非你顯式地調用了設置函數進行狀態的更新。這是大多數繪圖系統的實現方式,包括 OpenGL、QPainter以及 Java2D。正由於QPainter是一個狀態機,纔會引出咱們前面曾經介紹過的一個細節問題:因爲paintEvent()是須要重複進入的,所以,須要注意第二次進入時,QPainter的狀態是否是和第一次一致,不然的話可能會形成閃爍的現象。這個閃爍並非因爲雙緩衝的問題,而是因爲繪製狀態的快速切換。

相關文章
相關標籤/搜索