1、GraphicsView框架簡介

QT4.2開始引入了Graphics View框架用來取代QT3中的Canvas模塊,並做出了改進,Graphics View框架實現了模型-視圖結構的圖形管理,能對大量圖元進行管理,支持碰撞檢測,座標變換和圖元組等多種方便的功能。框架

wKioL1hCZ9mzslUwAADgkFOxTRs344.png

    GraphicsView框架結構主要包含三個主要的類QGraphicsScene(場景)、QGraphicsView(視圖)、QGraphicsItem(圖元)。QGraphicsScene自己不可見,是一個存儲圖元的容器,必須經過與之相連的QGraphicsView視圖來顯示及與外界進行交互,主要提供圖元的操做接口、傳遞事件和管理各個圖元狀態,提供無變換的繪製功能(如打印);QGraphicsView提供一個可視的窗口,用於顯示場景中的圖元,一個場景中能夠有多個視圖。QGraphicsItem是場景中各個圖元的基礎類,QT提供了經常使用圖形圖元的標準類,如矩形(QGraphicsRectItem)、橢(QGraphicsEllipseItem)、文本(QGraphicsTextItem)。ide

    GraphicsView是一個基於圖元的Model/View架構的框架,每個組件都是一個獨立的元素。QPainter採用面向過程的描述方式繪圖;GraphicsView採用面向對象的描述方式繪圖。GraphicsView繪圖時首先建立一個場景,而後建立圖元對象(如一個直線對象、一個多邊形對象),再使用場景的add()函數,將圖元對象添加到場景中,最後經過視圖進行顯示。對於複雜的圖像來講,若是圖像包含大量的直線、曲線、多邊形等圖元對象,管理圖元對象比管理QPainter的繪製過程語句要容易,而且圖元對象更符合面向對象的思想,圖形的可複用性更好。函數

2、QGraphicsScene場景

    QGraphicsScene場景是QGraphicsItem對象的容器,主要功能以下: 工具

    A、提供管理大量圖元的快速接口 佈局

    B、傳播鼠標、鍵盤等事件給場景中的每一個圖元 字體

    C、管理圖元狀態,如圖元選擇和焦點處理 動畫

    D、提供無變換的渲染功能,如打印 spa

    經過函數QGraphicsScene::addItem()能夠加入一個圖元到場景中。圖元能夠經過多個函數進行檢索:QGraphicsScene::items()及重載函數能夠返回和點、矩形、多邊形或向量路徑相交的全部圖元。QGraphicsScene::itemAt()返回指定點的最頂層圖元。全部圖元查找函數按照遞減棧順序返回圖元,第一個返回的圖元位置最頂層,最後一個返回的圖元位於最底層。

    QGraphicsScene的事件傳播體系將場景事件發送給圖元,同時也管理圖元之間的事件傳播。若是場景收到了在某一點的鼠標單擊事件,場景會把事件傳給在這一點的最頂層圖元。QGraphicsScene負責管理一些圖元的狀態,如圖元選擇和焦點。經過QGraphicsScene::setSeletionArea()函數選擇多個圖元,選擇區域能夠是任意的形狀,使用 QPainterPath表示;要獲得當前選擇的圖元列表可使用 QGraphicsScene::selectedItems()函數;QGraphicsScene還管理圖元的鍵盤輸入焦點狀態,能夠經過QGraphicsScene::setFocusItem()函數或者QGraphicsItem::setFoucs()函數來設置圖元的焦點;得到當前具備焦點的圖元使用函數QGraphicsScene::foucsItem()。可使用 QGraphicsScene::render()函數在繪圖設備上繪製場景。 

3、QGraphicsView視圖

    QGraphicsView是視圖窗口部件,使場景內容可視化,能夠鏈接多個視圖到一個場景,也能夠爲相同數據源的數據集提供不一樣的視圖。QGraphicsView是可滾動的窗口部件,能夠提供滾動條來瀏覽大的場景。若是須要使用OpenGL,可使用QGraphicsView::setViewport()將視圖設置爲QGLWidget組件。

    視圖接收鍵盤和鼠標的輸入事件,並把事件翻譯爲場景事件(將座標轉換爲場景的座標),再發送到場景。使用變換矩陣函數QGraphicsView::martix()能夠變換場景的座標系統,經過變換場景的座標系統能夠實現場景的縮放和旋轉。爲了方便,QGraphicsView提供了視圖和場景的座標轉換函數:QGraphicsView::mapToScene()和QGraphicsView::mapFromScene()。 

