首先说下qt的插件,扫一下盲,很多新人会有点懵逼,它包含几大类:
1、qt内核插件plugin:用来完善qt本身的功能,比如你搞个数据库插件,让别人可以直接用来读写数据库,这个也叫high-level api
2、qtcreator插件:用来扩展qtcreator的功能,比如代码缩进整理
3、qtdesigner插件:用来当作普通控件使用,比如你制定一个绿色button,写完插件后拖到qtdesigner的plugin目录,然后就可以愉快的用鼠标拖拉这个绿色button到你的widget了,可以参考:http://labisart.com/blog/index.php/Home/Index/article/aid/172
4、普通程序插件:官方例子Plug & Paint的解析很好,实际上qtcreator也是基于此方法然后扩展出自己的插件
我们这里说的就是第四种:普通程序插件
创建和调用都比较简单,主要说说插件怎么发信号和槽,主要参考3篇文章:
https://blog.csdn.net/kenfan1647/article/details/107493294
https://blog.csdn.net/Ecrhon/article/details/83622545
https://blog.csdn.net/yizhou2010/article/details/79961554
我们不希望自定义结构体来做转发,所以还是希望用原生的signal/slot机制来通信。当然,插件本身应该是解耦的,如果互相调用又违反了这个规则了,可以思考下互相connect是否合适?
废话说完转入正题.
这种方法就是纯虚函数接口,signal和slots你不要声明,但是要加注释,不然别人用你的接口的时候搞不清哪个跟哪个。
然后在插件类的实现中,指定哪些是signal,哪些是slots即可:
#ifndef MYINTERFACE4_H
#define MYINTERFACE4_H
#include <QWidget>
#include <QObject>
class _MyPlugin4
{
public:
~_MyPlugin4() = default;
virtual QWidget *CreateWidget(QWidget *parent)=0;
virtual int add(int a,int b)=0;
//signals:
virtual void sigAdd(QString txt)=0;
//public slots:
// 直接当作曹函数
virtual void onNotify(QString txt) =0;
};
Q_DECLARE_INTERFACE(_MyPlugin4,"com.company._MyPlugin4/1.0")
#endif // MYINTERFACE_H继承的插件实现定义如下:
class MyPlugin4 :public QObject,
public _MyPlugin4,
public IPluginBase
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QGenericPluginFactoryInterface4" FILE "MyPlugin4.json")
Q_INTERFACES(_MyPlugin4 IPluginBase)
public:
QWidget *CreateWidget(QWidget *parent) override;
int add(int a,int b) override;
//
signals:
void sigAdd(QString txt) override;
public slots:
void onNotify(QString txt) override;
};connect的时候找到qobject,然后使用传统的connect方法即可连接。
// pb pbMyplugin4Add
void MainWindow::on_pbMyplugin4Add_clicked()
{
QObject *obj = PluginManager::i().plugin("MyPlugin4");
if(obj == nullptr){
T_ERR << "实例为空";
return;
}
_MyPlugin4 *m2 = qobject_cast<_MyPlugin4*>(obj);
if(m2 != nullptr){
// 链接信号和曹,要用object才可链接
connect(obj,SIGNAL(sigAdd(QString)),this,SLOT(onAdd(QString)),Qt::UniqueConnection);
T_INF <<"1+2="<<m2->add(1,2);
// 发信号给这个插件
connect(this,SIGNAL(notifyPlugin(QString)),obj,SLOT(onNotify(QString)),Qt::UniqueConnection);
emit notifyPlugin("mainwindow to plugin");
}
}首先遇到问题是signal不能为虚函数:https://stackoverflow.com/questions/50516359/declaring-signals-in-interface-class-using-qt-plugin-system-with-new-signal-slot
然后你connect的时候,如果用QT5的新语法,他就提示找不到信号函数所在的符号,解决方案2个:
1、把接口建立为dll工程,跟着exe走,也是上面文章说的,这个显然很挫
2、使用connect老方法即可
不推荐用这个,大家用我上面这个靠谱一点,可以留言交流。
另外要注意,插件子类的实现不能把构造函数隐藏起来,即
private: MyClass();
是不行的,moc会以new生成新实例,如果定义为private就没法编译通过了。
空名网友:你这个确定能用?我用5.15.2 按你这个写了一遍,提示sigAdd没有override。
2025-11-06 11:42:25 回复