4. qgis c++二次開發(fā) map canvas介紹

前言

前幾篇文章分別介紹了qgis二次開發(fā)的

在顯示GIS數(shù)據(jù)之前,需要首先介紹一下map canvas风宁,畢竟在將顏料(GIS地圖等數(shù)據(jù))畫在畫布(map canvas)之前铅搓,首先要創(chuàng)建畫布(map canvas)潭流。

Map canvas

QGis軟件中的Map canvas

  • 官方文檔training_manual 有一節(jié)Navigating the Map Canvas專門講述了Map Canvas
  • 下圖空白區(qū)域左側(cè)為圖層樹(Layer tree),右側(cè)為Map Canvas


    image.png

代碼添加Map canvas

Map canvas is a class for displaying all GIS data types on a canvas.


image.png
  • QgsMapCanvas是Map canvas霞掺,類的詳細內(nèi)容見文檔

  • QgsMapCanvas本質(zhì)是一個QGraphicsViewQGraphicsView是Qt Graphics View Framework框架的一個類,Graphics View Framework是Qt提供的一個用于管理大量2D圖形項目并與之交互的框架辅鲸。

    image.png

    • QGraphicsView提供了視圖,相當(dāng)于畫布
    • QGraphicsItem圖形類的基類抄腔,可以顯示在canvas的組件瓢湃,QgsMapCanvasItem是該類的子類
    • QGraphicsScene用于管理item

Map Canvas創(chuàng)建和顯示

  • Map Canvas創(chuàng)建代碼如下
void ll_qgis_base_lib::initialize(QMainWindow *mainWindow)
{
    mMainWindow = mainWindow;

    mMapCanvas = new QgsMapCanvas;
    mMapCanvas->enableAntiAliasing(true);
    mMapCanvas->setCachingEnabled(true);
    mMapCanvas->setCanvasColor(QColor(255,255,255));
    mMapCanvas->setVisible(true);

    initLayerTreeView();
    initMaptools();
}
  • ll_qgis_base_lib類是qgis_cpp_api_apps項目的一個庫,由于Map canvas和Layer tree很通用赫蛇,所以將這兩個放在庫中
  • mMapCanvas添加到父Widget即可顯示Map canvas
void MainWindow::initStackwidgetPageCanvas()
{
    auto gridLayout = new QGridLayout;
    gridLayout->addWidget((QWidget*)mApp->mapCanvas());
    ui->page_canvas->setLayout(gridLayout);
    addDockWidget(Qt::LeftDockWidgetArea,mApp->layerTreeDock());
}

QGis中的QGraphicsItem

image.png
  • Measure功能使用了QgsRubberBand類绵患,上圖中的三角形就是用QgsRubberBand類繪制的

二次開發(fā)中的Item

image.png
  • QgsMapCanvasItem是一個抽象類,用于放置在地圖畫布上的項目悟耘。

  • QgsRubberband類是一個用于在地圖上繪制臨時特征(例如數(shù)字化線條)的類落蝙。類圖如下

    image.png

  • 如下代碼實現(xiàn)在圖層上畫三角形

void MainWindow::rubberBandPolygonSlot()
{
    //添加shapefile
    QString filename = QStringLiteral("maps/shapefile/protected_areas.shp");
    QFileInfo ff(filename);
    mApp->addVectorLayer(filename,ff.baseName());
    zoomToFirstLayer<QgsVectorLayer*>();
    //定義三個點
    QgsPointXY point1(20.34013,-33.90453);
    QgsPointXY point2(20.49744,-33.91126);
    QgsPointXY point3(20.41396,-33.93079);
    //新建PolygonGeometry類型的RubberBand
    mRubberBandPolygon = new QgsRubberBand(mApp->mapCanvas(),QgsWkbTypes::PolygonGeometry);
    //添加三個點
    mRubberBandPolygon->addPoint(point1);
    mRubberBandPolygon->addPoint(point2);
    mRubberBandPolygon->addPoint(point3);
    //設(shè)置線寬顏色等屬性
    mRubberBandPolygon->setWidth(4);
    mRubberBandPolygon->setColor(QColor(222,155,67));
    mRubberBandPoint = new QgsRubberBand(mApp->mapCanvas(),QgsWkbTypes::PointGeometry);
    mRubberBandPoint->addPoint(point1);
    mRubberBandPoint->addPoint(point2);
    mRubberBandPoint->addPoint(point3);
    mRubberBandPoint->setWidth(6);
    mRubberBandPoint->setColor(QColor(222,155,67));
    mRubberBandPolygon->show();
    mRubberBandPoint->show();
}
  • 以下代碼實現(xiàn)刪除QgsGraphicsItem
