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");
}
最終運行結果: