QT開發(四十)——GraphicsView編程

QT開發(四十)——GraphicsView編程

一、QGraphicsScene

1、QGraphicsScene

QGraphicsScene繼承自QObject,是一個管理圖元的容器,與QGraphicsView合用可以在2D屏幕上顯示如線、三角形、文本、自定義圖元等圖元。

QGraphicsScene是不可見的,只用於管理圖元。爲了查看場景,需要創建一個視圖組件。

    一個場景分爲三個層:圖元層、前景層和背景層。場景的繪製總是從背景層開始,然後是圖形項層,最後是前景層。

2、事件處理與傳播

    QGraphicsScene的責任之一是傳播來自視圖的事件。要發送一個事件到場景,需要構造一個繼承自QEvent的事件,使用QApplication::sendEvent()函數發送事件。event()函數負責派發事件到各個圖元。常用的事件會被便利事件處理函數處理,如鼠標按下事件會被mousePressEvent()函數處理。

    按鍵事件會被派發到焦點圖元。爲了設置焦點圖元,可以調用setFocusItem()函數,或是圖元自身調用QGraphicsItem::setFocus()函數。調用focusItem()函數可以獲取當前的焦點圖元。爲了兼容圖形組件,場景維護着自己的焦點信息。默認場景並沒有焦點,並且所有的按鍵事件會別丟棄。如果setFocus()函數被調用,或是場景中一個圖元獲得了焦點,場景會自動獲得焦點。如果場景有焦點,hasFocus()函數會返回true,按鍵事件會被髮送到焦點圖元。如果場景失去了焦點,而圖元有焦點(如調用clearFocus()函數),場景會維護圖元的焦點信息,一旦場景重新獲得焦點,會確保最後一個有焦點的圖元獲得焦點。

    對於懸停效果,QGraphicsScene會派發懸停事件,如果某個圖元接受了懸停事件(調用QGraphicsItem::acceptHoverEvents()),當鼠標進入圖元的區域時,圖元會接收到一個GraphicsSceneHoverEnter事件。當鼠標繼續在圖元內部移動時,QGraphicsScene會發送GraphicsSceneHoverMove事件。當鼠標離開圖元的區域時,圖元會收到一個GraphicsSceneHoverLeave事件。

    所有鼠標事件會被傳播到當前鼠標獲取的圖元。如果一個圖元接收了鼠標事件,並收到鼠標按下,圖元就是場景的鼠標獲取圖元。這個圖元會一直被鼠標獲取,直到圖元收到一個鼠標釋放事件。調用mouseGrabberItem()函數可以知道當前鼠標獲取的圖元。

場景可以傳遞來自視圖的事件,將事件傳遞給該點最頂層的圖元。如果一個圖元要接收鍵盤事件,那麼它必須獲得焦點。而且,如果在場景中重寫了事件處理函數,那麼在該函數的最後必須調用場景默認的事件處理函數,只有這樣,圖元才能接收到該事件。

A、拖拽事件

[virtual protected] void dragEnterEvent(QGraphicsSceneDragDropEvent *event)

拖入事件處理函數

[virtual protected] void dragLeaveEvent(QGraphicsSceneDragDropEvent *event)

拖離事件梳理函數

[virtual protected] void dragMoveEvent(QGraphicsSceneDragDropEvent *event)

拖動事件處理函數

[virtual protected] void dropEvent(QGraphicsSceneDragDropEvent *event)

Drop事件處理函數

在以上拖拽事件處理函數中的末尾需要調用QGraphicsScene類相應的事件處理函數。

QGraphicsScene::dragEnterEvent(event);

QGraphicsScene::dragLeaveEvent(event);

QGraphicsScene::dragMoveEvent(event);

QGraphicsScene::dropEvent(event);

B、鼠標事件

[virtual protected] void mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)

鼠標移動處理函數

[virtual protected] void mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)

鼠標按下處理函數

[virtual protected] void mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent)

鼠標釋放處理函數

在以上鼠標事件處理函數中的末尾需要調用QGraphicsScene類相應的事件處理函數。

QGraphicsScene::mouseMoveEvent(event);

QGraphicsScene::mousePressEvent(event);

QGraphicsScene::mouseReleaseEvent(event);

3、索引算法

    索引算法,是指在場景中進行圖元查找的算法。QGraphicsScene中提供了兩種選擇,在一個枚舉變量QGraphicsScene::ItemIndexMethod中定義,分別是:

    QGraphicsSecne::BspTreeIndex :應用Binary Space Partition tree,適合於大量的靜態圖元,是默認值。

    QGraphicsScene::NoIndex :不用索引,搜索場景中所有的圖元,適合於經常進行圖元的添加、移動和刪除等操作的情況。

    使用setItemIndexMethod()函數進行索引算法的更改。

4、邊界矩形

    圖元可以放到場景的任何位置,場景的大小默認是沒有限制的。而場景的邊界矩形僅用於場景內部進行索引的維護。因爲如果沒有邊界矩形,場景就要搜索所有的圖元,然後確定出其邊界,這是十分費時的。所以如果要操作一個較大的場景,應該給出它的邊界矩形。

    設置邊界矩形,可以使用setSceneRect()函數。

5、圖元的查找

    場景最大的優勢之一就是可以快速的鎖定圖元的位置,即使有上百萬個圖元,items()函數也能在數毫秒的時間內鎖定一個圖元的位置。items()函數有幾個重載函數來方便的進行圖元的查找。如果在場景的一個點可能重疊着幾個圖元,可以使用itemAt()函數返回最上面的一個圖元。

二、QGraphicsItem

1、自定義QGraphicsItem

    QGraphicsItem是圖元的基類。

    自定義圖元,首先應該繼承QGraphicsItem,然後重寫他的兩個純虛公共函數boundingRect()和paint(),boundingRect()函數返回繪製圖元大概的區域,paint()函數用來繪製圖元內容。

    boundingRect()函數有很多用處,場景在boundingRect()來建立它的圖元的index,視圖使用boundingRect來剪切可見的圖元,在重新繪製圖元時候,來決定相互重疊的部分,此外,圖元的碰撞檢測機制也使用的boundingRect()來提供一個高效的定點,在collidesWithItem()更好的碰撞算法建立在調用函數shape(),shape()函數以QpainterPath類型返回圖元的精準的輪廓。
    場景不希望圖元的boundingRect()和shape()變化,除非該圖元被通告,如果想通過一些方法改變圖元的形狀,首先應該調用QgraphicsScene()來允許場景QgraphicsScene來刷新它的圖元記錄。

    圖元沒有獲得焦點時,事件只能從視圖傳遞到場景,不能傳遞到圖元。清除圖元的焦點函數爲clearFocus()。

2、繪製

    paint()函數被QgrapicsView類調用來繪製圖元的內容,圖元默認是沒有背景或者填充顏色的。在函數中沒有被繪製的所有區域都將會發亮,可以調用update()來重繪圖元,可以選擇傳遞需要重繪的矩形區域(不是必須的)。取決於圖元在視圖中是否可見,圖元可能會也可能不會重繪,QgraphicsItem裏面沒有和 Qwidget::repaint()函數等價的圖元通過視圖來繪製,從父類圖元開始,然後是圖元自身,以上升的棧的順序,可以通過調用setZValue()設置圖元的棧順序,通過zValue()來測試,具有低z-values的圖元比具有高z-value 的圖元先繪製,棧順序應用於兄弟圖元,父類圖元總是比子類圖元更早繪製。

3、排序

    所有的圖元都按照一個已經聲明的穩定的順序來繪製,聲明的順序決定了當在場景中點擊鼠標時候,哪個圖元最先接受鼠標的輸入。通常情況下,不需要擔心圖元排序的問題,因爲所有的圖元都按照一個在場景中聲明的自然的順序。
    在一個棧中,子類圖元在父類圖元的上面,兄弟圖元按照插入場景的順序來入棧,如果你先添加圖元A ,然後是圖元B,然後是圖元C ,棧中的順序從下往上就是ABC。可以調用setZvalue()來設置一個圖元的相對於另一個圖元向上、向下或者兄弟棧順序。默認的Z值是0,具有同樣的Z值的圖元會按照插入的順序來入棧。可以調用stackBefore()來備份子類圖元的列表,直接更正圖元的順序。
    如果想讓子類圖元在父類圖元的後面,也就是先繪製子類圖元,然後再繪製父類圖元。可以利用函數setFlag()設置ItemStacksBehindParent屬性給圖元。

4、事件處理

    QgraphicsItem從場景中通過sceneEvent()函數來接受事件,sceneEvent()函數通過一些方便的操作分散大部分事件

    ContextMenuEvent()函數接受上下文菜單事件

    FocusInEvent()和focusOutEvent()函數接受焦點進出事件 
    hoverEnterEvent()hoverMoveEvent()hoverLeaveEvent() 接受鼠標懸浮移動和離開事件
    inputMethodEvent()函數處理輸入法事件,
    keyPressEvent()keyReleaseEvent()事件處理鍵盤按下和釋放事件
    mousePressEvent()mouseMoveEvent()mouseReleaseEvent()    mouseDoubleClickEvent()處理鼠標按下、移動、釋放、雙擊事件
    通過安裝過濾器,可以爲圖元過濾一些事件,與QT一般的事件過濾器不一樣,一般的過濾器只工作在Qobject及其子類。通過調用 installSceneEventFilter()爲圖元安裝事件過濾器後,被過濾的事件將會被虛函數sceneEventFilter()捕捉 到,可以通過調用函數removeSceneEventFilter()來去除掉事件過濾器

A、拖拽事件

    GraphicsView框架爲視圖、場景、圖元提供拖拽支持。當視圖接收到拖拽事件,GraphicsView框架會將拖拽事件翻譯爲QGraphicsSceneDragDropEvent事件,再發送到場景,場景接管事件,把事件發送到光標下接受拖拽的第一個圖元。
    從圖元開始拖拽時,創建一個QDrag對象,傳遞開始拖拽的QWidget的指針。圖元可以同時被多個視圖觀察,但只有一個視圖可以開始拖拽。拖拽在多數情況下是從按下鼠標或是移動鼠標開始的,在mousePressEvent()或mouseMoveEvent()中,可以從事件中得到原始的QWidget指針

    要在場景中取拖拽事件,需要重新實現QGraphicsScene::dragEnterEvent()QGraphicsItem子類裏任何與特定場景需要的事件處理器。圖元也可以通過調用QGraphicsItem::setAcceptDrops()獲得拖拽支持,爲了處理將要進行的拖拽,需要重新實現QGraphicsItemdragEnterEvent()dragMoveEvent()

dropEvent()dragLeaveEvent() 。

[virtual protected] void dragEnterEvent(QGraphicsSceneDragDropEvent *event)

[virtual protected] void dragLeaveEvent(QGraphicsSceneDragDropEvent *event)

[virtual protected] void dragMoveEvent(QGraphicsSceneDragDropEvent *event)

[virtual protected] void dropEvent(QGraphicsSceneDragDropEvent *event)

B、鼠標事件

    要在自定義圖元類中處理鼠標事件,需要重寫QGraphicsItem類中鼠標按下、鼠標移動、鼠標釋放的事件。

[virtual protected] void mouseMoveEvent(QGraphicsSceneMouseEvent *event)

[virtual protected] void mousePressEvent(QGraphicsSceneMouseEvent *event)

[virtual protected] void mouseReleaseEvent(QGraphicsSceneMouseEvent *event)

