2008年8月25日 星期一

QT - Paint

重點說明:repaint()、paintEvent()
因為,這個在之後非常重要,所以,在這裡說明一下

void QWidget::repaint () [slots]
把整個畫布以背景重新粉刷過一次,然後,呼叫void QWidget::paintEvent ( QPaintEvent * ),參數的部分就應該是傳整個畫布。
void QWidget::repaint ( const QRect & r, bool erase = TRUE ) [slots]
會在r這一個區域用背景重新粉刷過一次,然後,呼叫void QWidget::paintEvent(QPaintEvent *),參數的部分就是r。
repaint的部分其實就是決定要把目前的畫面哪一個部分要把它由背景填滿,也就是說,它的工作就是清除。

真正畫圖的部分是由QPaint去實作的,而我們通常把QPaint的宣告放在paintEvent中,因為,當我們呼叫repaint(const QRect &r,bool erase = TRUE)時,程式會透過它呼誓paintEvent(),並把r當參數傳給paintEvent(),這個時候,我們就可以在paintEvent中寫出畫圖的程式。

以下是畫圖的例子:

QPainter p( pd ); // 決定要在哪一個設備上畫圖
p.setBrush( blue ); // 設定畫筆為藍色
p.setPen( NoPen ); // 設定沒有邊框
p.drawEllipse(0,0,10,10); // 畫一個10*10的橢圓,剛好就是一個直徑為10的圓啦~


下面再一個例子:

void CannonField::paintEvent( QPaintEvent * )
{
  QString s = "Angle = " + QString::number( ang );
  QPainter p( this );
  p.drawText( 200, 200, s );
}


void CannonField::paintEvent( QPaintEvent * )
{
  QString s = "Angle = " + QString::number( ang );
  QPainter p;
  p.begin( this );
  p.drawText( 200, 200, s );
  p.end();
}

上面兩個程式碼的義意是一樣的。

begin():開始繪製
end():結束繪製。繪製時使用的任何資源都被釋放。注意雖然你幾乎不需要調用end(),建構函數將會執行它,但是至少還有一種情況需要它,就是雙重緩衝(就是先把要畫的先畫在pixmap再畫到qpainter)。

QPainter p( myPixmap, this )
// ...
p.end(); // 停止在myPixmap上的繪製
p.begin( this );
p.drawPixmap( myPixmap );


這是我們第一次試圖寫一個繪畫事件處理程序。
這個事件參數包含一個繪畫事件的描述。
QPaintEvent包含一個必須被刷新的視窗元件的區域。
現在,我們比較懶惰,並且只是畫每一件事。

我們的程式碼在一個固定位置顯示窗口部件的角度值。
首先我們創建一個含有一些文本和角度值的QString,
然後我們創建一個操作這個窗口部件的QPainter並使用它來畫這個字符串。
我們一會兒會回到QPainter,它可以做很多事。

repaint
void QWidget::repaint ( int x, int y, int w, int h, bool erase = TRUE ) [slots]
通過立即調用paintEvent()來直接重新繪製視窗元件,
除非更新是失效的或者窗口部件被隱藏。
如果erase為真,Qt在paintEvent()調用之前擦除區域(x,y,w,h)。
如果w是負數,它被width()-x替換,並且如果h是負數,它被height()-y替換。
如果你需要立即重新繪製,我們建議使用repaint(),比如在動畫期間。在絕大多數情況下,update()更好,因為它允許Qt來優化速度並且防止閃爍。
警告:如果你在一個函數中調用repaint(),而它自己又被paintEvent()調用,你也許會看到無線循環。update()函數從來不會產生循環。


在一開始的時候,就會執行一次paintEvent

沒有留言: