閱讀785 返回首頁    go 京東網上商城


[Qt教程] 第18篇 2D繪圖(八)雙緩衝繪圖

[Qt教程] 第18篇 2D繪圖(八)雙緩衝繪圖

樓主
 發表於 2013-5-2 22:07:23 | 查看: 789| 回複: 1
雙緩衝繪圖


版權聲明

該文章原創於Qter開源社區(www.qter.org),作者yafeilinux,轉載請注明出處!


導語

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


環境:Windows Xp + Qt 4.8.4+QtCreator 2.6.2


目錄

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


正文


一、繪製矩形

1.我們仍然在前麵程序的基礎上進行修改,先更改painEvent()函數:
void Dialog::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    int x,y,w,h;
    x = lastPoint.x();
    y = lastPoint.y();
    w = endPoint.x() - x;
    h = endPoint.y() - y;
    painter.drawRect(x, y, w, h);
}
       這裏就是通過lastPointendPoint兩個點來確定要繪製的矩形的起點、寬和高的。運行程序,用鼠標拖出一個矩形,效果如下圖所示。
18-1.jpg



2. 上麵已經可以拖出一個矩形了,但是這樣直接在窗口上繪圖,以前畫的矩形是不能保存下來的。所以我們下麵加入畫布,在畫布上進行繪圖。將paintEvent()函數更改如下:
void Dialog::paintEvent(QPaintEvent *)
{
    int x,y,w,h;
    x = lastPoint.x();
    y = lastPoint.y();
    w = endPoint.x() - x;
    h = endPoint.y() - y;
    QPainter pp(&pix);
    pp.drawRect(x, y, w, h);
    QPainter painter(this);
    painter.drawPixmap(0, 0, pix);
}
       這裏就是將圖形先繪製在了畫布上,然後將畫布繪製到窗口上。我們運行程序,然後使用鼠標拖出一個矩形,發現出現了很多重影,效果如下圖所示。
18-2.jpg


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


二、雙緩衝繪圖

1.我們再添加一個輔助畫布,如果正在繪圖,也就是鼠標按鍵還沒有釋放的時候,就在這個輔助畫布上繪圖,隻有當鼠標按鍵釋放的時候,才在真正的畫布上繪圖。
       首先在dialog.h文件中添加兩個私有變量:

QPixmap tempPix; //輔助畫布
bool isDrawing;   //標誌是否正在繪圖

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

isDrawing = false;

下麵再更改paintEvent()函數:
void Dialog::paintEvent(QPaintEvent *)
{
    int x,y,w,h;
    x = lastPoint.x();
    y = lastPoint.y();
    w = endPoint.x() - x;
    h = endPoint.y() - y;
    QPainter painter(this);
    if(isDrawing) //如果正在繪圖,就在輔助畫布上繪製
    {
       //將以前pix中的內容複製到tempPix中,保證以前的內容不消失
       tempPix = pix;
       QPainter pp(&tempPix);
       pp.drawRect(x,y,w,h);
       painter.drawPixmap(0, 0, tempPix);
    } else {
       QPainter pp(&pix);
       pp.drawRect(x,y,w,h);
       painter.drawPixmap(0,0,pix);
    }
}

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

void Dialog::mousePressEvent(QMouseEvent *event)
{
    if(event->button()==Qt::LeftButton) //鼠標左鍵按下
    {
       lastPoint = event->pos();
       isDrawing = true;   //正在繪圖
    }
}
void Dialog::mouseReleaseEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton) //鼠標左鍵釋放
    {
       endPoint = event->pos();
       isDrawing = false;    //結束繪圖
       update();
    }
}
       當鼠標左鍵按下時我們開始標記正在繪圖,當按鍵釋放時我們取消正在繪圖的標記。現在運行程序,已經可以實現正常的繪圖了。效果如下圖所示。
18-3.jpg


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中得圖形視圖框架。




涉及到的源碼:  painter_3.zip (2.74 KB, 下載次數: 9)

最後更新:2017-04-03 14:54:15

  上一篇:go [Qt教程] 第15篇 2D繪圖(五)繪製圖片
  下一篇:go Java IO--數據操作流DataOutputStream/DataInputStream