5、動畫效果

    實現圖元的動畫效果,也可以在不同的層面進行。如果只想控制一兩個圖元的動畫,一般在場景或視圖中實現。但是要是想讓一個圖元類的多個對象都進行同樣的動畫,那麼我們就可以在圖元類的構造函數中進行實現。

    //圖元可獲得焦點

    setFlag(QGraphicsItem::ItemIsFocusable);

    //圖元可移動

    setFlag(QGraphicsItem::ItemIsMovable);

    QGraphicsItemAnimation *anim = new QGraphicsItemAnimation;

    //將圖元加入動畫對象中

    anim->setItem(this);

    //創建長爲1秒的時間線

    QTimeLine *timeLine = new QTimeLine(1000);

    //動畫循環次數爲0,表示無限循環

    timeLine->setLoopCount(0);

    //將時間線加入動畫類對象中

    anim->setTimeLine(timeLine);

    //在動畫時間的一半時圖形項旋轉180

    anim->setRotationAt(0.5,180);

    //在動畫執行完時圖形項旋轉360

    anim->setRotationAt(1,360);

    //開始動畫

    timeLine->start();

6、移動

    圖元的移動,有多種方法實現,可以在視圖或場景上控制,但對於不同類型的大量圖元,怎樣能一起控制呢?在圖形視圖框架中提供了advance()槽函數,advance()函數在QGraphicsSceneQGraphicsItem中都有定義,在圖元類中的原型是advance(int phase)。實現流程是,利用QGraphicsScene類的對象調用QGraphicsSceneadvance()函數,會執行兩次場景中所有圖元的advance(int phase)函數,第一次phase0,告訴所有圖形項即將要移動;第二次phase的值爲1,執行移動。

    QTimer timer;

    QObject::connect(&timer, SIGNAL(timeout()),scene, SLOT(advance()));

    timer.start(1000);

    至於圖元如何移動,需要重寫圖元類的advance()函數。

    如果在自定義圖元類的構造函數中設置爲可移動,則圖元可以直接使用鼠標拖拽。

setFlag(QGraphicsItem::ItemIsMovable);

7、圖元的座標轉換

    QgraphicsItem支持座標轉換,對於簡單的轉換,可以調用函數setRotation()或者setScale(),可以傳遞一個轉換矩陣給函數setTransform(),對於一些更復雜的轉換,可以通過調用函數setTransformations()來設置一系列組合的轉換。
    圖元轉換從父類到子類進行聚集,因此如果一個父類圖元和子類圖元都旋轉90度,那麼子類圖元就旋轉了180度;如果父類圖元和子類圖元都放大了2X倍,那麼子類圖元就被放大4X倍,圖元的轉換不影響圖元的外觀,所有和外觀有關的函數(例如contains(),update()和所有的映射mapping函數)將會在本地座標中操作,QgraphicsItem提供函數sceneTransform(),將會返回圖元所有的轉換矩陣,scenePos()將會返回圖元在場景座標中的位置,重新設置圖元的矩陣,調用函數resetTransform()
    一般的轉換回產生一個不同的結果,取決於轉換應用的順序,轉換順序不同得到結果將不同。

8、主要成員函數

QVariant itemChange(GraphicsItemChange change, const QVariant & value)

    itemChange函數被QGraphicsItem調用用來標識圖元的狀態改變了,通過重載itemChange函數,可以對自己定義事件響應。參數change是改變的圖元的改變狀態參數,value是一個新的數據,類型取決於change,change是QGraphicsItem::GraphicsItemChange枚舉變量

    在itemChange函數內部調用函數時候要謹慎,不能在itemChange函數裏面調用setPos(),參數change是ItemPositionChange時,setPos()函數將會再次調用itemChange(ItemPositionChange),形成死循環。

    void setFlag(GraphicsItemFlag flag, bool enabled = true)
 
     void setFlags(GraphicsItemFlags flags)
 
    flags設置爲圖元的屬性,如果圖元獲得了光標,但flags沒有使能ItemsFocusable,圖元將會丟失光標,當圖元被選擇,但沒有使能ItemsSelectable,圖元會自動的失去選擇。
     
