一、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 ,棧中的順序從下往上就是A、B、C。可以調用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()獲得拖拽支持,為了處理將要進行的拖拽,需要重新實現QGraphicsItem的dragEnterEvent()、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()函數在QGraphicsScene和QGraphicsItem中都有定義,在圖元類中的原型是advance(int phase)。實現流程是,利用QGraphicsScene類的對象調用QGraphicsScene的advance()函數,會執行兩次場景中所有圖元的advance(int phase)函數,第一次phase為0,告訴所有圖形項即將要移動;第二次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(); }