QGis二次开发基础 -- 构建图层管理器

为了回应有些同学对上一篇博文的建议,这篇文章主要关注于QGis二次开发中的“图层管理器”的实现。

使用QGis构建独立应用系统,我相信大部分同学应该还是关注于GIS基本功能框架构建上,也就是一些基本的GIS功能,例如:

  • 数据的显示、漫游浏览等
  • 读入数据的管理,也就是“图层管理器”功能
  • 数据基本信息的查询,例如空间坐标、投影查询,属性表查询等
  • 数据编辑,包括对属性表的编辑和矢量文件形状的编辑等

虽然各个应用系统的功能不尽相同,各种处理算法层出不穷,但是我想以上几个功能需求应该是通用的。

通过上一篇文章(QGis 二次开发最基础的问题——“显示数据”)的讲解,解决了最基本的显示数据、漫游浏览的问题。这一篇文章集中在解决“图层管理器”的构建问题,并且是在上一篇文章的代码基础上进行的,所以没有看上一篇的同学,一定去把上一篇的代码copy下来。

目前来说QGis二次开发这块主要还是看源代码进行学习,有心的同学肯定会发现,我的文章中的代码很多就是QGis的源码,只不过做了一些精简,去掉了目前无关的东西,所以我希望大家去看源码。希望近期能够有足够的时间将以上列出的基本功能都讲解一次,填补QGis二次开发教程目前的一个空白,希望能够帮到一些同学,与大家一道交流、学习。


工程概述

将项目做一个简要的说明,代码主要是QGis 二次开发最基础的问题——“显示数据”中的,所以请一定先去看看那篇文章。

工程中主要包含3个文件,分别是

  • qgis_dev.h
  • qgis_dev.cpp
  • main.cpp

其中“qgis_dev”这个类控制应用程序的初始化以及功能,我们需要扩展的也是这个类中的代码。这一节中,对main.cpp这个文件没有做任何更改。下图展示的是目前工程的运行效果。

上一篇文章的显示效果

添加图层管理器

QGis中,图层管理器的GUI是由类 QgsLayerTreeView 提供的,而与地图画布控件的数据交互,是由 QgsLayerTreeMapCanvasBridge 类提供。
因此首先打开 qgis_dev.h 这个文件,添加如下代码

 //! 图层管理
 QgsLayerTreeView* m_layerTreeView;
 QgsLayerTreeMapCanvasBridge *m_layerTreeCanvasBridge;

图层管理器的初始化单独放在一个方法中会使得代码结构清晰一些,因此添加一个私有方法负责初始化图层管理器

void initLayerTreeView();

现在开始在类构造函数中加入相关代码来实现这个图层管理的功能。打开 qgis_dev.cpp 这个文件,找到类的构造函数,添加初始化代码为:

//! 初始化map canvas
m_mapCanvas = new QgsMapCanvas();
m_mapCanvas->enableAntiAliasing( true );
m_mapCanvas->setCanvasColor( QColor( 255, 255, 255 ) );

//! 初始化图层管理器
m_layerTreeView = new QgsLayerTreeView( this );
initLayerTreeView();

//! 布局
QWidget* centralWidget = this->centralWidget();
QGridLayout* centralLayout = new QGridLayout( centralWidget );
centralLayout->addWidget( m_mapCanvas, 0, 0, 1, 1 );
centralLayout->addWidget( m_layerTreeView, 0, 1, 1, 1 ); 

// connections 这两句是上一篇文章里面就有的
connect( ui.actionAdd_Vector, SIGNAL( triggered() ), this, SLOT( addVectorLayers() ) );
connect( ui.actionAdd_Raster, SIGNAL( triggered() ), this, SLOT( addRasterLayers() ) );

添加好后运行程序,就可以看到图层管理器面板了。但现在的面板还只是一片空白而已,还需要添加进功能以及将它与地图画布控件绑定。

实现 initLayerTreeView 方法时,首先应该绑定一个 model 用来存储数据(这属于Qt的Model-View模型的知识),然后核心就是将 LayerTreeView 与地图画布控件关联上,因此主要代码为

QgsLayerTreeModel* model = new QgsLayerTreeModel( QgsProject::instance()->layerTreeRoot(), this );
model->setFlag( QgsLayerTreeModel::AllowNodeRename );
model->setFlag( QgsLayerTreeModel::AllowNodeReorder );
model->setFlag( QgsLayerTreeModel::AllowNodeChangeVisibility );
model->setFlag( QgsLayerTreeModel::ShowLegendAsTree );
model->setAutoCollapseLegendNodes( 10 );
m_layerTreeView->setModel( model );

// 连接地图画布和图层管理器
m_layerTreeCanvasBridge = new QgsLayerTreeMapCanvasBridge( QgsProject::instance()->layerTreeRoot(), m_mapCanvas, this );
connect( QgsProject::instance(), SIGNAL( writeProject( QDomDocument& ) ), m_layerTreeCanvasBridge, SLOT( writeProject( QDomDocument& ) ) );
connect( QgsProject::instance(), SIGNAL( readProject( QDomDocument ) ), m_layerTreeCanvasBridge, SLOT( readProject( QDomDocument ) ) );