QPainterPath shape () const 

    以QPainterPath返回圖元在本地座標中的形狀,形狀可以用來做很多事情,包括碰撞偵測,打擊測試,還有用來 QGraphicsScene::items() 函數
    默認的函數調用boundingRect()返回一個簡單的矩形形狀,子類可以重載boundingRect函數,爲非矩形的圖元返回一個更加精準的形狀,例如一個圓形的圖元可以選擇返回一個橢圓形,用來獲得更好的碰撞偵測效果。

三、QGraphicsView

1、QGraphicsView簡介

    QGraphicsView繼承自QAbstractScrollArea,繼承了QWidget的特性。

    QGraphicsView提供了視圖窗口部件,使場景的內容可視化。可以給一個場景關聯多個視圖,從而給一個數據集提供多個視口。視圖部件是一個滾動區域,可以提供一個滾動條來顯示大型的場景。

2、事件處理

    在圖形視圖框架中,鼠標鍵盤等事件是從視圖進入的,視圖將事件傳遞給場景,場景再將事件傳遞給該點的圖元,如果該點有多個圖元,那麼就傳給最上面的圖元。爲了使事件能進一步傳播到場景,需要在重新實現事件處理函數時,在其最後將event參數傳給默認的事件處理函數。比如重寫了視圖的鼠標按下事件處理函數,那麼就在該函數的最後寫上QGraphicsView::mousePressEvent(event);

A、拖拽事件

    在QGraphicView中提供了三種拖拽模式,分別是:

    QGraphicsView::NoDrag :忽略鼠標事件,不可以拖動。

    QGraphicsView::ScrollHandDrag :光標變爲手型,可以拖動場景進行移動。

    QGraphicsView::RubberBandDrag :使用橡皮筋效果,進行區域選擇,可以選中一個區域內的所有圖元。

    可以利用setDragMode()函數進行相應設置。

[virtual protected] void dragEnterEvent(QDragEnterEvent *event)

[virtual protected] void dragLeaveEvent(QDragLeaveEvent *event)

[virtual protected] void dragMoveEvent(QDragMoveEvent *event)

[virtual protected] void dropEvent(QDropEvent *event)

在以上拖拽事件處理函數中的末尾需要調用QGraphicsView類相應的事件處理函數。

QGraphicsView::dragEnterEvent(event);

QGraphicsView::dragLeaveEvent(event);

QGraphicsView::dragMoveEvent(event);

QGraphicsView::dropEvent(event);

B、鼠標事件

[virtual protected] void mouseMoveEvent(QMouseEvent *event)

[virtual protected] void mousePressEvent(QMouseEvent *event)

[virtual protected] void mouseReleaseEvent(QMouseEvent *event)

void setMouseTracking(bool enable)

在以上鼠標事件處理函數中的末尾需要調用QGraphicsView類相應的事件處理函數。

QGraphicsView::mouseMoveEvent(event);

QGraphicsView::mousePressEvent(event);

QGraphicsView::mouseReleaseEvent(event);

四、程序實例

1、自定義視圖

CustomView.h文件:

#ifndef CUSTOMVIEW_H
#define CUSTOMVIEW_H
 
#include <QGraphicsView>
 
class CustomView : public QGraphicsView
{
    Q_OBJECT
public:
    CustomView(QWidget *parent = 0);
protected:
    void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
    void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
    void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
    void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;
    void dragEnterEvent(QDragEnterEvent *event) Q_DECL_OVERRIDE;
    void dragLeaveEvent(QDragLeaveEvent *event) Q_DECL_OVERRIDE;
    void dragMoveEvent(QDragMoveEvent *event) Q_DECL_OVERRIDE;
    void dropEvent(QDropEvent *event) Q_DECL_OVERRIDE;
};
 
#endif // CUSTOMVIEW_H

CustomView.cpp文件:

#include "CustomView.h"
#include <QDebug>
 
CustomView::CustomView(QWidget *parent):QGraphicsView(parent)
{
}
 
