Qt雙緩衝繪圖

轉載自:https://wizardforcel.gitbooks.io/qt-beginning/content/22.html

導語

在前面一節中,講述瞭如何實現簡單的塗鴉板,這一次我們將實現在塗鴉板上繪製圖形,這裏以矩形爲例進行講解。在後面還會提出雙緩衝繪圖的概念。

環境:Windows Xp + Qt 4.8.4+QtCreator 2.6.2

目錄

  • 一、繪製矩形
  • 二、雙緩衝繪圖

正文

一、繪製矩形

1.我們仍然在前面程序的基礎上進行修改,先更改painEvent()函數:


 
  1. void Dialog::paintEvent(QPaintEvent *)

  2. {

  3. QPainter painter(this);

  4. int x,y,w,h;

  5. x = lastPoint.x();

  6. y = lastPoint.y();

  7. w = endPoint.x() - x;

  8. h = endPoint.y() - y;

  9. painter.drawRect(x, y, w, h);

  10. }

這裏就是通過lastPoint和endPoint兩個點來確定要繪製的矩形的起點、寬和高的。運行程序,用鼠標拖出一個矩形,效果如下圖所示。

18-1.jpguploading.4e448015.gif轉存失敗重新上傳取消

2.上面已經可以拖出一個矩形了,但是這樣直接在窗口上繪圖,以前畫的矩形是不能保存下來的。所以我們下面加入畫布,在畫布上進行繪圖。將paintEvent()函數更改如下:


 
  1. void Dialog::paintEvent(QPaintEvent *)

  2. {

  3. int x,y,w,h;

  4. x = lastPoint.x();

  5. y = lastPoint.y();

  6. w = endPoint.x() - x;

  7. h = endPoint.y() - y;

  8. QPainter pp(&pix);

  9. pp.drawRect(x, y, w, h);

  10. QPainter painter(this);

  11. painter.drawPixmap(0, 0, pix);

  12. }

這裏就是將圖形先繪製在了畫布上,然後將畫布繪製到窗口上。我們運行程序,然後使用鼠標拖出一個矩形,發現出現了很多重影,效果如下圖所示。

18-2.jpguploading.4e448015.gif轉存失敗重新上傳取消

爲什麼會出現這種現象呢?大家可以嘗試分別快速拖動鼠標和慢速拖動鼠標來繪製矩形,結果會發現,拖動速度越快,重影越少。其實,在我們拖動鼠標的過程中,屏幕已經刷新了很多次,也可以理解爲paintEvent()函數執行了多次,每執行一次就會繪製一個矩形。知道了原因,就有方法來避免這個問題發生了。

二、雙緩衝繪圖

1.我們再添加一個輔助畫布,如果正在繪圖,也就是鼠標按鍵還沒有釋放的時候,就在這個輔助畫布上繪圖,只有當鼠標按鍵釋放的時候,纔在真正的畫布上繪圖。

首先在dialog.h文件中添加兩個私有變量:


 
  1. QPixmap tempPix; //輔助畫布

  2. bool isDrawing; //標誌是否正在繪圖

然後到dialog.cpp的構造函數中對變量進行初始化:

isDrawing = false;

下面再更改paintEvent()函數:


 
  1. void Dialog::paintEvent(QPaintEvent *)

  2. {

  3. int x,y,w,h;

  4. x = lastPoint.x();

  5. y = lastPoint.y();

  6. w = endPoint.x() - x;

  7. h = endPoint.y() - y;

  8. QPainter painter(this);

  9. if(isDrawing) //如果正在繪圖,就在輔助畫布上繪製

  10. {

  11. //將以前pix中的內容複製到tempPix中,保證以前的內容不消失

  12. tempPix = pix;

  13. QPainter pp(&tempPix);

  14. pp.drawRect(x,y,w,h);

  15. painter.drawPixmap(0, 0, tempPix);

  16. } else {

  17. QPainter pp(&pix);

  18. pp.drawRect(x,y,w,h);

  19. painter.drawPixmap(0,0,pix);

  20. }

  21. }

下面還需要更改鼠標按下事件處理函數和鼠標釋放事件處理函數的內容:


 
  1. void Dialog::mousePressEvent(QMouseEvent *event)

  2. {

  3. if(event->button()==Qt::LeftButton) //鼠標左鍵按下

  4. {

  5. lastPoint = event->pos();

  6. isDrawing = true; //正在繪圖

  7. }

  8. }

  9. void Dialog::mouseReleaseEvent(QMouseEvent *event)

  10. {

  11. if(event->button() == Qt::LeftButton) //鼠標左鍵釋放

  12. {

  13. endPoint = event->pos();

  14. isDrawing = false; //結束繪圖

  15. update();

  16. }

  17. }

當鼠標左鍵按下時我們開始標記正在繪圖,當按鍵釋放時我們取消正在繪圖的標記。現在運行程序,已經可以實現正常的繪圖了。效果如下圖所示。

18-3.jpguploading.4e448015.gif轉存失敗重新上傳取消

2.雙緩衝繪圖

根據這個例子所使用的技巧,我們引出所謂的雙緩衝繪圖的概念。雙緩衝(double-buffers)繪圖,就是在進行繪製時,先將所有內容都繪製到一個繪圖設備(如QPixmap)上,然後再將整個圖像繪製到部件上顯示出來。使用雙緩衝繪圖可以避免顯示時的閃爍現象。從Qt 4.0開始,QWidget部件的所有繪製都自動使用了雙緩衝,所以一般沒有必要在paintEvent()函數中使用雙緩衝代碼來避免閃爍。

雖然在一般的繪圖中無需手動使用雙緩衝繪圖,不過要想實現一些繪圖效果,還是要藉助於雙緩衝的概念。比如這個程序裏,我們要實現使用鼠標在界面上繪製一個任意大小的矩形。這裏需要兩張畫布,它們都是QPixmap實例,其中一個tempPix用來作爲臨時緩衝區,當鼠標正在拖動矩形進行繪製時,將內容先繪製到tempPix上,然後將tempPix繪製到界面上;而另一個pix作爲緩衝區,用來保存已經完成的繪製。當鬆開鼠標完成矩形的繪製後,則將tempPix的內容複製到pix上。爲了繪製時不顯示拖影,而且保證以前繪製的內容不消失,那麼在移動鼠標過程中,每繪製一次,都要在繪製這個矩形的原來的圖像上進行繪製,所以需要在每次繪製tempPix之前,先將pix的內容複製到tempPix上。因爲這裏有兩個QPixmap對象,也可以說有兩個緩衝區,所以稱之爲雙緩衝繪圖。

結語

對於Qt基本繪圖的內容,我們就講到這裏,如果大家還想更加系統深入的學習這些基礎知識,可以參考《Qt Creator快速入門》的第10章。從下一節開始,我們將簡單介紹一下Qt中得圖形視圖框架。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章