QT 中的 Graphics View 系统
這個框架是一個相對成熟的渲染引擎的上層框架,通常也可以會叫做 Scene - View。
在QT中,GraphicsView是一個與QWdiget系列一點點不一樣的系統。這個系統主要由下面幾個框架類構成:QGraphicsView,? QGraphicsScene, QGraphicsItem
?
QGrahpicsView是從原生的QWidget繼承過來,QGraphics-View系統中,他承擔的也是視口的指責,Viewport,Viewport相當于顯示設備的一個矩形區域。
QGraphicsScene 是一個管理器,用來管理所有的QGraphicsItem,包括根據坐標查詢Item,排序Item,繪制Item等。
QGraphicsItem 是所有可見的元件。一個完整的UI界面,由各種QGraphicsItem組合起來。這些QGraphicsItem之間由一棵多叉樹組織。
要架構一個基于GraphicsView的UI庫,需要做如下的三件事情:
- 我們需要先由一個 QGraphicsView, 這個是UI顯示的地方,也就是裝滿可見原色的Scene,
- 然后需要一個QGraphicsScene 用來管理所有可見的界面元素,
- 要實現UI功能,我們需要用各種從QGraphicsItem拼裝成UI控件,并賦予他控件的邏輯。
對應到Duifw,我們的DuiFrameWindow 就是從 QGraphicsView 繼承過來的,也就是說它是一個獨立的視口,相當于操作系統的一個窗口.
在DuiFrameWindow 中 void DuiFrameWindow::_initScene(), 函數中,我們為每一個 DuiFrameWindow 創建了一個標準的 QGraphicsScene,? 并且在 scene 上我們 add 了一個 DuiRootItem,然后我們就在 rootitem上構建我們的所有UI控件,? 從? DuiRootItem: m_rootItem 上 我們add 三個子Item ,分別是 DuiBackgroundItem:m_backgroundItem, DuiTitlebar:m_titlebar, DuiSpacerItem:m_contentItem, 然后我們定義了一個rootWidget() 函數 用來返回? DuiSpacerItem:m_contentItem, 后面通過xml文件配置的一個窗口,就通過訪問rootWidget(), 把所有DuiFrameWindow的孩子節點都以 這個rootWidget為 父節點,如下代碼:
createChild(child->child(index), frame->rootWidget());
這樣就構建了一個QGraphicsItem的多叉樹。前面有一個細節,沒有列出,就是我們的DuiWidget, 是一個什么, 我們的DuiWidget是從QGraphicsWidget,繼承而來的,也就是說它本身是一個符合 QGraphicsScene - QGraphicsItem體系的可視元件。
了解了的GraphicsView的構成框架后,對于QGraphicsItem的消息來源,以及這個框架中的消息走向能夠大概有了猜測了。
QGraphicsView 會把? 原來的QWidget中的各種QHoverEvent, QInputEvent,......等等一些列命令,轉換成各種 QGraphicsSceneEvent ,QGraphicsSceneMouseEvent,QGraphicsSceneWheelEvent......,,,然后傳遞給當前View綁定的QGraphicsScene。然后通過Scene傳遞給 QGraphicsitem,QGraphicsScene 有如下的一堆消息處理接口:
通過上述的分發,最后消息會通過下面的接口傳遞到具體的item,所有的scene消息都是走接口:
這樣就完成了從windows消息到 QGraphicsItem 的消息處理的流程。
到此。QGraphics - View 框架就簡述完成了。
?
//***************************************************
Qt圖形簡單繪制? -貪吃蛇小游戲
在初步了解Qt繪圖相關的基礎知識后,我們將開始學習用Qt做一個貪吃蛇小游戲。
不過在開始游戲之前,我們首先要了解Qt中的一個重要框架,叫Graphics View。
Graphics View是一個很常用的框架(貪吃蛇,俄羅斯方塊等用Graphics View都是最好的方法...),甚至Linux的KDE桌面視圖都是用它編寫的。
Graphics View 分為三個部分:元素(item),場景(scene)以及視圖(view)。
我們舉一個很簡單的例子:我們看到森林里有很多樹,那么這個森林就是場景(scene),樹是元素(item),你的眼睛就是視圖(view)。我們可以在場景里種樹,也就是把item通過add的方法置于場景,遮陽,在我們的視圖(view)里面就會出現一棵樹了。而實際上,我們也未必會一直站在同一個地方看樹;當我們移動的時候,整個森林(scene)的場景在我們的視圖(view)里邊變化。而這在程序中對應著二維圖的旋轉,縮放等功能。
我們來看下面一這個代碼:
?
?int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
QGraphicsScene scene;
scene.addRect(0,0,150,150);
scene.setBackgroundBrush(QBrush(Qt::gray));
QGraphicsView view(&scene);
view.rotate(30);
view.setWindowTitle("Graphics View");
view.resize(200, 200);
view.show();
return a.exec();
}
在這里,我們構建了一個場景(scene)和一個視圖(view),同時,我們在視圖上做了旋轉,那么它輸出的結果就是一個旋轉的正方形,如下圖:
?
這種方式在OpenGL以及其他三維軟件API中也很常用,想想大家完第一視角的游戲(比如‘我的世界’),無非就是建立一個場景(世界),修改場景中的元素(比如蓋房子),然后移動視角,遮陽在場景中就能呈現我們的世界。
大家也可以通過以上代碼,簡單做幾個小程序,或者采用簡單的形狀,通過代碼畫一幅簡單的畫。
?
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 ,棧中的順序從下往上就是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_HCustomView.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_HCustomScene.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_HCustomItem.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(); }?
總結
以上是生活随笔為你收集整理的QT 中的 Graphics View 系统的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 得当前时间的工具类
- 下一篇: 解决:liunx 光标消失(显示光标)