zhonghua

C++博客 首页 新随笔 联系 聚合 管理
  72 Posts :: 1 Stories :: 4 Comments :: 0 Trackbacks

一:qt plugin 介绍

      Qt Plugin和其他类型的插件一样,是一种计算机应用程序,它和主应用程序(host application)互相交互,以提供特定的功能。应用程序支持Plugin有许多原因,一些主要原因包括:使得第三方开发者有能力扩展应用程序,以提供无法先期预料的特色;减小应用程序的大小;由于软件版权之间的不兼容性将源代码和应用程序分享。Qt Plugin 分动态插件和静态插件两种。

二:qt plugin 创建和使用方法

Qt有两种与插件有关的API。一种用来扩展Qt本身的功能,如自定义数据库驱动,图像格式,文本编解码,自定义分格,等等,称为Higher-Level API。另一种用于应用程序的功能扩展,称为Lower-Level API。前一种是建立在后一种的基础之上的。这里讨论的是后一种,即用来扩展应用程序的Lower-level API

让应用程序支持插件扩展的步骤:

 1. 定义一个接口集(只有纯虚函数的类),用来与插件交流。

 2. 用宏Q_DECLARE_INTERFACE()将该接口告诉Qt元对象系统。

 Q_DECLARE_INTERFACE(BrushInterface,"com.trolltech.PlugAndPaint.BrushInterface/1.0")

 3. 应用程序中用QPluginLoader来装载插件。

 4. 用宏qobject_cast()来确定一个插件是否实现了接口。

 QObject *obj = new QTimer; 

 QTimer *timer = qobject_cast<QTimer *>(obj);

写一个插件的步骤:

 1. 声明插件类,该类从QObject和该插件希望实现的接口继承而来。

 2. 用宏Q_INTERFACES()将该接口告诉Qt元对象系统。

  class BasicToolsPlugin : public QObject,

                            public BrushInterface,

                            public ShapeInterface,

                            public FilterInterface

  {

       Q_OBJECT

       Q_INTERFACES(BrushInterface ShapeInterface FilterInterface)

  public:

       ...

   };

 3. 用宏Q_EXPORT_PLUGIN2()导出插件。

  Q_EXPORT_PLUGIN2 ( PluginName, ClassName )

 4. 用适当的.pro文件构建插件。

下面的代码声明了一个接口类:

 

class FilterInterface

 {

 public:

        virtual ~FilterInterface() {}

        virtual QStringList filters() const = 0;

        virtual QImage filterImage(const QString &filter, const QImage &image, QWidget* parent)=0;

  };

Q_DECLARE_INTERFACE(FilterInterface, "com.trolltech.PlugAndPaint.FilterInterface/1.0")

这里是实现该接口的插件类的定义:

 

 #include <QObject>

 #include <QStringList>

 #include <QImage>

 #include <plugandpaint/interfaces.h>

 class ExtraFiltersPlugin : public QObject, public FilterInterface

 {

 Q_OBJECT

 Q_INTERFACES(FilterInterface)

 public:

     QStringList filters() const;

     QImage filterImage(const QString &filter, const QImage &image,

     QWidget *parent);

 };

根据插件的类型不同,pro文件中配置上有不同。下面是pro文件分析:

TEMPLATE      = lib                                  // 声明为lib,动态和静态插件一样。

CONFIG       += plugin static                // 声明为plugin,带static表面为静态,否则为动态。

INCLUDEPATH += ../..

HEADERS       = basictoolsplugin.h

SOURCES       = basictoolsplugin.cpp

TARGET        = $$qtLibraryTarget(pnp_basictools)           // 指明插件的名称

DESTDIR       = ../../plugandpaint/plugins

加载插件的主应用程序默认在当前目录下的plugins文件夹中寻找可用插件,如果是动态插件,则直接放在plugins文件夹中便可,如果是静态,则需要在主应用程序的main函数的开始的地方用宏:Q_IMPORT_PLUGIN(pluginname(和pro文件中声明的一致))声明需要加载的插件并在工程配置中指明插件的lib位置。

三:基于qt plugin 技术的框架结构设想

1.      愿景

由于我们目前系统功能多,模块多,缺乏系统的整体性。我们想借助Qt Plugin技术,把各个独立的功能模块实现为一个个插件,统一在主体框架中,并能根据不同地方的用户的不同需求,在主框架中加载不同的功能模块,以实现整个系统的功能集中,体现出系统的整体性。

2.      plugin 接口

通过技术验证得出,目前我们采用动态插件,各个功能的插件实现定义的统一接口,具体功能放在插件界面中实现,此部分就像开发独立的应用程序,只是需要注意的是:

功能部分的主界面需要继承至插件界面基类:PluginWidget,插件接口中用具体的实现类指针给插件界面基类指针赋值,在加载插件的主框架中通过插件接口中定义的基类指针统一调用,利用C++动态技术动态识别具体指向的实现类。

插件界面类必须实现基类的虚函数:CreateActions()用于创建Action

创建Action需要使用基类的方法newAction创建,在此函数中加入了保存创建的Action功能。

插件接口定义如下:

class QPluginInterface

{

public:

    // 析构函数

    virtual ~QPluginInterface() {}

   

    // 插件名称

    virtual    QString    PluginName() = 0;

   

    // 插件显示在主框架中的图标文件路径

    virtual    QString PluginIconurl() = 0;

   

    // 插件提供的对外操作接口集

    virtual QList<QAction*>* Actions() = 0;

 

    // 创建插件提供的操作方法

    virtual    void CreateActions()=0;

 

    // 插件的主界面

    virtual QWidget* Widget() = 0;

protected:

    // 插件的主界面基类

    PluginWidget *pluginWidget;

};

插件界面基类定义如下:

class PluginWidget :public QMainWindow

{

    Q_OBJECT

public:

    PluginWidget(QWidget*parent=0);

    ~PluginWidget();

    QList<QAction*>* Actions();

    virtual void      CreateActions(){}

    QActionnewAction(const QIcon &icon,const QString &text,QObject*parent);

    QAction *         newAction(const QString &text,QObject*parent);

    void       AppendAction(QAction*act);

protected:

    // action链表

    QList<QAction*> *m_actlist;

};

下图是一个实现案例中各类之间的关系图:

基于QT Plugin框架结构  - yleesun - 与青春有关的日子...

3.      插件调用

插件在主框架中动态加载,目前考虑主框架基本结构是继承至QMainWindow,工具栏上显示当前加载的插件的功能键,并留有返回键可以回退到上一级。主工作区是一个QStackWidget,保存插件的界面,并把插件序号和插件对应的界面建立映射,保存在QMap<int,QWidget>中。通过序号到QStackWidget中切换界面。

下图是把DBManager做成插件加载到主框架的运行界面:

基于QT Plugin框架结构  - yleesun - 与青春有关的日子...

下图是把一个简单的绘图程序做成了插件,加载到主框架的运行界面:

基于QT Plugin框架结构  - yleesun - 与青春有关的日子...

四:总结

       目前只是通过实现两个动态插件在主框架中运行,基本算是功能性的验证,离具体实施还有很多工作需要进一步的研究,比如主框架的风格,插件的管理等等。由于本人的能力有限,可能有很多认识不够的地方,请指正。

posted on 2013-02-22 15:10 米米 阅读(711) 评论(0)  编辑 收藏 引用 所属分类: qt

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理