4、QGraphicsItem圖元

    QGraphicsItem是圖元的基類。QGraphics View框架提供了多種標準的圖元: 

    QGraphicsEllipseItem 橢圓圖元

 QGraphicsLineItem     直線圖元

    QGraphicsPathItem     路徑圖元
    QGraphicsPixmapItem   圖像圖元

    QGraphicsPolygonItem  多邊形圖元
    QGraphicsRectItem     矩形圖元
    QGraphicsSimpleTextItem 簡單文本圖元
    QGraphicsTextItem     文本瀏覽圖元

    用戶能夠繼承QGraphicsItem實現自定義的圖元。

    QGraphicsItem圖元主要特性以下: 

    A、支持鼠標按下、移動、釋放、雙擊、懸停、滾動和右鍵菜單事件。 

    B、支持鍵盤輸入焦點和按鍵事件 

    C、支持拖拽事件

    D、支持分組,使用父子關係和QGraphicsItemGroup

    E、支持碰撞檢測 

    圖元存在於本地座標系統上,場景提供了在圖元和場景間、圖元與圖元間進行座標變換的函數。QGraphicsItem::transform()函數可使用矩陣轉換座標系統。這對於翻轉和縮放圖元是有用的。

    圖元能夠包含其餘圖元,父圖元的變換會被其全部的子圖元繼承。不管一個圖元自己有多少變換,圖元的全部函數(QGraphicsItem::contains(), QGraphicsItem::boundingRect(), QGraphicsItem::collidesWith())仍舊執行在本地座標系上。

    QGraphicsItem經過虛函數shape()和collideWith())來支持碰撞檢測。從shape()返回圖元的形狀(以本地座標QPainterPath表示),QGraphicsItem會處理全部的碰撞檢測。若是要提供本身的碰撞檢測,須要從新實現QGraphicsItem::collideWith()。

    碰撞檢測的方法:

    a、重寫shape()函數來返回圖元的精準輪廓,依靠默認的collidesWithItem()來作外形交集。若是item輪廓和複雜時候,消耗是很大的。
    b、重寫collidesWithItem(),提供一個本身的圖元和輪廓碰撞的算法
Contains()函數能夠調用,用來決定一個圖元是否包含一個點。Contains函數能夠重寫,contains()函數默認的方法是經過調用shape()來完成的。
    圖元中也能夠包含其餘的圖元,也能夠被別的圖元包含,全部的圖元能夠有一個父類圖元和多個子類圖元,除非一個圖元沒有父類,不然圖元的位置是在父類座標中,子類圖元將會繼承父類圖元的位置和轉換。 

    經過調用setVisible(),能夠設置圖元是否可見,隱藏一個圖元同時也隱藏了其子類,經過調用 setEnabled()來是指圖元是否可用。若是禁用了圖元,那麼其全部的子類都不可用。圖元默認都是可見和可用的。

5、GraphicsView座標系統

    Graphics View座標系基於笛卡爾座標系,圖元的場景中的位置和幾何形狀經過x座標和y座標表示。當使用沒有變換的視圖觀察場景時,場景中的一個單位對應屏幕上的一個像素。

    Graphics View架構中有三個有效的座標系統,圖元座標、場景座標和視圖座標。Graphics View提供了三個座標系統之間的轉換函數。在繪製圖形時,QGraphics View的場景座標對應QPainter的邏輯座標,QGraphics View的視圖座標對應QPainter的設備座標。 

一、圖元座標 

    圖元存在於本身的本地座標上,圖元的座標系統一般以圖元中心爲原點,圖元中心也是全部座標變換的原點,圖元座標方向是x軸正方向向右,y軸正方向向下。建立自定義圖元時,只須要注意圖元的座標,QGraphicsScene和QGraphicsView會完成全部的變換。 例如,若是接受到一個鼠標按下或拖入事件,所給的事件位置是基於圖元座標系的。若是某個點位於圖元內部,使用圖元上的點做爲QGraphicsItem::contains()虛函數的參數,函數會返回true。相似,圖元的邊界矩形和形狀也是基於圖元座標系。

    圖元的位置是圖元的中心點在其父圖元座標系統的座標。按這種說法,場景是全部無父圖元的圖元的父圖元。頂層圖元的位置是場景座標。

wKioL1hCZ_6zyHecAACPjX725s4423.png

 

子圖元的座標與父圖元的座標相關。若是子圖元無變換,子圖元座標和父圖元座標之間的區別與他們的父圖元的座標相同。例如,若是一個無變換的子圖元精確的位於父圖元的中心點,父子圖元的座標系統是相同的。若是子圖元的位置是(10,0),子圖元上的點(0,10)就是父圖元上的點(10,10)。