void CustomView::mousePressEvent(QMouseEvent *event)
{
    qDebug() << "CustomView::mousePressEvent";
    QGraphicsView::mousePressEvent(event);
}
 
void CustomView::mouseMoveEvent(QMouseEvent *event)
{
    qDebug() << "CustomView::mouseMoveEvent";
    QGraphicsView::mouseMoveEvent(event);
}
 
void CustomView::mouseReleaseEvent(QMouseEvent *event)
{
    qDebug() << "CustomView::mouseReleaseEvent";
    QGraphicsView::mouseReleaseEvent(event);
}
 
void CustomView::paintEvent(QPaintEvent *event)
{
    qDebug() << "CustomView::paintEvent";
    QGraphicsView::paintEvent(event);
}
 
void CustomView::dragEnterEvent(QDragEnterEvent *event)
{
    qDebug() << "CustomView::dragEnterEvent";
    QGraphicsView::dragEnterEvent(event);
}
 
void CustomView::dragLeaveEvent(QDragLeaveEvent *event)
{
    qDebug() << "CustomView::dragLeaveEvent";
    QGraphicsView::dragLeaveEvent(event);
}
 
void CustomView::dragMoveEvent(QDragMoveEvent *event)
{
    setCursor(Qt::CrossCursor);
    qDebug() << "CustomView::dragMoveEvent";
    QGraphicsView::dragMoveEvent(event);
}
 
void CustomView::dropEvent(QDropEvent *event)
{
    qDebug() << "CustomView::dropEvent";
    QGraphicsView::dropEvent(event);
}

 

2、自定義場景

CustomScene.h文件:

#ifndef CUSTOMSCENE_H
#define CUSTOMSCENE_H
 
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QPaintEvent>
 
class CustomScene : public QGraphicsScene
{
    Q_OBJECT
public:
    CustomScene(QObject *parent = 0);
protected:
    void mousePressEvent(QGraphicsSceneMouseEvent *event) Q_DECL_OVERRIDE;
    void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) Q_DECL_OVERRIDE;
    void mouseMoveEvent(QGraphicsSceneMouseEvent *event) Q_DECL_OVERRIDE;
    void dragEnterEvent(QGraphicsSceneDragDropEvent *event) Q_DECL_OVERRIDE;
    void dragLeaveEvent(QGraphicsSceneDragDropEvent *event) Q_DECL_OVERRIDE;
    void dragMoveEvent(QGraphicsSceneDragDropEvent *event) Q_DECL_OVERRIDE;
    void dropEvent(QGraphicsSceneDragDropEvent *event) Q_DECL_OVERRIDE;
};
 
#endif // CUSTOMSCENE_H

CustomScene.cpp文件:

#include "CustomScene.h"
#include <QDebug>
 
CustomScene::CustomScene(QObject *parent):QGraphicsScene(parent)
{
}
 
void CustomScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    qDebug() << "CustomScene::mousePressEvent";
    QGraphicsScene::mousePressEvent(event);
}
 
void CustomScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    qDebug() << "CustomScene::mouseReleaseEvent";
    QGraphicsScene::mouseReleaseEvent(event);
}
 
void CustomScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
    qDebug() << "CustomScene::mouseMoveEvent";
    QGraphicsScene::mouseMoveEvent(event);
}
 
void CustomScene::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
{
    qDebug() << "CustomScene::dragEnterEvent";
    QGraphicsScene::dragEnterEvent(event);
}
 
void CustomScene::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
{
    qDebug() << "CustomScene::dragLeaveEvent";
    QGraphicsScene::dragLeaveEvent(event);
}
 
void CustomScene::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
{
    qDebug() << "CustomScene::dragMoveEvent";
    QGraphicsScene::dragMoveEvent(event);
}
 
void CustomScene::dropEvent(QGraphicsSceneDragDropEvent *event)
{
    qDebug() << "CustomScene::dropEvent";
    QGraphicsScene::dropEvent(event);
}

3、自定義圖元

CustomItem.h文件:

