<a target="_blank" href="http://bbs.qter.org/forum.php?mod=viewthread&tid=119">樓主</a>
發表于 2013-5-2 21:37:41 | 檢視:
1255| 回複: 16
塗鴉闆
版權聲明
導語
通過前面幾節的學習,大家應該已經對qt中2d繪圖有了一定的認識,這一節我們将應用前面講到的内容,編寫一個簡單的塗鴉闆程式,這一節隻是實作最基本的滑鼠畫線功能。
環境:windows xp + qt 4.8.4+qtcreator 2.6.2
目錄
一、實作塗鴉闆
二、實作放大功能
正文
1.建立qt gui應用,項目名稱為pianter_3,基類這次還用qdialog,類名保持dialog不變即可。
2.到dialog.h檔案中,先添加頭檔案包含:#include <qmouseevent>
然後添加幾個函數的聲明:
protected:
void paintevent(qpaintevent *);
void mousepressevent(qmouseevent *);
void mousemoveevent(qmouseevent *);
void mousereleaseevent(qmouseevent *);
第一個是繪制事件處理函數,後面分别是滑鼠按下、移動和釋放事件的處理函數。
下面再添加幾個private私有變量聲明:
qpixmap pix;
qpoint lastpoint;
qpoint endpoint;
因為在函數裡聲明的qpixmap類對象是臨時變量,不能存儲以前的值,為了實作保留上次的繪畫結果,我們需要将其設為全局變量。後面兩個qpoint變量存儲滑鼠指針的兩個坐标值,我們需要用這兩個坐标值完成繪圖。
2.到dialog.cpp檔案中,先添加頭檔案包含:#include <qpainter>
然後在構造函數中添加如下初始代碼:
resize(600, 500); //視窗大小設定為600*500
pix = qpixmap(200, 200);
pix.fill(qt::white);
下面添加幾個函數的定義:
void dialog::paintevent(qpaintevent *)
{
qpainter pp(&pix);
// 根據滑鼠指針前後兩個位置就行繪制直線
pp.drawline(lastpoint, endpoint);
// 讓前一個坐标值等于後一個坐标值,這樣就能實作畫出連續的線
lastpoint = endpoint;
qpainter painter(this);
painter.drawpixmap(0, 0, pix);
}
這裡使用了兩個點來繪制線條,這兩個點在下面的滑鼠事件中獲得。
void dialog::mousepressevent(qmouseevent *event)
{
if(event->button()==qt::leftbutton) //滑鼠左鍵按下
lastpoint = event->pos();
當滑鼠左鍵按下時獲得開始點。
void dialog::mousemoveevent(qmouseevent *event)
if(event->buttons()&qt::leftbutton) //滑鼠左鍵按下的同時移動滑鼠
{
endpoint = event->pos();
update(); //進行繪制
}
當滑鼠移動時獲得結束點,并更新繪制。調用update()函數會執行paintevent()函數進行重新繪制。
void dialog::mousereleaseevent(qmouseevent *event)
if(event->button() == qt::leftbutton) //滑鼠左鍵釋放
{
endpoint = event->pos();
update();
}
當滑鼠按鍵釋放時也進行重繪。
現在運作程式,使用滑鼠在白色畫布上進行繪制,發現已經實作了簡單的塗鴉闆功能,效果如下圖所示。
前面已經實作了簡單的繪制功能,下面我們将實作放大功能,将畫布放大後繼續進行塗鴉。這裡将使用兩種方法來實作,也是對上一節坐标系統後面的問題的更進一步的應用實踐。
1.添加放大按鈕。到dialog.h檔案中,先添加頭檔案:
#include <qpushbutton>
然後添加下面private私有變量聲明:
qreal scale;
qpushbutton *button;
最後再添加一個私有槽聲明:
private slots:
void zoomin();
2.到dialog.cpp檔案中,先在構造函數中添加如下代碼:
//設定初始放大倍數為1,即不放大
scale =1;
//建立按鈕對象
button = new qpushbutton(this);
//設定按鈕顯示文本
button->settext(tr("zoomin"));
//設定按鈕放置位置
button->move(500, 450);
//對按鈕的單擊事件和其槽函數進行關聯
connect(button, signal(clicked()), this, slot(zoomin()));
這裡使用代碼建立了一個按鈕對象,并将其單擊信号關聯到了放大槽上,也就是說按下這個按鈕,就會執行zoomin()槽。
3.下面添加zoomin()的定義:
void dialog::zoomin()
{
scale *=2;
update();
這裡我們讓每按下這個按鈕,放大值都擴大兩倍。後面調用update()函數來更新顯示。
4. 通過上一節的學習,我們應該已經知道想讓畫布的内容放大有兩個辦法,一個是直接放大畫布的坐标系統,一個是放大視窗的坐标系統。下面我們先來放大視窗的坐标系統。更改paintevent()函數如下:
qpainter pp(&pix);
pp.drawline(lastpoint, endpoint);
lastpoint = endpoint;
qpainter painter(this);
//進行放大操作
painter.scale(scale, scale);
painter.drawpixmap(0, 0, pix);
現在運作程式,先在白色畫布上任意繪制一個圖形,效果如下圖所示。
然後按下zoomin按鈕,效果如下圖所示。
現在再用滑鼠進行繪制,發現圖形已經不能和滑鼠軌迹重合了,效果如下圖所示。
有了前面一節的知識,就不難了解出現這個問題的原因了。視窗的坐标擴大了,但是畫布的坐标并沒有擴大,而我們畫圖用的坐标值是滑鼠指針的,滑鼠指針又是擷取的視窗的坐标值。現在視窗和畫布的同一點的坐标并不相等,是以就出現了這樣的問題。
其實解決辦法很簡單,視窗放大了多少倍,就将獲得的滑鼠指針的坐标值縮小多少倍就行了。我們将paintevent()函數更改如下:
pp.drawline(lastpoint/scale, endpoint/scale);
lastpoint = endpoint;
運作程式,效果如下圖所示。可以看到,已經能夠在放大以後繼續繪圖了。
這種用改變視窗坐标大小來改變畫布面積的方法,實際上是有損圖檔品質的。就像将一張位圖放大一樣,越放大越不清晰。原因就是,它的像素的個數沒有變,如果将可視面積放大,那麼機關面積裡的像素個數就變少了,是以畫質就差了。
5.方法二。擴大畫布坐标系統。先将paintevent()更改如下:
pp.scale(scale, scale);
pp.drawline(lastpoint,endpoint);
這時運作程式,先進行繪制,然後點選zoomin按鈕,發現以前的内容并沒有放大,而當我們再次繪畫時,發現滑鼠指針和繪制的線條又不重合了。效果如下圖所示。
這并不是我們想要的結果,為了實作按下放大按鈕,畫布和圖形都進行放大,我們可以使用緩沖畫布(就是一個輔助畫布)來實作。将paintevent()函數内容更改如下。
if(scale!=1) //如果進行放大操作
{
//臨時畫布,大小變化了scale倍
qpixmap copypix(pix.size()*scale);
qpainter pter(&copypix);
pter.scale(scale, scale);
//将以前畫布上的内容複制到現在的畫布上
pter.drawpixmap(0, 0, pix);
//将放大後的内容再複制回原來的畫布上
pix = copypix;
//讓scale重新置1
scale =1;
}
pp.scale(scale,scale);
pp.drawline(lastpoint/scale,endpoint/scale);
painter.drawpixmap(0,0,pix);
現在運作程式,效果如下圖所示。
結語
本節講到的塗鴉闆,隻是為了實踐前面的知識,起到抛磚引玉的作用。大家可以根據自己的了解繼續探究下去。在下一節,我們将講解怎樣在塗鴉闆上繪制出矩形、橢圓等圖形。
涉及到的源碼:
kb, 下載下傳次數: 22)