第7章 Qt 5圖形視圖框架
7.1 圖形視圖體系結(jié)構(gòu)
7.1.1 Graphics View的特點(diǎn)
Graphics View框架結(jié)構(gòu)的主要特點(diǎn)如下。
(1)Graphics View框架結(jié)構(gòu)中,系統(tǒng)可以利用Qt繪圖系統(tǒng)的反鋸齒、OpenGL工具來改善繪圖性能。
(2)Graphics View支持事件傳播體系結(jié)構(gòu),可以使圖元在場(chǎng)景(scene)中的交互能力提高1倍,圖元能夠處理鍵盤事件和鼠標(biāo)事件。其中,鼠標(biāo)事件包括鼠標(biāo)按下、移動(dòng)、釋放和雙擊,還可以跟蹤鼠標(biāo)的移動(dòng)。
(3)在Graphics View框架中,通過二元空間劃分樹(Binary Space Partitioning,BSP)提供快速的圖元查找,這樣就能夠?qū)崟r(shí)地顯示包含上百萬(wàn)個(gè)圖元的大場(chǎng)景。
7.1.2 Graphics View的三元素
它們?nèi)咧g的關(guān)系如圖7.1所示。
1.場(chǎng)景類:QGraphicsScene類
場(chǎng)景類主要完成的工作包括提供對(duì)它包含的圖元的操作接口和傳遞事件、管理各個(gè)圖元的狀態(tài)(如選擇和焦點(diǎn)處理)、提供無變換的繪制功能(如打?。┑取?br> 事件傳播體系結(jié)構(gòu)將場(chǎng)景事件發(fā)送給圖元,同時(shí)也管理圖元之間的事件傳播。如果場(chǎng)景接收到了在某一點(diǎn)的鼠標(biāo)單擊事件,場(chǎng)景會(huì)將事件傳給這一點(diǎn)的圖元。
管理各個(gè)圖元的狀態(tài)(如選擇和焦點(diǎn)處理)??梢酝ㄟ^QGraphicsScene:: setSelectionArea()函數(shù)選擇圖元,選擇區(qū)域可以是任意的形狀,使用QPainterPath表示。若要得到當(dāng)前選擇的圖元列表,則可以使用函數(shù)QGraphicsScene:: selectedItems()??梢酝ㄟ^QGraphicsScene:: setFocusItem()函數(shù)或QGraphicsScene:: setFocus()函數(shù)來設(shè)置圖元的焦點(diǎn),獲得當(dāng)前具有焦點(diǎn)的圖元使用函數(shù)QGraphicsScene::focusItem()。
2.視圖類:QGraphicsView類
QGraphicsView是可滾動(dòng)的窗口部件,可以提供滾動(dòng)條來瀏覽大的場(chǎng)景。如果需要使用OpenGL,則可以使用QGraphicsView::setViewport()將視圖設(shè)置為QGLWidget。
視圖接收鍵盤和鼠標(biāo)的輸入事件,并將它們翻譯為場(chǎng)景事件(將坐標(biāo)轉(zhuǎn)換為場(chǎng)景的坐標(biāo))。使用變換矩陣函數(shù)QGraphicsView::matrix()可以變換場(chǎng)景的坐標(biāo),實(shí)現(xiàn)場(chǎng)景縮放和旋轉(zhuǎn)。QGraphicsView提供QGraphicsView::mapToScene()和QGraphicsView:: mapFromScene()用于與場(chǎng)景的坐標(biāo)進(jìn)行轉(zhuǎn)換。
3.圖元類:QGraphicsItem類
它是場(chǎng)景中各個(gè)圖元的基類,在它的基礎(chǔ)上可以繼承出各種圖元類,Qt已經(jīng)預(yù)置的包括直線(QGraphicsLineItem)、橢圓(QGraphicsEllipseItem)、文本圖元(QGraphicsTextItem)、矩形(QGraphicsRectItem)等。
QGraphicsItem主要有以下功能。
? 處理鼠標(biāo)按下、移動(dòng)、釋放、雙擊、懸停、滾輪和右鍵菜單事件。
? 處理鍵盤輸入事件。
? 處理拖曳事件。
? 分組。
? 碰撞檢測(cè)。
7.1.3 GraphicsView的坐標(biāo)系統(tǒng)
1.場(chǎng)景坐標(biāo)
場(chǎng)景坐標(biāo)是所有圖元的基礎(chǔ)坐標(biāo)系統(tǒng)。場(chǎng)景坐標(biāo)系統(tǒng)描述了頂層的圖元,每個(gè)圖元都有場(chǎng)景坐標(biāo)和相應(yīng)的包容框。場(chǎng)景坐標(biāo)的原點(diǎn)在場(chǎng)景中心,坐標(biāo)原點(diǎn)是x軸正方向向右,y軸正方向向下。
QGraphicsScene類的坐標(biāo)系以中心為原點(diǎn)(0,0),如圖7.2所示。
2.視圖坐標(biāo)
視圖坐標(biāo)是窗口部件的坐標(biāo)。視圖坐標(biāo)的單位是像素。QGraphicsView視圖的左上角是(0,0),x軸正方向向右,y軸正方向向下。所有的鼠標(biāo)事件最開始都是使用視圖坐標(biāo)。
QGraphicsView類繼承自QWidget類,因此它與其他的QWidget類一樣,以窗口的左上角作為自己坐標(biāo)系的原點(diǎn),如圖7.3所示。
3.圖元坐標(biāo)
圖元使用自己的本地坐標(biāo),這個(gè)坐標(biāo)系統(tǒng)通常以圖元中心為原點(diǎn),這也是所有變換的原點(diǎn)。圖元坐標(biāo)方向是x軸正方向向右,y軸正方向向下。創(chuàng)建圖元后,只需注意圖元坐標(biāo)就可以了,QGraphicsScene和QGraphicsView會(huì)完成所有的變換。
QGraphicsItem類的坐標(biāo)系,若在調(diào)用QGraphicsItem類的paint()函數(shù)重繪圖元時(shí),則以此坐標(biāo)系為基準(zhǔn),如圖7.4所示。
Graphics View框架提供了多種坐標(biāo)變換函數(shù),見表7.1。
7.2 【實(shí)例】:圖形視圖
7.2.1 飛舞的蝴蝶
【例】(難度中等)(CH701)設(shè)計(jì)界面,一個(gè)蝴蝶在屏幕上不停地上下飛舞。
操作步驟如下。
(1)新建Qt Widgets Application(詳見1.3.1節(jié)),項(xiàng)目名為“Butterfly”,基類選擇“QMainWindow”,類名命名默認(rèn)為“MainWindow”,取消“創(chuàng)建界面”復(fù)選框的選中狀態(tài)。單擊“下一步”按鈕,最后單擊“完成”按鈕,完成該項(xiàng)目工程的建立。
(2)在“Butterfly”項(xiàng)目名上單擊鼠標(biāo)右鍵,在彈出的快捷菜單中選擇“添加新文件…”菜單項(xiàng),在彈出的對(duì)話框中選擇“C++ Class”選項(xiàng)。單擊“Choose…”按鈕,彈出對(duì)話框,在“Base class”后面的下拉列表框中選擇基類名“QObject”,在“Class name”后面的文本框中輸入類的名稱“Butterfly”。
(3)單擊“下一步”按鈕,單擊“完成”按鈕,添加文件“butterfly.h”和“butterfly. cpp”。
(4)Butterfly類繼承自QObject類、QGraphicsItem類,在頭文件“butterfly.h”中完成的代碼具體內(nèi)容。
(5)在源文件“butterfly. cpp”中完成的代碼具體內(nèi)容如下:
#include "butterfly.h"
#include <math.h>
const static double PI=3.1416;
Butterfly::Butterfly(QObject *parent) : QObject(parent)
{
up = true; //給標(biāo)志蝴蝶翅膀位置的變量賦初值
pix_up.load("up.png"); //調(diào)用QPixmap的load()函數(shù)加載所用到的圖片
pix_down.load("down.png");
startTimer(100); //啟動(dòng)定時(shí)器,并設(shè)置時(shí)間間隔為100毫秒
}
boundingRect()函數(shù)為圖元限定區(qū)域范圍。此范圍是以圖元自身的坐標(biāo)系為基礎(chǔ)設(shè)定的。具體實(shí)現(xiàn)代碼內(nèi)容如下:
QRectF Butterfly::boundingRect() const
{
qreal adjust =2;
return QRectF(-pix_up.width()/2-adjust,-pix_up.height()/2-adjust,
pix_up.width()+adjust*2,pix_up.height()+adjust*2);
}
在重畫函數(shù)paint()中,首先判斷當(dāng)前已顯示的圖片是pix_up還是pix_down。實(shí)現(xiàn)蝴蝶翅膀上下飛舞效果時(shí),若當(dāng)前顯示的是pix_up圖片,則重繪pix_down圖片,反之亦然。具體實(shí)現(xiàn)代碼內(nèi)容如下:
void Butterfly::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
if(up)
{
painter->drawPixmap(boundingRect().topLeft(),pix_up);
up=!up;
}
else
{
painter->drawPixmap(boundingRect().topLeft(),pix_down);
up=!up;
}
}
定時(shí)器的timerEvent()函數(shù)實(shí)現(xiàn)蝴蝶的飛舞,具體實(shí)現(xiàn)代碼內(nèi)容如下:
void Butterfly::timerEvent(QTimerEvent *)
{
//邊界控制
qreal edgex=scene()->sceneRect().right()+boundingRect().width()/2;
//限定蝴蝶飛舞的右邊界
qreal edgetop=scene()->sceneRect().top()+boundingRect(). height()/2; //限定蝴蝶飛舞的上邊界
qreal edgebottom=scene()->sceneRect().bottom()+boundingRect(). height()/2; //限定蝴蝶飛舞的下邊界
if(pos().x()>=edgex) //若超過了右邊界,則水平移回左邊界處
setPos(scene()->sceneRect().left(),pos().y());
if(pos().y()<=edgetop) //若超過了上邊界,則垂直移回下邊界處
setPos(pos().x(),scene()->sceneRect().bottom());
if(pos().y()>=edgebottom) //若超過了下邊界,則垂直移回上邊界處
setPos(pos().x(),scene()->sceneRect().top());
angle+=(qrand()%10)/20.0;
qreal dx=fabs(sin(angle*PI)*10.0);
qreal dy=(qrand()%20)-10.0;
setPos(mapToParent(dx,dy)); //(a)
}
(6)完成了蝴蝶圖元的實(shí)現(xiàn)后,在源文件“main.cpp”中將它加載到場(chǎng)景中,并關(guān)聯(lián)一個(gè)視圖,具體實(shí)現(xiàn)代碼內(nèi)容如下:
#include <QApplication>
#include "butterfly.h"
#include <QGraphicsScene>
int main(int argc,char* argv[])
{
QApplication a(argc,argv);
QGraphicsScene *scene = new QGraphicsScene;
scene->setSceneRect(QRectF(-200,-200,400,400));
Butterfly *butterfly = new Butterfly;
butterfly->setPos(-100,0);
scene->addItem(butterfly);
QGraphicsView *view = new QGraphicsView;
view->setScene(scene);
view->resize(400,400);
view->show();
return a.exec();
}
(7)運(yùn)行程序,將程序中用到的圖片保存到該工程的D:\Qt\CH7\CH701\build-Butterfly-Desktop_Qt_5_8_0_MinGW_32bit-Debug文件夾中,運(yùn)行結(jié)果如圖7.5所示。
7.2.2 地圖瀏覽器
【例】(難度中等)(CH702)設(shè)計(jì)一個(gè)地圖瀏覽器,包括地圖的瀏覽、放大、縮小,以及顯示各點(diǎn)的坐標(biāo)等,如圖7.6所示。
操作步驟如下。
(1)新建Qt Widgets Application (詳見1.3.1節(jié)),項(xiàng)目名稱為“MapWidget”,基類選擇“QMainWindow”,類名命名默認(rèn)為“MainWindow”,取消“創(chuàng)建界面”復(fù)選框的選中狀態(tài)。單擊“下一步”按鈕,最后單擊“完成”按鈕,完成該項(xiàng)目工程的建立。
(2)在“MapWidget”項(xiàng)目名上單擊鼠標(biāo)右鍵,在彈出的快捷菜單中選擇“添加新文件…”菜單項(xiàng),在彈出的對(duì)話框中選擇“C++ Class”選項(xiàng)。單擊“Choose…”按鈕,彈出對(duì)話框,在“Base class”后面的文本框中輸入基類名“QGraphicsView”(手工添加),在“Class name”后面的文本框中輸入類的名稱“MapWidget”。
(3)單擊“下一步”按鈕,單擊“完成”按鈕,添加文件“mapwidget.h”和文件“mapwidget.cpp”。
(4)MapWidget類繼承自QGraphicsView類,作為地圖瀏覽器的主窗體。在頭文件“mapwidget.h”中完成的代碼。
(5)在源文件“mapwidget.cpp”中完成的代碼。
(6)新建一個(gè)文本文件“maps.txt”,利用該文本文件描述與地圖相關(guān)的信息,將該文件保存在該工程下的D:\Qt\CH7\CH702\ build-MapWidget-Desktop_Qt_5_ 4_0_ MinGW_32bit-Debug文件中,文件內(nèi)容為:
China.jpg 114.4665527 35.96022297 119.9597168 31.3911575
(7)打開“mapwidget.cpp”文件,添加讀取地圖信息readMap()函數(shù)的具體實(shí)現(xiàn)代碼如下:
void MapWidget::readMap() //讀取地圖信息
{
QString mapName;
QFile mapFile("maps.txt"); //(a)
int ok = mapFile.open(QIODevice::ReadOnly);//以“只讀”方式打開此文件
if(ok) //分別讀取地圖的名稱和四個(gè)經(jīng)緯度信息
{
QTextStream ts(&mapFile);
if(!ts.atEnd())
{
ts>>mapName;
ts>>x1>>y1>>x2>>y2;
}
}
map.load(mapName); //將地圖讀取至私有變量map中
}
根據(jù)縮放滑動(dòng)條的當(dāng)前值,確定縮放的比例,調(diào)用scale()函數(shù)實(shí)現(xiàn)地圖縮放。完成地圖縮放功能的slotZoom()函數(shù)的具體實(shí)現(xiàn)代碼內(nèi)容如下:
void MapWidget::slotZoom(int value) //地圖縮放
{
qreal s;
if(value>zoom) //放大
{
s=pow(1.01,(value-zoom));
}
else //縮小
{
s=pow(1/1.01,(zoom-value));
}
scale(s,s);
zoom = value;
}
QGraphicsView類的drawBackground()函數(shù)中以地圖圖片重繪場(chǎng)景的背景來實(shí)現(xiàn)地圖顯示。具體實(shí)現(xiàn)代碼如下:
void MapWidget::drawBackground(QPainter *painter, const QRectF &rect)
{
painter->drawPixmap(int(sceneRect().left()),int(sceneRect(). top()), map);
}
響應(yīng)鼠標(biāo)移動(dòng)事件mouseMoveEvent()函數(shù),完成某點(diǎn)在各層坐標(biāo)中的映射及顯示。具體實(shí)現(xiàn)代碼如下:
void MapWidget::mouseMoveEvent(QMouseEvent *event)
{
//QGraphicsView 坐標(biāo)
QPoint viewPoint = event->pos();
viewCoord->setText(QString::number(viewPoint.x())+","+
QString::number(viewPoint.y()));
//QGraphicsScene 坐標(biāo)
QPointF scenePoint = mapToScene(viewPoint);
sceneCoord->setText(QString::number(scenePoint.x())+","+
QString::number(scenePoint.y()));
//地圖坐標(biāo)(經(jīng)、緯度值)
QPointF latLon = mapToMap(scenePoint);
mapCoord->setText(QString::number(latLon.x())+","+
QString::number(latLon.y()));
}
完成從場(chǎng)景坐標(biāo)至地圖坐標(biāo)的轉(zhuǎn)換mapToMap()函數(shù)。具體實(shí)現(xiàn)代碼如下:
QPointF MapWidget::mapToMap(QPointF p)
{
QPointF latLon;
qreal w =sceneRect().width();
qreal h =sceneRect().height();
qreal lon = y1-((h/2+p.y())*abs(y1-y2)/h);
qreal lat = x1+((w/2+p.x())*abs(x1-x2)/w);
latLon.setX(lat);
latLon.setY(lon);
return latLon;
}
(8)下面是文件“main.cpp”的具體代碼:
#include <QApplication>
#include "mapwidget.h"
#include <QFont>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QFont font("ARPL KaitiM GB",12);
font.setBold(true);
a.setFont(font);
MapWidget mapWidget;
mapWidget.show();
return a.exec();
}
(9)將程序用到的圖片保存到該工程的D:\Qt\CH7\CH702\build-MapWidget-Desktop_Qt_5_8_0_MinGW_32bit-Debug文件夾中,運(yùn)行結(jié)果如圖7.6所示。
7.2.3 圖元?jiǎng)?chuàng)建
【例】(難度中等)(CH703)設(shè)計(jì)窗體,顯示各種類型QGraphicsItem(包括不停閃爍的圓及來回移動(dòng)的星星等),如圖7.7所示。
實(shí)現(xiàn)步驟如下。
(1)新建Qt Widgets Application(詳見1.3.1節(jié)),項(xiàng)目名稱為“GraphicsItem”,基類選擇“QMainWindow”,類名命名默認(rèn)為“MainWindow”,取消“創(chuàng)建界面”復(fù)選框的選中狀態(tài)。單擊“下一步”按鈕,最后單擊“完成”按鈕,完成該項(xiàng)目工程的建立。
(2)MainWindow類繼承自QMainWindow作為主窗體,包含一個(gè)加入圖元的各種操作的菜單欄,以及一個(gè)顯示各種類型圖元的QGraphicsView作為主窗體的centralWidget?!癿ainwindow.h”文件的具體代碼實(shí)現(xiàn)內(nèi)容。
(3)“mainwindow.cpp”文件中的代碼。
(4)將程序中所用圖片保存到該工程的D:\Qt\CH7\CH703\build-GraphicsItem-Desktop_Qt_5_8_0_MinGW_32bit-Debug文件夾下,此時(shí)運(yùn)行效果如圖7.8所示。
以上完成了主窗體的顯示工作,下面介紹如何實(shí)現(xiàn)圓的閃爍功能。
(1)在“GraphicsItem”項(xiàng)目名上單擊鼠標(biāo)右鍵,在彈出的快捷菜單中選擇“添加新文件…”菜單項(xiàng),在彈出的對(duì)話框中選擇“C++ Class”選項(xiàng)。單擊“Choose…”按鈕,彈出對(duì)話框,在“Base class”后面的下拉列表框中選擇基類名“QObject”,在“Class name”后面的文本框中輸入類的名稱“FlashItem”。
(2)單擊“下一步”按鈕,單擊“完成”按鈕,添加文件“flashitem.h”和文件“flashitem.cpp”。
(3)“flashitem.h”文件的具體代碼如下:
#include <QGraphicsItem>
#include <QPainter>
class FlashItem : public QObject,public QGraphicsItem
{
Q_OBJECT
public:
explicit FlashItem(QObject *parent = 0);
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
void timerEvent(QTimerEvent *);
private:
bool flash;
QTimer *timer;
signals:
public slots:
};
(4)“flashitem.cpp”文件的具體代碼如下:
#include "flashitem.h"
FlashItem::FlashItem(QObject *parent) : QObject(parent)
{
flash=true; //為顏色切換標(biāo)識(shí)賦初值
setFlag(ItemIsMovable); //(a)
startTimer(1000); //啟動(dòng)一個(gè)定時(shí)器,以1000毫秒為時(shí)間間隔
}
定義圖元邊界的函數(shù)boundingRect(),完成以圖元坐標(biāo)系為基礎(chǔ),增加兩個(gè)像素點(diǎn)的冗余工作。具體實(shí)現(xiàn)代碼如下:
QRectF FlashItem::boundingRect() const
{
qreal adjust = 2;
return QRectF(-10-adjust,-10-adjust,43+adjust,43+adjust);
}
為自定義圖元重繪的函數(shù)paint()具體實(shí)現(xiàn)代碼如下:
void FlashItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
painter->setPen(Qt::NoPen); //閃爍圖元的陰影區(qū)不繪制邊線
painter->setBrush(Qt::darkGray); //閃爍圖元的陰影區(qū)的陰影畫刷顏色為深灰
painter->drawEllipse(-7,-7,40,40); //繪制陰影區(qū)
painter->setPen(QPen(Qt::black,0));
//閃爍區(qū)的橢圓邊線顏色為黑色、線寬為0
painter->setBrush(flash?(Qt::red):(Qt::yellow)); //(a)
painter->drawEllipse(-10,-10,40,40); //(b)
}
定時(shí)器響應(yīng)函數(shù)timerEvent()完成顏色切換標(biāo)識(shí)的反置,并在每次反置后調(diào)用update()函數(shù)重繪圖元以實(shí)現(xiàn)閃爍的效果。具體實(shí)現(xiàn)代碼如下:
void FlashItem::timerEvent(QTimerEvent *)
{
flash=!flash;
update();
}
(5)在“mainwindow.h”文件中添加代碼如下:
public slots:
void slotAddFlashItem();
private:
QAction *addFlashItemAct;
(6)在“mainwindow.cpp”文件中添加代碼如下:
#include "flashitem.h"
其中,在createActions()函數(shù)中添加代碼如下:
addFlashItemAct = new QAction(tr("加入閃爍圓"),this);
connect(addFlashItemAct,SIGNAL(triggered()),this,SLOT(slotAddFlashItem()));
在createMenus()函數(shù)中添加代碼如下:
itemsMenu->addAction(addFlashItemAct);
在initScene()函數(shù)中添加代碼如下:
for(i=0;i<3;i++)
slotAddFlashItem();
函數(shù)slotAddFlashItem()具體實(shí)現(xiàn)代碼如下:
void MainWindow::slotAddFlashItem() //在場(chǎng)景中加入一個(gè)閃爍圖元
{
FlashItem *item = new FlashItem;
scene->addItem(item);
item->setPos((qrand()%int(scene->sceneRect().width()))-200,
(qrand()%int(scene->sceneRect().height()))-200);
}
(7)運(yùn)行效果如圖7.9所示。
下面將接著完成實(shí)現(xiàn)星星移動(dòng)的功能。
(1)向項(xiàng)目中添加一個(gè)新的C++類,類名命名為“StartItem”,操作步驟同前。StartItem類繼承自QGraphicsItem類,實(shí)際上是一個(gè)圖片圖元。
“startitem.h”文件的具體代碼如下:
#include <QGraphicsItem>
#include <QPainter>
class StartItem : public QGraphicsItem
{
public:
StartItem();
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
private:
QPixmap pix;
};
(2)StartItem構(gòu)造函數(shù)中僅完成讀取圖片信息的工作。
“startitem.cpp”文件中的具體代碼如下:
#include "startitem.h"
StartItem::StartItem()
{
pix.load("star.png");
}
定義圖元的邊界函數(shù)boundingRect(),它是所有自定義圖元均必須實(shí)現(xiàn)的函數(shù),代碼如下:
QRectF StartItem::boundingRect() const
{
return QRectF(-pix.width()/2,-pix.height()/2,pix.width(),pix. height());
}
自定義圖元重繪函數(shù)paint(),代碼如下:
void StartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,QWidget *widget)
{
painter->drawPixmap(boundingRect().topLeft(),pix);
}
(3)在“mainwindow.h”文件中添加代碼如下:
public slots:
void slotAddAnimationItem();
private:
QAction *addAnimItemAct;
(4)在“mainwindow.cpp”文件中添加代碼如下:
#include "startitem.h"
#include <QGraphicsItemAnimation>
#include <QTimeLine>
其中,在createActions()函數(shù)中添加代碼如下:
addAnimItemAct = new QAction(tr("加入 星星"),this);
connect(addAnimItemAct,SIGNAL(triggered()),this,SLOT(slotAddAnimationItem()));
在createMenus()函數(shù)中添加代碼如下:
itemsMenu->addAction(addAnimItemAct);
在initScene()函數(shù)中添加代碼如下:
for(i=0;i<3;i++)
slotAddAnimationItem();
實(shí)現(xiàn)函數(shù)slotAddAnimationItem()的具體代碼如下:
void MainWindow::slotAddAnimationItem() //在場(chǎng)景中加入一個(gè)動(dòng)畫星星
{
StartItem *item = new StartItem;
QGraphicsItemAnimation *anim = new QGraphicsItemAnimation;
anim->setItem(item);
QTimeLine *timeLine = new QTimeLine(4000);
timeLine->setCurveShape(QTimeLine::SineCurve);
timeLine->setLoopCount(0);
anim->setTimeLine(timeLine);
int y =(qrand()%400)-200;
for(int i=0;i<400;i++)
{
anim->setPosAt(i/400.0,QPointF(i-200,y));
}
timeLine->start();
scene->addItem(item);
}
(5)最終運(yùn)行結(jié)果如圖7.7所示,圖中的小星星會(huì)不停地左右移動(dòng)。
7.2.4 圖元的旋轉(zhuǎn)、縮放、切變和位移
【例】(難度中等)(CH704)設(shè)計(jì)界面,實(shí)現(xiàn)蝴蝶各種變形。如圖7.10所示。
(1)新建Qt Widgets Application(詳見1.3.1節(jié)),項(xiàng)目名稱為“ItemWidget”,基類選擇“QWidget”,類名命名為“MainWidget”,取消“創(chuàng)建界面”復(fù)選框的選中狀態(tài)。單擊“下一步”按鈕,最后單擊“完成”按鈕,完成該項(xiàng)目工程的建立。
(2)MainWidget類繼承自QWidget,作為主窗體類,用于對(duì)圖元的顯示,包含一個(gè)控制面板區(qū)及一個(gè)顯示區(qū)。
“mainwidget.h”文件中的代碼如下:
#include <QWidget>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QFrame>
class MainWidget : public QWidget
{
Q_OBJECT
public:
MainWidget(QWidget *parent = 0);
~MainWidget();
void createControlFrame();
private:
int angle;
qreal scaleValue;
qreal shearValue;
qreal translateValue;
QGraphicsView *view;
QFrame *ctrlFrame;
};
(3)“mainwidget.cpp”文件中的具體代碼。
右側(cè)的控制面板區(qū)分為旋轉(zhuǎn)控制區(qū)、縮放控制區(qū)、切變控制區(qū)及位移控制區(qū),每個(gè)區(qū)均由包含一個(gè)QSlider對(duì)象的QGroupBox對(duì)象實(shí)現(xiàn),具體實(shí)現(xiàn)代碼。
(4)運(yùn)行效果如圖7.11所示。
上面完成的是主窗體的功能,下面介紹用于變形顯示的圖元的制作。
(1)在“ItemWidget”項(xiàng)目名上單擊鼠標(biāo)右鍵,在彈出的快捷菜單中選擇“添加新文件…”菜單項(xiàng),在彈出的對(duì)話框中選擇“C++ Class”選項(xiàng)。單擊“Choose…”按鈕,彈出對(duì)話框,在“Base class”后面的文本框中輸入基類名“QGraphicsItem”(手工添加),在“Class name”后面的文本框中輸入類的名稱“PixItem”。
(2)單擊“下一步”按鈕,單擊“完成”按鈕,添加文件“pixitem.h”和文件“pixitem.cpp”。
(3)自定義PixItem類繼承自QGraphicsItem類。
“pixitem.h”文件中的具體代碼如下:
#include <QGraphicsItem>
#include <QPixmap>
#include <QPainter>
class PixItem : public QGraphicsItem
{
public:
PixItem(QPixmap *pixmap);
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
private:
QPixmap pix; //作為圖元顯示的圖片
};
(4)PixItem的構(gòu)造函數(shù)只是初始化了變量pix。“pixitem.cpp”文件中的具體內(nèi)容如下:
#include “pixitem.h”
PixItem::PixItem(QPixmap *pixmap)
{
pix = *pixmap;
}
定義圖元邊界的函數(shù)boundingRect(),完成以圖元坐標(biāo)系為基礎(chǔ)增加兩個(gè)像素點(diǎn)的冗余的工作。具體實(shí)現(xiàn)代碼如下:
QRectF PixItem::boundingRect() const
{
return QRectF(-2-pix.width()/2,-2-pix.height()/2,pix.width()+4, pix. height()+4);
}
重畫函數(shù)只需QPainter的drawPixmap()函數(shù)將圖元圖片繪出即可。具體代碼如下:
void PixItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,QWidget *widget)
{
painter->drawPixmap(-pix.width()/2,-pix.height()/2,pix);
}
(5)在“mainwidget.h”文件中添加代碼如下:
#include "pixitem.h"
private:
PixItem *pixItem;
(6)打開“mainwidget.cpp”文件,在語(yǔ)句scene->setSceneRect(-200,-200,400,400)與view = new QGraphicsView之間添加如下代碼:
QPixmap *pixmap = new QPixmap("image.png");
pixItem = new PixItem(pixmap);
scene->addItem(pixItem);
pixItem->setPos(0,0);
(7)運(yùn)行效果如圖7.12所示。
上述內(nèi)容只是完成了圖元圖片的加載顯示。下面介紹實(shí)現(xiàn)圖元的各種變形的實(shí)際功能。
(1)在“mainwidget.h”文件中添加槽函數(shù)聲明如下:
public slots:
void slotRotate(int);
void slotScale(int);
void slotShear(int);
void slotTranslate(int);
(2)在“mainwidget.cpp”文件中添加頭文件:
#include <math.h>
其中,在createControlFrame()函數(shù)中的QVBoxLayout *frameLayout=new QVBoxLayout語(yǔ)句之前添加以下代碼:
connect(rotateSlider,SIGNAL(valueChanged(int)),this,SLOT(slotRotate(int)));
connect(scaleSlider,SIGNAL(valueChanged(int)),this,SLOT(slotScale(int)));
connect(shearSlider,SIGNAL(valueChanged(int)),this,SLOT(slotShear(int)));
connect(translateSlider,SIGNAL(valueChanged(int)),this,SLOT(slotTranslate(int)));
實(shí)現(xiàn)圖元的旋轉(zhuǎn)功能函數(shù)slotRotate(),主要是調(diào)用QGraphicsView類的rotate()函數(shù)實(shí)現(xiàn)的,它的參數(shù)為旋轉(zhuǎn)角度的度數(shù)值,具體實(shí)現(xiàn)代碼如下:
void MainWidget::slotRotate(int value)
{
view->rotate(value-angle);
angle = value;
}
實(shí)現(xiàn)圖元的縮放功能函數(shù)slotScale(),主要是調(diào)用QGraphicsView類的scale()函數(shù)實(shí)現(xiàn)的,它的參數(shù)為縮放的比例,具體實(shí)現(xiàn)代碼如下:
void MainWidget::slotScale(int value)
{
qreal s;
if(value>scaleValue)
s=pow(1.1,(value-scaleValue));
else
s=pow(1/1.1,(scaleValue-value));
view->scale(s,s);
scaleValue=value;
}
實(shí)現(xiàn)圖元的切變功能函數(shù)slotShear(),主要是調(diào)用QGraphicsView類的shear()函數(shù)實(shí)現(xiàn)的,它的參數(shù)為切變的比例,具體實(shí)現(xiàn)代碼如下:
void MainWidget::slotShear(int value)
{
view->shear((value-shearValue)/10.0,0);
shearValue=value;
}
實(shí)現(xiàn)圖元的位移功能函數(shù)slotTranslate(),主要是調(diào)用QGraphicsView類的translate()函數(shù)實(shí)現(xiàn)的,它的參數(shù)為位移的大小,具體實(shí)現(xiàn)代碼如下:
void MainWidget::slotTranslate(int value)
{
view->translate(value-translateValue,value-translateValue);
translateValue=value;
}
(3)最終運(yùn)行結(jié)果如圖7.10所示,讀者可以試著拖曳滑塊觀看圖形的各種變換效果。
本章相關(guān)例程源碼下載
1.Qt5開發(fā)及實(shí)例_CH701.rar 下載
Qt5開發(fā)及實(shí)例_CH701.rar
2.Qt5開發(fā)及實(shí)例_CH702.rar 下載
Qt5開發(fā)及實(shí)例_CH702.rar
3.Qt5開發(fā)及實(shí)例_CH703.rar 下載
Qt5開發(fā)及實(shí)例_CH703.rar文章來源:http://www.zghlxwxcb.cn/news/detail-730993.html
4.Qt5開發(fā)及實(shí)例_CH704.rar 下載
Qt5開發(fā)及實(shí)例_CH704.rar文章來源地址http://www.zghlxwxcb.cn/news/detail-730993.html
到了這里,關(guān)于Qt5開發(fā)及實(shí)例V2.0-第七章-Qt圖形視圖框架的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!