qt 插件plugin之间的通信机制,与主程序通信

首先说下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是否合适?

废话说完转入正题.


方法1,纯虚函数做接口interface:


这种方法就是纯虚函数接口,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");
    }
}


方法2,接口直接继承QObject并声明signal:


首先遇到问题是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就没法编译通过了。


本文为3YL原创,转载无需联系,但请注明来自labisart.com。

原创文章不易,如果觉得有帮助,可打赏或点击右侧广告支持:

查看打赏记录

发表评论请遵守党国法律!后台审核后方可显示!
  • 最新评论
  • 总共0条评论
  • Blog v1.1© 2024 labisart.com 版权所有 | 联系:labartwork@163.com