本文从我原先发布在 CSDN 的文章迁移而来,原文链接:https://blog.csdn.net/wang112031/article/details/105348798。
feiyangqingyun大神写的Qt-组态软件设计 非常值得仔细学习研读。
应用程序插件化,提高了程序可扩展性和灵活性,降低了程序的耦合度,有利于各模块的独立维护,加快项目的维护更新。越来越多的软件都是基于插件化实现,比如Qt Creator, Notepad++ 等等。
上一篇博客主要实现了自定义Designer 插件,Qt 已经帮我们实现接口类,所以实现起来也非常容易;减少造轮子,开发应用程序插件也是可以完全使用这一套接口类的,所以这里自定义应用程序控件,没有在重新编译插件库,直接使用上一次博客编译好的插件,在应用程序里面使用就可以。
通过插件扩展应用程序功能(即应用使用插件)主要分为如下几步:
- 定义一个接口集(只有纯虚函数的类),用来与插件通信。
- 用宏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");
}最终运行结果:

回复 / 留言