【Qt】2D绘图之图形视图框架(一)
00. 目錄
文章目錄
- 00. 目錄
- 01. 概述
- 02. 開發環境
- 03. 場景(Scene)
- 04. 視圖(View)
- 05. 圖形項
- 06. 附錄
01. 概述
在前面講的基本繪圖中,我們可以自己繪制各種圖形,并且控制它們。但是,如果需要同時繪制很多個相同或不同的圖形,并且要控制它們的移動、檢測它們的碰撞和疊加;或者我們想讓自己繪制的圖形可以拖動位置、進行縮放和旋轉等操作。實現這些功能,要是還使用以前的方法,那么會十分困難。解決這些問題,可以使用Qt提供的圖形視圖框架。
圖形視圖(Graphics View)框架結構的主要特點如下:
- 圖形視圖(Graphics View)可以對大量定制的2D圖形項進行管理和相互作用。視圖部件可以讓所有圖形項可視化,它還提供了縮放和旋轉功能。
- 框架中包含了一個事件傳播構架,提供了和場景中的圖形項進行精確的雙精度交互的能力,圖形項可以處理鍵盤事件,鼠標的按下、移動、釋放和雙擊事件,還可以跟蹤鼠標的移動。
- 圖形視圖框架使用一個BSP(Binary Space Partitioning)樹來快速發現圖形項,也正是因為如此,它可以實時顯示一個巨大的場景,甚至包含上百萬個圖形項。
- 圖形視圖框架結構中,系統可以利用Qt繪圖系統的反鋸齒、OpenGL工具來改善繪圖性能。
圖形視圖結構主要包含三部分:
- 場景(Scene) :QGraphicsScene類
- 視圖(View) :QGraphicsView類
- 圖形項(Item):QGraphicsItem類
02. 開發環境
Windows系統:Windows10
Qt版本:Qt5.15或者Qt6
03. 場景(Scene)
場景是圖形項QGraphicsItem對象的容器,其主要完成的工作包括:
(1)提供用于管理大量圖形項的快速接口;
(2)傳播事件給每一個圖形項;
(3)管理圖形項的狀態(如選擇和焦點處理);
(4)提供無變換的渲染功能,主要用于打印。
下面是一些QGraphicsScene的常用函數:
- 可以調用QGraphicsScene: :addItem()函數將圖形項添加到場景中,然后調用任意一個圖形項發現函數來檢索添加的圖形項。
- QGraphicsScene::items()函數和其他幾個重載函數可以返回符合條件的所有圖形項。這些圖形項不是與指定的點、矩形、多邊形或者矢量路徑相交,就是包含在它們之中。
- QGraphicsScene::itemAt()函數返回指定點的最上面的圖形項。所有的圖形項發現函數返回的圖形項都是使用遞減順序(例如第一個返回的圖形項在最上面,最后返回的圖形項在最下面)。
- 如果要從場景中刪除一個圖形項,可以使用QGraphicsScene::Removeltem()函數。
- 可以通過向QGraphicsScene::setSelectionArea()函數中傳遞一個任意的形狀來選擇場景中指定的圖形項。
- 如果要獲取當前選取的所有圖形項的列表,可以使用QGraphicsScene:: selectedltems()函數。
- 另外可以調用QGraphicsScene:: setFocusItem()或者 QGraph-icsScene:: setFocus( )函數來為一個圖形項設置焦點,調用QGraphicsScene:: focusItem()函數來獲取當前獲得焦點的圖形項。
- QGraphicsScene:: render()函數將場景中的一部分渲染到一個繪圖設備上。
下面先來看一個最簡單的例子。新建空的Qt項目(Empty qmake Project),項目名稱為myscene。然后在這個項目中添加新的C++源文件,命名為main.cpp。添加完成后首先在myscene.pro文件中添加一行代碼:
QT += widgets
然后將main.cpp的內容更改如下。
#include <QApplication> #include <QGraphicsScene> #include <QGraphicsRectItem> #include <QDebug>int main(int argc, char **argv) {QApplication app(argc, argv);//新建場景QGraphicsScene scene;//創建矩形圖形項QGraphicsRectItem *item = new QGraphicsRectItem(0, 0, 100, 100);//將圖形項添加到場景中scene.addItem(item);//輸出(50, 50)點處的圖形項qDebug() << scene.itemAt(50, 50, QTransform());return app.exec(); }這里先創建了一個場景,然后創建了一個矩形圖形項,并且將該圖形項添加到了場景中。然后使用itemAt()函數來返回指定坐標處最頂層的圖形項,這里返回的就是剛才添加的矩形圖形項。現在可以運行程序,不過因為還沒有設置視圖,所以不會出現任何圖形界面,這時可以在應用程序輸出欄中看到輸出的項目的信息如下:
QGraphicsItem(0x18a8720, pos=0,0)04. 視圖(View)
QGraphicsView提供了視圖部件,它用來使場景中的內容可視化??梢赃B接多個視圖到同一個場景來為相同的數據集提供多個視口。
下面是一些QGraphicsView:的常用函數:
- 視圖部件是一個可滾動的區域,提供了一個滾動條來瀏覽大的場景,可以使用setDragMode()函數以QGraphicsView::SCrollHandDrag為參數來使光標變為手掌形狀,從而可以拖動場景。
- 如果設置 setDragMode()的參數為QGraphicsView::RubberBandDrag,那么可以在視圖上使用 鼠標拖出橡皮筋框來選擇圖形項。
- 默認的QGraphicsView提供了一個QWidget作為視口部件,如果要使用OpenGL進行植染,可以調用QGraphicsView::setViewport()設置QOpenGLWidget作為視口。QGraphicsView會獲取視口部件的擁有權(ownership)。
在前面的程序中先添加頭文件# include ,然后main.cpp文件中的代碼:
#include <QApplication> #include <QGraphicsScene> #include <QGraphicsView> #include <QGraphicsRectItem> #include <QDebug>int main(int argc, char **argv) {QApplication app(argc, argv);//新建場景QGraphicsScene scene;//創建矩形圖形項QGraphicsRectItem *item = new QGraphicsRectItem(0, 0, 100, 100);//將圖形項添加到場景中scene.addItem(item);//輸出(50, 50)點處的圖形項qDebug() << scene.itemAt(50, 50, QTransform());//創建視圖QGraphicsView view(&scene);//設置場景的前景色view.setForegroundBrush(QColor(255, 255, 0, 100));//設置場景的背景圖片view.setBackgroundBrush(QPixmap(":/image/d.png"));view.resize(400, 300);view.show();return app.exec(); }這里新建了視圖部件,并指定了要可視化的場景。然后為該視圖設置了場景前景色和背景圖片。一個場景分為3層:圖形項層(ItemLayer)、前景層(ForegroundLayer)和背景層(BackgroundLayer)。場景的繪制總是從背景層開始,然后是圖形項層,最后是前景層。前景層和背景層都可以使用QBrush進行填充,比如使用漸變和貼圖等。這里的前景色設置為半透明的黃色,當然也可以設置為其他的填充。這里要提示一下,其實使用好前景色可以實現很多特殊的效果,比如使用半透明的黑色便可以實現夜幕降臨的效果。
代碼中使用了 QGraphicsView類中的函數來設置場景中的背景和前景,其實也可以使用QGraphicsScene中的同名函數來實現,不過它們的效果并不完全 一樣。如果使用QGraphicsScene對象設置了場景背景或者前景,那么對所有關聯了該場景的視圖都有效,而QGraphicsView對象設置的場景的背景或者前景,只對它本身對應的視圖有效。
運行程序,效果如下圖所示。可以看到矩形圖形項和背景圖片都是在視圖中間部分進行繪制的,這個問題會在后面的坐標系統部分詳細講解。
05. 圖形項
QGraphicsItem是場景中圖形項的基類。圖形視圖框架為典型的形狀提供了標準的圖形項,比如矩形(QGraphicsRectlem)、橢圓(QGraphicsEllipseltem)和文本項(QGraphicsTextltem)。不過,只有編寫自定義的圖形項時才能發揮QGraphicsItem的強大功能。
QGraphicsItem主要支持以下功能:
- 鼠標按下、移動、釋放、雙擊、懸停、滾輪和右鍵菜單事件;
- 鍵盤輸入焦點和鍵盤事件;
- 拖放事件;
- 分組,使用QGraphicsItemGroup通過parent-child關系來實現;
- 碰撞檢測。
除此之外,圖形項還可以存儲自定義的數據,可以使用setData()進行數據存儲,然后使用data()獲取其中的數據。下面自定義圖形項。
在前面的程序中添加新文件,模板選擇C+ +類,類名為Myltem,基類為 QGraphicsItem,類型信息選擇“無”。添加完成后,在myitem.h文件中添加兩個函數的聲明:
#ifndef MYITEM_H #define MYITEM_H#include <QGraphicsItem>class MyItem : public QGraphicsItem { public:MyItem();//返回要繪制圖形項的矩形區域QRectF boundingRect() const;//用來執行實際的繪圖操作void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,QWidget *widget); };#endif // MYITEM_H再到myitem.cpp文件中添加頭文件# include ,然后定義添加的兩個函數:
#include "myitem.h"#include <QPainter>MyItem::MyItem() {}//返回要繪制圖形項的矩形區域 QRectF MyItem::boundingRect() const {qreal penWidth = 1;return QRectF(0 - penWidth / 2, 0 - penWidth / 2,20 + penWidth, 20 + penWidth); }//用來執行實際的繪圖操作 void MyItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {//聲明參數沒有使用Q_UNUSED(option);Q_UNUSED(widget);painter->setBrush(Qt::red);painter->drawRect(0, 0, 20, 20); }要實現自定義的圖形項,那么首先要創建一個QGraphicsItem的子類,然后重新實現它的兩個純虛公共函數:boimdingRect()和paint(),前者用來返回要繪制圖形項的矩形區域,后者用來執行實際的繪圖操作。其中,boimdingRect()函數將圖形項的外部邊界定義為一個矩形,所有的繪圖操作都必須限制在圖形項的邊界矩形之中。而且,QGraphicsView要使用這個矩形來剔除那些不可見的圖形項,另外QGraphicsItem的碰撞檢測機制也需要使用到這個邊界矩形。
下面到main.cpp中添加#include “myitem.h”,將程序改為:
#include <QApplication> #include <QGraphicsScene> #include <QGraphicsView> #include <QGraphicsRectItem> #include <QDebug> #include "myitem.h"int main(int argc, char **argv) {QApplication app(argc, argv);//新建場景QGraphicsScene scene;//創建矩形圖形項//QGraphicsRectItem *item = new QGraphicsRectItem(0, 0, 100, 100);MyItem *item = new MyItem;//將圖形項添加到場景中scene.addItem(item);//輸出(50, 50)點處的圖形項qDebug() << scene.itemAt(50, 50, QTransform());//創建視圖QGraphicsView view(&scene);//設置場景的前景色view.setForegroundBrush(QColor(255, 255, 0, 100));//設置場景的背景圖片view.setBackgroundBrush(QPixmap(":/image/d.png"));view.resize(400, 300);view.show();return app.exec(); }這時運行程序,效果如下圖所示。可以看到,自定義的紅色小方塊出現在了視圖的正中間,背景圖片的位置也有所變化,這些問題都會在后面的坐標系統中講到。如果只想添加簡單的圖形項,那么也可以直接使用圖形視圖框架提供的8種標準圖形項。
圖形視圖框架提供的標準圖形項
06. 附錄
源碼下載:【Qt】2D繪圖之圖形視圖框架(一).rar
總結
以上是生活随笔為你收集整理的【Qt】2D绘图之图形视图框架(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Qt】2D绘图之双缓冲绘图
- 下一篇: 【Qt】Qt工程管理