一: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(){}
      QAction * newAction(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;
  };
  下图是一个实现案例中各类之间的关系图:
  
  3.      插件调用
  插件在主框架中动态加载,目前考虑主框架基本结构是继承至QMainWindow,工具栏上显示当前加载的插件的功能键,并留有返回键可以回退到上一级。主工作区是一个QStackWidget,保存插件的界面,并把插件序号和插件对应的界面建立映射,保存在QMap<int,QWidget>中。通过序号到QStackWidget中切换界面。
  下图是把DBManager做成插件加载到主框架的运行界面:
  
  下图是把一个简单的绘图程序做成了插件,加载到主框架的运行界面:
  
  四:总结
         目前只是通过实现两个动态插件在主框架中运行,基本算是功能性的验证,离具体实施还有很多工作需要进一步的研究,比如主框架的风格,插件的管理等等。由于本人的能力有限,可能有很多认识不够的地方,请指正。