1.先创建一个名为mainProject的主项目,并进行简单的ui布局
2.使用C++ Library库创建动态库项目作为主项目的子插件
2.1 Qt模块选择为Widgets
2.2 环境配置和主项目要一致
3.给插件添加qt界面设计类
4.给subPlugin插件添加一个名为PluginInterface.h的头文件
#ifndef PLUGININTERFACE_H
#define PLUGININTERFACE_H
#include <QWidget>
#define PluginInterfaceIID "com.szweebon.PluginInterface/1.0.0" // 定义一个插件接口的唯一标识符(IID),用于标识插件的接口版本
class PluginInterface{ // 这是一个纯虚基类(接口),用于定义插件接口的标准。
public:
virtual ~PluginInterface() = default; // 虚析构函数,确保派生类在销毁时能够正确释放资源
virtual QWidget *getWidget() = 0; // 该函数用于返回一个 QWidget 指针,表示插件提供的界面部件
};
Q_DECLARE_INTERFACE(PluginInterface, PluginInterfaceIID) // 确保接口类和它的 IID 在 Qt 元对象系统中注册
#endif // PLUGININTERFACE_H
5.编辑subplugin.h和subplugin.cpp代码
#ifndef SUBPLUGIN_H
#define SUBPLUGIN_H
#include "PluginInterface.h"
#include "subPlugin_global.h"
class SUBPLUGIN_EXPORT SubPlugin: public QObject, public PluginInterface
{
Q_OBJECT
Q_PLUGIN_METADATA(IID PluginInterfaceIID)//PluginInterfaceIID就是IID
Q_INTERFACES(PluginInterface)
public:
SubPlugin();
~SubPlugin();
QWidget *getWidget();
private:
QWidget *mGenWidget;
};
#endif // SUBPLUGIN_H
#include "subplugin.h"
#include "form.h"
SubPlugin::SubPlugin() {
mGenWidget = Q_NULLPTR;
}
SubPlugin::~SubPlugin() {
if(mGenWidget){
mGenWidget->deleteLater();
}
}
QWidget *SubPlugin::getWidget()
{
if(!mGenWidget){
mGenWidget = new Form;
}
return mGenWidget;
}
6.去掉mainProject项目和subPlugin项目的的影子编译
7.将插件subPlugin项目的PluginInterface.h赋值一份到mianProject项目中,并添加到主项目录
8.把subPlugin项目生成的dll文件复制一份到mianProject主项目
这个运行动态库项目没有exe是很正常的。反正我的没有,有dll就行
9.编写主程序代码
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QPluginLoader>//插件加载类
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
QPluginLoader loader;
bool isPluginLoaded; // 标志插件是否已加载
void removeTabWithTitle(const QString &title);
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "PluginInterface.h"
#include <QDir>
#include <QMessageBox>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
, isPluginLoaded(false) // 新增标志以跟踪插件是否已加载
{
ui->setupUi(this);
// 初始化按钮文本
ui->pushButton->setText("加载插件");
}
MainWindow::~MainWindow()
{
// 在销毁窗口时,检查并卸载已加载的插件
if (isPluginLoaded) {
loader.unload();
}
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
if (isPluginLoaded) {
// 如果插件已经加载,执行卸载操作
loader.unload();
removeTabWithTitle("插件标签"); // 清除具有特定标题的标签页
isPluginLoaded = false; // 更新插件加载标志
ui->pushButton->setText("加载插件"); // 更新按钮文本
qDebug("插件已卸载");
} else {
// 插件未加载时,进行加载操作
QDir dir("D:/EmbeddedDevelopment/Qt/Plugins/mainProject/debug");
// 如果需要使用应用程序的运行目录,可以启用以下代码
// QDir dir(qApp->applicationDirPath());
qDebug("目录1: %s", dir.path().toUtf8().constData()); // 输出目录路径
// 设置插件文件路径并准备加载插件
loader.setFileName(dir.filePath("subPlugin.dll"));
qDebug("目录2: %s", dir.filePath("subPlugin.dll").toUtf8().constData()); // 输出插件文件路径
// 尝试加载插件
if (!loader.load()) {
qDebug("Failed to load loader");
QMessageBox::critical(this, "错误", loader.errorString()); // 显示错误信息
return;
}
// 创建插件实例
QObject *plugin = loader.instance();
if (!plugin) { // 如果插件实例为空,输出错误信息并退出
qDebug("loader.instance() is null");
return;
}
qDebug("插件实例创建成功");
// 将插件实例转换为 PluginInterface 类型
PluginInterface *pi = qobject_cast<PluginInterface *>(plugin);
if (pi) { // 如果转换成功,获取插件的 QWidget 并添加到 TabWidget 中
QWidget *w = pi->getWidget();
if (w) {
ui->tabWidget->addTab(w, "插件标签"); // 添加插件的 QWidget 为新标签页
qDebug("插件标签添加成功");
isPluginLoaded = true; // 更新插件加载标志
ui->pushButton->setText("卸载插件"); // 更新按钮文本
} else {
qDebug("插件未返回有效的 QWidget");
}
} else {
qDebug("插件转换失败,pi is NULL");
}
}
}
void MainWindow::removeTabWithTitle(const QString &title)
{
int count = ui->tabWidget->count();
for (int i = 0; i < count; ++i) {
if (ui->tabWidget->tabText(i) == title) {
ui->tabWidget->removeTab(i);
return; // 一旦找到并移除目标标签页后退出
}
}
}
10.运行结果
可以添加卸载插件界面,其实添加的是一个不能自己独立运行的封装好的动态库界面,而且项目直接没有层级,故我不建议采纳这种方法