恩,差不多了,就这几句而已。直接运行就能有下图的效果了。

这里写图片描述

是感觉太粗糙了一点,除了能显示数据图层外,还没有别的功能。下面再改进一下,为图层管理器添加一些功能。

添加图层管理器右键菜单

右键菜单我觉得算是一个比较基础的功能了,通过这里讲解如何添加右键菜单,做一个样例,让同学们大致了解一下机制,后面才能自己扩充更丰富的功能。

QGis的图层管理器右键菜单有个专门的抽象类,叫 QgsLayerTreeViewMenuProvider。通过继承这个类,可以为图层管理器添加右键菜单功能,其中最主要的就是实现 “createContextMenu()”这个方法。

明白了操作方式,下面开始动手。先创建一个新类,取名叫“qgis_devLayerTreeViewMenuProvider“继承自 “QgsLayerTreeViewMenuProvider”类,当然,它还必须继承自 “QObject”。 这个类的原型如下

class qgis_devLayerTreeViewMenuProvider : public QObject, public QgsLayerTreeViewMenuProvider
{
    Q_OBJECT
public:
    qgis_devLayerTreeViewMenuProvider( QgsLayerTreeView *view, QgsMapCanvas* canvas ); // 构造函数这样定义,直接获得图层管理器和地图画布控件,以便对它们建立联系
    ~qgis_devLayerTreeViewMenuProvider();

    //! 重写这个方法来获取右键菜单
    QMenu* createContextMenu() override;

protected:
    QgsLayerTreeView* mView;
    QgsMapCanvas* mCanvas;

};

通过以上原型可以看到分别建立了一个图层管理器和地图画布控件的指针实例,自然是要在构造函数中初始化它们。

// 构造函数
qgis_devLayerTreeViewMenuProvider::qgis_devLayerTreeViewMenuProvider( QgsLayerTreeView *view, QgsMapCanvas* canvas )
    : mView( view )
    , mCanvas( canvas )
{
}

剩下的也就是最关键的”createContextMenu()”这个方法的实现了,直接给代码吧,我不啰嗦了,相信大家也都看得明白。

QMenu* qgis_devLayerTreeViewMenuProvider::createContextMenu()
{
    // 设置这个路径是为了获取图标文件
    QString iconDir = "../images/themes/default/";

    QMenu* menu = new QMenu;
    QgsLayerTreeViewDefaultActions* actions = mView->defaultActions();
    QModelIndex idx = mView->currentIndex();

    // global menu
    if ( !idx.isValid() )
    {
        menu->addAction( actions->actionAddGroup( menu ) );
        menu->addAction( QIcon( iconDir + "mActionExpandTree.png" ), tr( "&Expand All" ), mView, SLOT( expandAll() ) );
        menu->addAction( QIcon( iconDir + "mActionCollapseTree.png" ), tr( "&Collapse All" ), mView, SLOT( collapseAll() ) );
    }
    else if ( QgsLayerTreeNode* node = mView->layerTreeModel()
  • 17
    点赞
  • 62
    收藏
    觉得还不错? 一键收藏
  • 24
    评论
QGIS二次开发中,图层管理器的实现和画布的链接是非常重要的。通过图层管理器,您可以管理和控制地图中的不同图层,包括添加、删除、隐藏和更改图层的属性等操作。而画布则是地图的可视化部分,用于显示地图数据和与用户交互。 要实现图层管理器的功能,您可以使用QGIS提供的PyQGIS Python API。以下是一个简单的示例代码,展示了如何创建一个图层管理器窗口,并添加一个图层: ```python from qgis.core import ( QgsProject, QgsVectorLayer, QgsMapLayerProxyModel ) from qgis.gui import QgsLayerTreeView # 创建一个图层管理器窗口 layer_tree_view = QgsLayerTreeView() # 设置图层管理器的数据模型 layer_proxy_model = QgsMapLayerProxyModel(QgsProject.instance()) layer_proxy_model.setFilterMode(QgsMapLayerProxyModel.FilterMode.ShowAll) layer_tree_view.setLayerModel(layer_proxy_model) # 添加一个图层 layer = QgsVectorLayer('/path/to/your/layer.shp', 'Layer Name', 'ogr') QgsProject.instance().addMapLayer(layer) # 将图层管理器窗口添加到主窗口中 main_window.addDockWidget(Qt.LeftDockWidgetArea, layer_tree_view) ``` 至于画布和图层管理器之间的链接,您可以使用QGIS提供的信号和槽机制来实现。通过连接画布的信号(如`currentLayerChanged`)到图层管理器的槽函数,您可以在用户选择不同图层时更新图层管理器的状态。 ```python canvas.currentLayerChanged.connect(layer_tree_view.setCurrentLayer) ``` 这里的`canvas`是您创建的画布对象。通过这个连接,当用户在画布上选择不同的图层时,图层管理器会自动更新当前选中的图层。 希望这些代码能帮助您开始实现图层管理器和画布的链接!请注意,这只是一个简单示例,您可以根据实际需求进行更多的定制和功能扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 24
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值