Qt 自定義應用程序插件

feiyangqingyun大神寫的Qt-組態軟件設計 非常值得仔細學習研讀。

        應用程序插件化,提高了程序可擴展性和靈活性,降低了程序的耦合度,有利於各模塊的獨立維護,加快項目的維護更新。越來越多的軟件都是基於插件化實現,比如Qt Creator, Notepad++ 等等。

        上一篇博客主要實現了自定義Designer 插件,Qt 已經幫我們實現接口類,所以實現起來也非常容易;減少造輪子,開發應用程序插件也是可以完全使用這一套接口類的,所以這裏自定義應用程序控件,沒有在重新編譯插件庫,直接使用上一次博客編譯好的插件,在應用程序裏面使用就可以。

       通過插件擴展應用程序功能(即應用使用插件)主要分爲如下幾步:
           1)   定義一個接口集(只有純虛函數的類),用來與插件通信。
           2)  用宏Q_DECLARE_INTERFACE()將該接口告訴Qt元對象系統。
           3)應用程序中用QPluginLoader來加載插件。
           4)用宏qobject_cast()來判斷一個插件是否實現了接口。

    創建一個Qt Widgets Application 任意項目,由於使用了Designer 的接口類,所以1),2)兩步接口類已經幫我們實現,可以看一下接口類的頭文件:

#ifndef CUSTOMWIDGET_H
#define CUSTOMWIDGET_H

#include <QtCore/qobject.h>
#include <QtCore/qstring.h>
#include <QtGui/qicon.h>

QT_BEGIN_NAMESPACE

class QWidget;
class QDesignerFormEditorInterface;

class QDesignerCustomWidgetInterface
{
public:
    virtual ~QDesignerCustomWidgetInterface() {}

    virtual QString name() const = 0;
    virtual QString group() const = 0;
    virtual QString toolTip() const = 0;
    virtual QString whatsThis() const = 0;
    virtual QString includeFile() const = 0;
    virtual QIcon icon() const = 0;

    virtual bool isContainer() const = 0;

    virtual QWidget *createWidget(QWidget *parent) = 0;

    virtual bool isInitialized() const { return false; }
    virtual void initialize(QDesignerFormEditorInterface *core) { Q_UNUSED(core); }

    virtual QString domXml() const
    {
        return QString::fromUtf8("<widget class=\"%1\" name=\"%2\"/>")
            .arg(name()).arg(name().toLower());
    }

    virtual QString codeTemplate() const { return QString(); }
};

#define QDesignerCustomWidgetInterface_iid "org.qt-project.QDesignerCustomWidgetInterface"

Q_DECLARE_INTERFACE(QDesignerCustomWidgetInterface, QDesignerCustomWidgetInterface_iid)

class QDesignerCustomWidgetCollectionInterface
{
public:
    virtual ~QDesignerCustomWidgetCollectionInterface() {}

    virtual QList<QDesignerCustomWidgetInterface*> customWidgets() const = 0;
};

#define QDesignerCustomWidgetCollectionInterface_iid "org.qt-project.Qt.QDesignerCustomWidgetCollectionInterface"

Q_DECLARE_INTERFACE(QDesignerCustomWidgetCollectionInterface, QDesignerCustomWidgetCollectionInterface_iid)

QT_END_NAMESPACE

#endif // CUSTOMWIDGET_H

故pro 文件需要添加:

QT += designer

需要我們實現的就只有3),4)步驟,添加代碼如下:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QPluginLoader>
#include <QDebug>
#include <QDir>
#include <QStringList>
#include <QDesignerCustomWidgetInterface> /*包含接口類頭文件*/
#include <QMetaProperty>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QString DirPath=QApplication::applicationDirPath();
    DirPath=DirPath.left(DirPath.lastIndexOf("/"));
    QString pluginfilename;
    pluginfilename = DirPath+"/qmybatteryplugind.dll";
    qDebug()<<pluginfilename;
    QPluginLoader loader( pluginfilename );

   bool b = loader.load();
   if(b)
       qDebug("loder ok!\r\n");
   else
       qDebug("loder error!\r\n");

   QObject *plugin = loader.instance();
   if (plugin){
       QDesignerCustomWidgetInterface *Interface = qobject_cast<QDesignerCustomWidgetInterface *>(plugin);
       if( Interface ){
           qDebug("loader.instance() OK\r\n");
           qDebug()<< "name:" << Interface->name() <<"icon:"<<Interface->icon();

           QWidget *Widget = Interface->createWidget(ui->widget);
           Widget->resize(100,60);

           const QMetaObject *metaobject = Widget->metaObject();

           int count = metaobject->propertyCount(); //獲取元對象的所有屬性
           int index = metaobject->propertyOffset();//獲取當前控件的第一個屬性index

           for (int i = index; i < count; ++i) {

               QMetaProperty metaproperty = metaobject->property(i);

               const char *name = metaproperty.name();
               QVariant value = Widget->property(name);

               qDebug() << name << value;
           }

           Widget->setProperty("value", 30.0);

           //ui->objectController->setObject(Widget);
       }
   }
   else
       qDebug("loader.instance() error\r\n");

}

最終運行結果:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章