因爲圖元的位置和變換與父圖元相關,但子圖元的座標並不會被父圖元的變換影響,雖然父圖元的變換會隱式地變換子圖元。在上例中,即便父圖元被翻轉和縮放,子圖元上的點(0,10)仍舊是父圖元上的點(10,10)。

    若是調用QGraphicsItem類的paint()函數重繪圖元時,則以圖元座標系爲基準。

二、場景座標 

    場景座標是全部圖元的基礎座標系統。場景座標系統描述了頂層圖元的位置,而且構成從視圖傳播到場景的全部場景事件的基礎。每一個圖元在場景上都有場景座標和邊界矩形。場景座標的原點在場景中心,座標原點是X軸正方向向右,Y軸正方向向下。

wKiom1hCaBzznyLgAABQlPpPquk204.png

三、視圖座標 

    視圖座標是窗口部件的座標,視圖座標的單位是像素,QGraphicsView的左上角是(0,0)。全部鼠標事件、拖拽事件最開始都使用視圖座標,爲了和圖元交互,須要轉換座標爲場景座標。

wKiom1hCaDmQoeO3AABAsC66bUs857.png

四、座標變換 

    在Graphics View框架中,常常須要將多種座標變換,從場景到圖元,從圖元到圖元,從視圖到場景 。QGraphics View框架座標變換函數以下:

QGraphicsView::mapToScene()視圖到場景

QGraphicsView::mapFromScene() 場景到視圖

QGraphicsItem::mapFromScene()  場景到圖元

QGraphicsItem::mapToScene()  圖元到場景

QGraphicsItem::mapToParent()  子圖元到父圖元

QGraphicsItem::mapFromParent() 父圖元到子圖元

QGraphicsItem::mapToItem()本圖元到其餘圖元

QGraphicsItem::mapFromItem()其餘圖元到本圖元

    在場景中處理圖元時,從場景到圖元、從圖元到圖元、從視圖到場景進行座標和圖形變換是有用的。當在QGraphicsView的視口中點擊鼠標時,應該經過調用QGraphicsView::mapToScence()與QGraphicsScene::itemAt()來獲知光標下是場景中的哪一個圖元;若是想獲知一個圖元位於視口中的位置,應該先在圖元上調用QGraphicsItem::mapToScene(),而後調用QGraphicsView::mapFromScene();若是想獲知在一個視圖橢圓中有哪些圖元,應該把QPainterPath傳遞到mapToScene(),而後再把映射後的路徑傳遞到QGraphicsScene::items()。 能夠調用QGraphicsItem::mapToScene()與QGraphicsItem::mapFromScene()在圖元與場景之間進行座標與形狀的映射,也能夠在子圖元與其父圖元之間經過QGraphicsItem::mapToParent()與QGraphicsItem::mapFromItem()進行映射。全部映射函數能夠包括點、矩形、多邊形、路徑。視圖與場景之間的映射也與此相似。對於視圖與圖元之間的映射,應該先從視圖映射到場景,而後再從場景圖映射到圖元。

6、GraphicsView框架特性

一、縮放與旋轉

    QGraphicsView經過QGraphicsView::setMatrix()支持同QPainter同樣的座標變換,經過對一個視圖應用變換,能夠很容易地支持普通的導航特性如縮放與旋轉。

二、打印

    圖形視圖架構經過渲染函數QGraphicsScene::render()和QGraphicsView::render()支持單行打印

場景和視圖的渲染函數的不一樣在於QGraphicsScene::render()使用場景座標,QGraphicsView::render()使用視圖座標。QGraphicsScene::render()常常用於打印未變換場景中的整塊,例如一塊圖形數據或是打印一個文本文檔。    QGraphicsView::render()適合用於截屏,默認會使用繪圖設備精確渲染視口的內容。

QGraphicsScene scene;

scene.addRect(QRectF(0, 0, 100, 200), QPen(Qt::black), QBrush(Qt::green));

QPixmap pixmap;

QPainter painter(&pixmap);

painter.setRenderHint(QPainter::Antialiasing);

scene.render(&painter);

painter.end();

pixmap.save("scene.png");

    當源和目標區尺寸不匹配時,源的內容會比例縮放適合目標區。

三、拖拽

    因爲QGraphicsView繼承自QWidget,GraphicsView一樣提供了拖拽功能。此外,爲了方便,GraphicsView框架也爲場景、圖元提供拖拽支持。當視圖接收到拖拽事件,GraphicsView框架會將拖拽事件翻譯爲QGraphicsSceneDragDropEvent事件,再發送到場景,場景接管事件,再把事件發送到光標下接受拖拽的第一個圖元。
    爲了開啓圖元拖拽,建立一個QDrag對象,傳遞啓動拖拽的QWidget的指針。圖元能夠同時被多個視圖觀察,但只有一個視圖能夠拖拽圖元。一般,拖拽是從按下鼠標或是移動鼠標開始的,在mousePressEvent()或mouseMoveEvent()中,能夠從事件中獲得原始的QWidget指針。

