一个工程中,不同的界面就可能由不同的模块进行管理开发,然后生成相应的dll。一般状况下,直接加载.dll创建对象的话,当这个.dll丢失的时候,程序就会直接报错,无法运行下去。
但当我们利用插件式开发,结合QPluginLoader,就可以做到即使.dll丢失,主程序也不会崩溃,只会丢失相应的功能。
1.首先自定义插件抽象基类
函数根据需要自行添加。
class IPlugin : public QObject
{
public:
virtual ~IPlugin() {}
public:
virtual void initialize() = 0;
virtual QString pluginName() const = 0;
virtual QString pluginDescr() const = 0;
virtual QStringList pluginWidgets() const = 0;
virtual QMap<QString, QWidget*> createWindow(const QString& name, QWidget* parent) = 0;
};
2.创建具体插件类
class MyPlugin : public IPlugin
{
Q_OBJECT
Q_INTERFACES(IPlugin)
Q_PLUGIN_METADATA(IID ICNCPlugin_iid FILE "MyPlugin.json")
public:
virtual void initialize() override;
virtual QString pluginName() const override;
virtual QString pluginDescr() const override;
virtual QStringList pluginWidgets() const override;
virtual QMap<QString, QWidget*> createWindow(const QString& name, QWidget* parent) override;
private:
QMap<QString, QWidget*> pluginPageGroup;
};
注意,Q_PLUGIN_METADATA该宏必须得声明,不然后面QPluginLoader会无法加载该模块,详见Qt帮助文档。
创建完具体插件类后,把接口实现。
3.创建插件管理类
用单例模式。
//PluginManager.h
class cPluginManager
{
public:
cPluginManager();
~cPluginManager();
private:
static cPluginManager *mPluginManager;
QMap<QString, IPlugin*> mLoadedPlugins;
public:
static cPluginManager* getInstance();
private:
void loadPlugins();
void releasePlugins();
public:
QList<IPlugin*> getLoadedPlugins();
IPlugin* getPluginByName(QString pluginName);
private:
class gc
{
public:
~gc()
{
if (mPluginManager)
{
delete mPluginManager;
mPluginManager = nullptr;
}
}
};
static gc delgc;
};
//PluginManager.cpp
//加载插件
void cPluginManager::loadPlugins()
{
QDir pluginsDir(QCoreApplication::applicationDirPath() + "");//dll所在文件夹
QStringList loadedPluginFileNames;
for (const QString& fileName : pluginsDir.entryList(QDir::Files))
{
if (!fileName.contains(".dll"))
continue;
if (loadedPluginFileNames.contains(fileName))
continue;
QPluginLoader pluginLoader(pluginsDir.absoluteFilePath(fileName));
QObject *plugin = pluginLoader.instance();
QString error = pluginLoader.errorString();
if (plugin)
{
IPlugin *myPlugin = qobject_cast<IPlugin*>(plugin);
if (myPlugin )
{
myPlugin ->initialize();
auto name = myPlugin ->pluginName();
mLoadedPlugins.insert(name, myPlugin );
loadedPluginFileNames.push_back(fileName);
}
else
{
delete plugin;
plugin = nullptr;
}
}
}
}
4.主界面调用
至此插件已加载完毕,用相应的容器接住QWidget,便可以进行相应操作。