if(mVertexMarker)
    mApp->mapCanvas()->scene()->removeItem(mVertexMarker);

Layer Tree

QGis軟件中的Layer Tree

image.png
  • Layer Tree用于管理圖層
  • Layer Tree和Map canvas建立連接,可以對圖層進行操作

代碼實現(xiàn)layer tree

image.png
  • 代碼如下
void ll_qgis_base_lib::initLayerTreeView()
{
    //添加DockWidget作為圖層樹的容器
    mLayerTreeDock = new QgsDockWidget(tr("Layer Tree"));
    mLayerTreeDock->setObjectName( QStringLiteral( "Layers" ) );
    mLayerTreeDock->setAllowedAreas( Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea );

    //創(chuàng)建Model
    QgsLayerTreeModel* model = new QgsLayerTreeModel(QgsProject::instance()->layerTreeRoot(),this);
    model->setFlag( QgsLayerTreeModel::AllowNodeReorder );
    model->setFlag( QgsLayerTreeModel::AllowNodeRename );
    model->setFlag( QgsLayerTreeModel::AllowNodeChangeVisibility );
    model->setFlag( QgsLayerTreeModel::ShowLegendAsTree );
    model->setFlag( QgsLayerTreeModel::UseEmbeddedWidgets );
    model->setFlag( QgsLayerTreeModel::UseTextFormatting );
    model->setAutoCollapseLegendNodes( 10 );

    //創(chuàng)建View暂幼,mLayerTreeView會在庫外使用筏勒,所以需要添加getter方法,
    mLayerTreeView = new QgsLayerTreeView();
    mLayerTreeView->setModel(model);

    //Map Canvas和Layer Tree View建立聯(lián)系旺嬉,這樣通過QgsProject::instance()->addMapLayer添加圖層后管行,會自動添加在圖層樹以及會在canvas渲染圖層
    mLayerTreeMapCanvasBridge = new QgsLayerTreeMapCanvasBridge(QgsProject::instance()->layerTreeRoot(),mMapCanvas,this);
    connect( mLayerTreeMapCanvasBridge, &QgsLayerTreeMapCanvasBridge::canvasLayersChanged, mMapCanvas, &QgsMapCanvas::setLayers );

    //Layer Tree View右鍵菜單實現(xiàn)
    mLayerTreeView->setMenuProvider(new ll_qgis_base_layertreeview_menu(mMainWindow,mLayerTreeView,mMapCanvas));
    connect(QgsProject::instance()->layerTreeRegistryBridge(),SIGNAL(addedLayersToLayerTree(QList<QgsMapLayer*>)),
            this,SLOT(slot_autoSelectAddedLayer(QList<QgsMapLayer*>)));
}
  • 主要涉及了以下類QgsDockWidget,QgsLayerTreeModel,QgsLayerTreeView,QgsLayerTreeMapCanvasBridge
  • QgsDockWidget是一個Qt Dock Widget,用于顯示圖層樹
  • QgsLayerTreeViewQgsLayerTreeModel實現(xiàn)了樹的功能
  • QgsLayerTreeMapCanvasBridge類負責(zé)從圖層樹中更新QgsMapCanvas的圖層

QgsProject(項目管理)

QGis的項目可以保存為項目文檔邪媳,后綴名為“qgz”或“qgs”捐顷。在QGIS 3以前,只能通過“qgs”文件保存項目雨效⊙镐蹋“qgs”文件的本質(zhì)是存儲圖層的信息等的XML文件。在QGIS 3以后徽龟,“qgz”格式采用ZIP壓縮方法叮姑,不僅包含“qgs”文件,還包括附屬數(shù)據(jù)庫(Auxiliary Storage)文件(后綴名為“qgd”)据悔。自QGIS 3.2以來传透,“qgz”文件成為QGIS項目的默認存儲格式耘沼,本書也使用“qgz”文件存儲QGIS項目。

QGis軟件中的項目管理

  • 新建項目朱盐,在Project菜單中可以新建一個空工程


    image.png
  • 保存項目 可以選擇項目名稱和位置


    image.png

    image.png

代碼實現(xiàn)

