[Qt教程] 第17篇 2D繪圖(七)塗鴉板
樓主
發表於 2013-5-2 21:37:41 | 查看:
1255| 回複: 16

塗鴉板
版權聲明
該文章原創於Qter開源社區(www.qter.org),作者yafeilinux,轉載請注明出處!
導語
通過前麵幾節的學習,大家應該已經對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()函數如下:
void Dialog::paintEvent(QPaintEvent *)
{
QPainter pp(&pix);
pp.drawLine(lastPoint, endPoint);
lastPoint = endPoint;
QPainter painter(this);
//進行放大操作
painter.scale(scale, scale);
painter.drawPixmap(0, 0, pix);
}
現在運行程序,先在白色畫布上任意繪製一個圖形,效果如下圖所示。
![]()
然後按下zoomIn按鈕,效果如下圖所示。
![]() 現在再用鼠標進行繪製,發現圖形已經不能和鼠標軌跡重合了,效果如下圖所示。
![]() 有了前麵一節的知識,就不難理解出現這個問題的原因了。窗口的坐標擴大了,但是畫布的坐標並沒有擴大,而我們畫圖用的坐標值是鼠標指針的,鼠標指針又是獲取的窗口的坐標值。現在窗口和畫布的同一點的坐標並不相等,所以就出現了這樣的問題。
其實解決辦法很簡單,窗口放大了多少倍,就將獲得的鼠標指針的坐標值縮小多少倍就行了。我們將paintEvent()函數更改如下:
void Dialog::paintEvent(QPaintEvent *)
{
QPainter pp(&pix);
pp.drawLine(lastPoint/scale, endPoint/scale);
lastPoint = endPoint;
QPainter painter(this);
painter.scale(scale, scale);
painter.drawPixmap(0, 0, pix);
}
運行程序,效果如下圖所示。可以看到,已經能夠在放大以後繼續繪圖了。
![]() 這種用改變窗口坐標大小來改變畫布麵積的方法,實際上是有損圖片質量的。就像將一張位圖放大一樣,越放大越不清晰。原因就是,它的像素的個數沒有變,如果將可視麵積放大,那麼單位麵積裏的像素個數就變少了,所以畫質就差了。
5.方法二。擴大畫布坐標係統。先將paintEvent()更改如下:
void Dialog::paintEvent(QPaintEvent *)
{
QPainter pp(&pix);
pp.scale(scale, scale);
pp.drawLine(lastPoint,endPoint);
lastPoint = endPoint;
QPainter painter(this);
painter.drawPixmap(0, 0, pix);
}
這時運行程序,先進行繪製,然後點擊zoomIn按鈕,發現以前的內容並沒有放大,而當我們再次繪畫時,發現鼠標指針和繪製的線條又不重合了。效果如下圖所示。
![]() 這並不是我們想要的結果,為了實現按下放大按鈕,畫布和圖形都進行放大,我們可以使用緩衝畫布(就是一個輔助畫布)來實現。將paintEvent()函數內容更改如下。
void Dialog::paintEvent(QPaintEvent *)
{
if(scale!=1) //如果進行放大操作
{
//臨時畫布,大小變化了scale倍
QPixmap copyPix(pix.size()*scale);
QPainter pter(©Pix);
pter.scale(scale, scale);
//將以前畫布上的內容複製到現在的畫布上
pter.drawPixmap(0, 0, pix);
//將放大後的內容再複製回原來的畫布上
pix = copyPix;
//讓scale重新置1
scale =1;
}
QPainter pp(&pix);
pp.scale(scale,scale);
pp.drawLine(lastPoint/scale,endPoint/scale);
lastPoint = endPoint;
QPainter painter(this);
painter.drawPixmap(0,0,pix);
}
現在運行程序,效果如下圖所示。
![]() 結語
本節講到的塗鴉板,隻是為了實踐前麵的知識,起到拋磚引玉的作用。大家可以根據自己的理解繼續探究下去。在下一節,我們將講解怎樣在塗鴉板上繪製出矩形、橢圓等圖形。
涉及到的源碼: ![]() |
最後更新:2017-04-03 14:54:15