#ifndef CUSTOMITEM_H
#define CUSTOMITEM_H
 
#include <QGraphicsItem>
#include <QGraphicsSceneMouseEvent>
 
class CustomItem : public QGraphicsItem
{
public:
    CustomItem();
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) Q_DECL_OVERRIDE;
    QRectF boundingRect() const Q_DECL_OVERRIDE;
protected:
    //鼠標事件
    void mousePressEvent(QGraphicsSceneMouseEvent *event) Q_DECL_OVERRIDE;
    void mouseMoveEvent(QGraphicsSceneMouseEvent *event) Q_DECL_OVERRIDE;
    void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) Q_DECL_OVERRIDE;
    //拖拽事件
    void dragEnterEvent(QGraphicsSceneDragDropEvent *event) Q_DECL_OVERRIDE;
    void dragLeaveEvent(QGraphicsSceneDragDropEvent *event) Q_DECL_OVERRIDE;
    void dragMoveEvent(QGraphicsSceneDragDropEvent *event) Q_DECL_OVERRIDE;
    void dropEvent(QGraphicsSceneDragDropEvent *event) Q_DECL_OVERRIDE;
private:
    QColor color;
};
 
#endif // CUSTOMITEM_H

 

CustomItem.cpp文件:

#include "CustomItem.h"
#include <QDebug>
#include <QPainter>
#include <QCursor>
#include <QPen>
 
CustomItem::CustomItem()
{
    color = Qt::red;
    setFlag(QGraphicsItem::ItemIsFocusable);
    //設置圖元爲可移動的
    setFlag(QGraphicsItem::ItemIsMovable);
    setAcceptDrops(true);
}
 
void CustomItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    Q_UNUSED(option);
    Q_UNUSED(widget);
    qDebug() << "CustomItem::paint";
    if(hasFocus()) {
        painter->setPen(QPen(QColor(255,255,255,200)));
    } else {
        painter->setPen(QPen(QColor(100,100,100,100)));
    }
    painter->setBrush(color);
    painter->drawRect(-10, -10, 20, 20);
}
 
QRectF CustomItem::boundingRect() const
{
    qreal adjust = 0.5;
    return QRectF(-10 - adjust, -10 - adjust, 20 + adjust, 20 + adjust);
}
 
void CustomItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    Q_UNUSED(event);
    qDebug() << "CustomItem::mousePressEvent";
    setCursor(Qt::OpenHandCursor);
}
 
void CustomItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
    setCursor(Qt::DragMoveCursor);
    qDebug() << "CustomItem::mouseMoveEvent";
}
 
void CustomItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    qDebug() << "CustomItem::mouseReleaseEvent";
    setCursor(Qt::ArrowCursor);
}
 
void CustomItem::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
{
    setCursor(Qt::CrossCursor);
    qDebug() << "CustomItem::dragEnterEvent";
}
 
void CustomItem::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
{
    setCursor(Qt::ForbiddenCursor);
    qDebug() << "CustomItem::dragLeaveEvent";
}
 
void CustomItem::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
{
    setCursor(Qt::CrossCursor);
    qDebug() << "CustomItem::dragMoveEvent";
}
 
void CustomItem::dropEvent(QGraphicsSceneDragDropEvent *event)
{
    setCursor(Qt::WaitCursor);
    qDebug() << "CustomItem::dropEvent";
}

 

4、程序使用

#include "CustomScene.h"
#include "CustomView.h"
#include "CustomItem.h"
#include <QApplication>
#include <QTime>
 
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    qsrand(QTime(0, 0, 0).secsTo(QTime::currentTime()));
 
    CustomScene scene;
    scene.setSceneRect(-200, -150, 400, 300);
    for(int i = 0; i < 5; ++i) {
        CustomItem *item = new CustomItem;
        item->setPos(i * 50 - 90, -50);
        scene.addItem(item);
    }
    CustomView view;
    view.setScene(&scene);
    view.show();
 
    return a.exec();
}

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章