void CustomItem::mousePressEvent(QGraphicsSceneMouseEvent *event)

  {

      QMimeData *data = new QMimeData;

      data->setColor(Qt::green);

      QDrag *drag = new QDrag(event->widget());

      drag->setMimeData(data);

      drag->start();

  }

    要在場景中取拖拽事件,須要從新實現QGraphicsScene::dragEnterEvent()和QGraphicsItem子類裏特定場景須要的事件處理器。

    圖元也能夠經過調用QGraphicsItem::setAcceptDrops()得到拖拽支持,爲了處理將要進行的拖拽,須要從新實現QGraphicsItem的dragEnterEvent()、dragMoveEvent()、dropEvent()、dragLeaveEvent() 。

四、光標與工具提示

    QGraphicsItem支持光標(QgraphicsItem::setCursor)與工具提示(QGraphicsItem::setToolTip())。當光標進入到圖元的區域,光標與工具提示被QGraphicsView激活(經過調用QGraphicsItem::contains()檢測),也能夠直接在視圖上設置一個缺省光標(QGraphicsView::setCursor)。

五、動畫

    GraphicsView框架支持多種層次的動畫。使用動畫框架能夠很容易製做出動畫。

GraphicsView框架支持的動畫實現種類以下:

    A、圖元須要繼承自QGraphicsObject,而且須要聯結QPropertyAnimation屬性。

    B、建立繼承自QObject和QGraphicsItem的圖元,圖元能夠設置本身的定時器,在QObject::timeEvent()中增長步進的方式來控制動畫。
    C、經過調用QGraphicsScene::advance()來推動場景,依次調用QGraphicsItem::advance()。

六、OpenGL渲染

    爲了使用OpenGL渲染,須要設置一個新的QGLWidget做爲QGraphicsView的視口:QGraphicsView::setViewPort()。若是須要OpenGL提供反鋸齒功能,則須要OpenGL採樣緩衝支持。
QGraphicsView view(&scene);
view.setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));

七、圖元組

    經過把一個圖元作爲另外一個圖元的孩子,能夠獲得圖元組的大多數本質特性:全部圖元會一塊兒移動,全部變換會從父到子傳遞。

    另外,QGraphicsItemGroup是一個特殊的圖元。爲了增長和刪除圖元,它使用一個有用接口合併了子圖元的事件處理。把一個圖元加到QGraphicsItemGroup仍會保留圖元的原始位置與變換,而給一個圖元從新指定父圖元則會讓圖元根據其新的父親從新定位。能夠用QGraphicsScene::createItemGroup()建立圖元組。

八、圖形組件和佈局

    QT4.4經過QGraphicsWidget支持圖形和圖元佈局。QGraphicsWidget相似於QWidget,但QGraphicsWidget並不從QPaintDevice繼承,而是繼承自QGraphicsItem。QGraphicsWidget支持事件、信號與槽、大小和策略。經過QGraphicsLinearLayout、QGraphicsGridLayout能夠對圖形組件進行佈局管理。

    QGraphicsWidget繼承了QWidget和QGraphicsItem的優勢,如QWidget的樣式、字體、調色板、佈局方向以及QGraphicsItem的圖形、獨立精度和變換支持。

    QGraphicsLayout是專爲QGraphicsWidget特殊設計的第二代佈局框架。QGraphicsLayout的API相似於QLayout。經過QGraphicsLinearLayout和QGraphicsGridLayout能夠管理組件與子佈局。

九、嵌入組件

圖形視圖框架爲嵌入任何組件到場景提供了無縫支持。能夠嵌入簡單的組件,如QLineEdit、QPushButton,或是複雜的組件如QTableWidget,甚至是主窗口。

要嵌入組件到場景,只須要調用QGraphicsScene::addWidget(),或是建立一個QGraphicsProxyWidget實例,手動嵌入組件。

    經過QGraphicsProxyWidget,圖形視圖框架能夠深度整合客戶組件特性,如光標、工具提示、鼠標、平板和鍵盤事件、子組件、動畫、彈拉框、組件輸入焦點和激活。QGraphicsProxyWidget甚至整合了嵌入組件的tab順序,能夠經過tab選擇嵌入的組件。甚至能夠嵌入一個QGraphicsView到場景。

    當變換和嵌入組件時,圖形視圖框架會確保組件會被獨立變換。