Encapsulates a QGIS project, including sets of map layers and their styles, layouts, annotations, canvases, etc.
QgsProject is available both as a singleton (QgsProject::instance()) and for use as standalone objects. The QGIS project singleton always gives access to the canonical project reference open within the main QGIS application.

  • QgsProject代表QGis中的一個項目耕拷,包含項目管理、圖層管理以及其他功能托享,QgsProject的詳細內(nèi)容見官方文檔骚烧。
  • QgsProject是一個單例類,通過方法QgsProject::instance()即可調(diào)用其方法闰围,以下是QgsProject的一些常用函數(shù)
  • QgsProject的最常用的功能是添加圖層赃绊,調(diào)用QgsProject::instance()->addMapLayer(vecLayer);后會在Map Canvas顯示,也會添加到Layer tree中羡榴,如下代碼添加一個shape文件
void MainWindow::addShpSlot()
{
    QString filename = QStringLiteral("maps/shapefile/protected_areas.shp");
    QFileInfo ff(filename);
    //創(chuàng)建圖層
    QgsVectorLayer* vecLayer = new QgsVectorLayer(filename,ff.baseName(),"ogr");
    if(!vecLayer->isValid())
    {
        QMessageBox::critical(this,tr("error"),tr("invalid layer"));
        return;
    }
    QgsProject::instance()->addMapLayer(vecLayer);
    zoomToFirstLayer<QgsVectorLayer*>();
}
  • 以下是QgsProject的常用函數(shù)
//讀取項目文件
bool    read (const QString &filename, Qgis::ProjectReadFlags flags=Qgis::ProjectReadFlags())
bool    read (Qgis::ProjectReadFlags flags=Qgis::ProjectReadFlags())
//保存項目文件
bool    write ()
bool    write (const QString &filename)
//添加單個圖層
QgsMapLayer *   addMapLayer (QgsMapLayer *mapLayer, bool addToLegend=true, bool takeOwnership=true)
//添加多個圖層
QList< QgsMapLayer * >  addMapLayers (const QList< QgsMapLayer * > &mapLayers, bool addToLegend=true, bool takeOwnership=true)
Q_INVOKABLE QgsMapLayer *mapLayer (const QString &layerId) const
template<class T >
T mapLayer (const QString &layerId) const
QMap< QString, QgsMapLayer * >  mapLayers (const bool validOnly=false) const
QList< QgsMapLayer * >  mapLayersByShortName (const QString &shortName) const
template<typename T >
QVector< T >    mapLayersByShortName (const QString &shortName) const
void    removeAllMapLayers ()
void    removeMapLayer (const QString &layerId)
void    removeMapLayer (QgsMapLayer *layer)
void    removeMapLayers (const QList< QgsMapLayer * > &layers)
void    removeMapLayers (const QStringList &layerIds)

總結(jié)

  • QgsMapCanvas作為視圖類提供了繪制的畫布
  • QgsMapCanvasItem可以繪制在畫布上的Item
  • QgsProject圖層管理碧查,尤其在添加圖層時常用
  • 了解了這幾個類,就可以學(xué)習(xí)如何顯示GIS數(shù)據(jù)了
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末校仑,一起剝皮案震驚了整個濱河市忠售,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌迄沫,老刑警劉巖稻扬,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異羊瘩,居然都是意外死亡泰佳,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進店門尘吗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來逝她,“玉大人,你說我怎么就攤上這事睬捶∏穑” “怎么了?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵擒贸,是天一觀的道長臀晃。 經(jīng)常有香客問我,道長酗宋,這世上最難降的妖魔是什么积仗? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任疆拘,我火速辦了婚禮蜕猫,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘哎迄。我一直安慰自己回右,他們只是感情好隆圆,可當(dāng)我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著翔烁,像睡著了一般渺氧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蹬屹,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天侣背,我揣著相機與錄音,去河邊找鬼慨默。 笑死贩耐,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的厦取。 我是一名探鬼主播潮太,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼虾攻!你這毒婦竟也來了铡买?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤霎箍,失蹤者是張志新(化名)和其女友劉穎奇钞,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體漂坏,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡蛇券,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了樊拓。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片纠亚。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖筋夏,靈堂內(nèi)的尸體忽然破棺而出蒂胞,到底是詐尸還是另有隱情,我是刑警寧澤条篷,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布骗随,位于F島的核電站,受9級特大地震影響赴叹,放射性物質(zhì)發(fā)生泄漏鸿染。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一乞巧、第九天 我趴在偏房一處隱蔽的房頂上張望涨椒。 院中可真熱鬧,春花似錦、人聲如沸蚕冬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽囤热。三九已至猎提,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間旁蔼,已是汗流浹背锨苏。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留棺聊,地道東北人蚓炬。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像躺屁,于是被迫代替她去往敵國和親肯夏。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,619評論 2 354

推薦閱讀更多精彩內(nèi)容