QgisPlugin插件开发技术

简介

QGIS的插件框架,结构简单、效果明显。基于插件技术,划分出各个相互独立的模块,可灵活搭建界面和组件库,在协作开发、版本迭代、功能扩展等多个层面都有很好的敏捷性。

插件类型

插件类型定义在QgsPlugin类中,包括UI插件、图层插件、渲染插件三种类型。插件类通过QgisInterface接口,进行模块之间的交互。

enum PluginType
    {
      UI = 1,   //!< User interface plug-in
      MapLayer, //!< Map layer plug-in
      Renderer, //!< A plugin for a new renderer class
    };

插件元数据类

QgsPluginMetadata,用于记录插件的名称、版本、类型、描述等基本信息,以及插件类的指针对象。

插件注册与加载

在QGIS中,插件注册的本质是把插件的名称和元数据类存储在QMap<QString, QgsPluginMetadata>对象中。
在这里插入图片描述看一下注册插件的核心代码(省略掉不重要代码,关键是理解注册机制):

void QgsPluginRegistry::loadCppPlugin( const QString &fullPathName )
{
  //....省略掉一段源码
  QLibrary myLib( fullPathName );
  bool loaded = myLib.load();
  //...省略掉一段源码
  //type就是定义的插件类型
  type_t *pType = ( type_t * ) cast_to_fptr( myLib.resolve( "type" ) );
  name_t *pName = ( name_t * ) cast_to_fptr( myLib.resolve( "name" ) );
  switch ( pType() )
  {
    case QgisPlugin::Renderer:
    case QgisPlugin::UI:
    {
      // UI only -- doesn't use mapcanvas
      create_ui *cf = ( create_ui * ) cast_to_fptr( myLib.resolve( "classFactory" ) );
      if ( cf )
      {
        QgisPlugin *pl = cf( mQgisInterface );
        if ( pl )
        {
          //往主界面中添加插件的UI,在应用中可以通过实现自己的qgisinterface来控制UI的添加方式
          pl->initGui();
          // add it to the plugin registry
          addPlugin( baseName, QgsPluginMetadata( myLib.fileName(), pName(), pl ) );
          //...省略掉一段源码
      }
      //...省略掉一段源码
    }
    break;
    default://...省略掉一段源码
  }
}

加载插件的代码是在QgisApp类构造函数中调用的:

QgsPluginRegistry::instance()->setQgisInterface( mQgisInterface );
if ( restorePlugins )
{
    // Restoring of plugins can be disabled with --noplugins command line option
    // because some plugins may cause QGIS to crash during startup
    QgsPluginRegistry::instance()->restoreSessionPlugins( QgsApplication::pluginPath() );
    // Also restore plugins from user specified plugin directories
    QString myPaths = settings.value( QStringLiteral( "plugins/searchPathsForPlugins" ), "" ).toString();
    if ( !myPaths.isEmpty() )
    {
      QStringList myPathList = myPaths.split( '|' );
      QgsPluginRegistry::instance()->restoreSessionPlugins( myPathList );
    }
}

当然,在加载插件之前还要对插件的合法性进行验证,代码如下:

bool QgsPluginRegistry::checkCppPlugin( const QString &pluginFullPath )
{
  QLibrary myLib( pluginFullPath );
  bool loaded = myLib.load();
  if ( ! loaded )
  {
    QgsMessageLog::logMessage( QObject::tr( "Failed to load %1 (Reason: %2)" ).arg( myLib.fileName(), myLib.errorString() ), QObject::tr( "Plugins" ) );
    return false;
  }
  name_t *myName = ( name_t * ) cast_to_fptr( myLib.resolve( "name" ) );
  description_t   *myDescription = ( description_t * )  cast_to_fptr( myLib.resolve( "description" ) );
  category_t   *myCategory = ( category_t * )  cast_to_fptr( myLib.resolve( "category" ) );
  version_t   *myVersion = ( version_t * ) cast_to_fptr( myLib.resolve( "version" ) );
  if ( myName && myDescription && myVersion  && myCategory )
    return true;
  QgsDebugMsgLevel( "Failed to get name, description, category or type for " + myLib.fileName(), 2 );
  return false;
}

QGIS插件的存放路径一般是运行时的plugins文件夹中,也可以通过环境变量配置默认的插件路径。从下图中,大致可以看出:名称以plugin结尾的是UI类型的插件;以provider结尾的都是图层类型的插件,用于各类数据格式的读写等。
在这里插入图片描述

扩展插件的实现

这里只介绍以plugin结尾的UI插件,以拓扑检查的插件topolplugin.dll为例。
插件类要继承QObject, QgisPlugin这两个类,且必须实现initGui()虚函数,其他自定义的函数用于配合实现UI的逻辑。

static const QString sName = QObject::tr( "Topology Checker" );
static const QString sDescription = QObject::tr( "A Plugin for finding topological errors in vector layers" );
static const QString sCategory = QObject::tr( "Vector" );
static const QString sPluginVersion = QObject::tr( "Version 0.1" );
static const QgisPlugin::PluginType sPluginType = QgisPlugin::UI;
static const QString sPluginIcon = QStringLiteral( ":/topology/mActionTopologyChecker.svg" );
class Topol: public QObject, public QgisPlugin
{
    Q_OBJECT
  public:
    explicit Topol( QgisInterface *interface );
  public slots:
    //! init the gui
    void initGui() override;
    //! Create and show the dialog box
    void run();
    //! Show/hide the dialog box
    void showOrHide();
    //! unload the plugin
    void unload() override;
    //! show the help document
    void help();
  private:
    QgisInterface *mQGisIface = nullptr;
    //!pointer to the qaction for this plugin
    QAction *mQActionPointer = nullptr;
    checkDock *mDock = nullptr;
};

再来看initGui()的定义:

void Topol::initGui()
{
  delete mQActionPointer;//为什么可以直接删除指针?
  mQActionPointer = new QAction( QIcon( sPluginIcon ), sName, this );
  mQActionPointer->setObjectName( QStringLiteral( "mQActionPointer" ) );
  mQActionPointer->setCheckable( true );
  mQActionPointer->setWhatsThis( tr( "Topology Checker for vector layer" ) );
  // 绑定ui控件与执行函数
  connect( mQActionPointer, &QAction::triggered, this, &Topol::showOrHide );
  // 在qgisInterface中添加ui
  //qgisInterface是虚类,具体的实现由QgisApp类实现
  mQGisIface->addVectorToolBarIcon( mQActionPointer );
  mQGisIface->addPluginToVectorMenu( QString(), mQActionPointer );
}

再来看QgisApp类对添加UI控件的实现:

void QgisApp::addPluginToVectorMenu( const QString &name, QAction *action )
{
  QMenu *menu = getVectorMenu( name );
  menu->addAction( action );
}

这既是实现插件的开发过程,对照前面定义的目录是Vector,名称是Topology Checker,即可在工具栏中找到该控件。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值