Qt学习--Qt Plugin创建及调用3(接口间通信)

转载 2018年04月16日 15:44:37

Qt Plugin创建及调用3(接口间通信)

转载http://blog.csdn.net/liang19890820

简述

插件接口(Interface)的作用,就是提供一个与其他系统交互的方法。其他系统无需(也无法)了解内部的具体细节,只能通过对外提供的接口来与进行通信。在上一篇的PluginInterface接口中,我们定义了两个纯虚函数

virtual void setInitData(QStringList &strlist) = 0;
virtual void getResultData(QStringList &strlist) = 0;

这两个纯虚函数可以在插件实现类中重写,同样对于槽函数也可以同样定义,那么信号呢?

在 Qt 中,定义一个纯虚信号有效吗?

的确,这个话题非常有意思。。。通常,我们会定义一些纯虚的槽函数,但关于纯虚信号这个话题讨论的比较少!那么,信号可不可以是纯虚的呢?

一些尝试

关于信号和纯虚,我们知道:

  • 信号永远不会有实现(也就是说,在 .h 中定义了信号,在 .cpp 中不需要实现)
  • 声明一个纯虚函数的主要目的,是强制继承的类提供一个实现。

信号没有实现,如果将其声明为纯虚的,需要继承的类来提供一个实现,这与“信号没有实现”直接冲突。就好比让一个人同时出现在两个地方,这是不可能的。因此,似乎声明一个纯虚信号是一个错误。

在编写完一个接口时,为了能使用 Qt 的信号槽特性,很多人可能会写出类似下面的代码:

#ifndef PLUGININTERFACE_H
#define PLUGININTERFACE_H
#include <QStringList>
#include <QObject>
class PluginInterface : public QObject
{
    Q_OBJECT
public:
    virtual ~PluginInterface() {}

public:
    virtual void setInitData(QStringList &strlist) = 0;
    virtual void getResultData(QStringList &strlist) = 0;
signals:
    virtual void information() = 0;
};
#define PluginInterface_iid "QtPluginsTest.QtPluginsManager.PluginInterface"

Q_DECLARE_INTERFACE(PluginInterface, PluginInterface_iid)

#endif // PLUGININTERFACE_H

很遗憾,Qt 发出了警告:

warning: Signals cannot be declared virtual

那么,如何解决这个问题呢?

解决方案

下面,列出三种解决方案:

  • 派生自 QObject,信号不使用 virtual
  • 将“信号”定义为一个纯虚函数
  • 在接口中定义信号槽的连接方式

派生自 QObject,信号不使用 virtual

不让用 virtual,好吧,那就不用了,这算是最简单的解决方式!

#ifndef PLUGININTERFACE_H
#define PLUGININTERFACE_H
#include <QStringList>
#include <QObject>
class PluginInterface : public QObject
{
    Q_OBJECT
public:
    virtual ~PluginInterface() {}

public:
    virtual void setInitData(QStringList &strlist) = 0;
    virtual void getResultData(QStringList &strlist) = 0;
signals:
    virtual void information() = 0;
};
#define PluginInterface_iid "QtPluginsTest.QtPluginsManager.PluginInterface"

Q_DECLARE_INTERFACE(PluginInterface, PluginInterface_iid)

#endif // PLUGININTERFACE_H

但是这种方式并不算理想,因为一般来说,接口是一个简单的 C++ 类,不需要派生自 QObject

将“信号”定义为一个纯虚函数

将“信号”定义为一个纯虚函数:

#ifndef PLUGININTERFACE_H
#define PLUGININTERFACE_H
#include <QStringList>
class PluginInterface
{
public:
    virtual ~PluginInterface() {}

public:
    virtual void setInitData(QStringList &strlist) = 0;
    virtual void getResultData(QStringList &strlist) = 0;
//signals:不是一个信号(但可以当做信号来用)
    virtual void information() = 0;
};
#define PluginInterface_iid "QtPluginsTest.QtPluginsManager.PluginInterface"

Q_DECLARE_INTERFACE(PluginInterface, PluginInterface_iid)

#endif // PLUGININTERFACE_H

注意: 对于 IClock 来说,alarm() 只是一个纯虚函数,并不是一个“信号”(但可以当做信号来用),因为 IClock 不是 QObject

由于需要信号支持,所以具体实现需要派生自 QObject。此外,还需要将 information() 定义为 signals

#ifndef PLUGIN_H
#define PLUGIN_H

#include "plugininterface.h"
#include <QObject>
#include <QtDebug>

class Plugin : public QObject, public PluginInterface
{
    Q_OBJECT

public:
    Plugin() {}

    void setInitData(QStringList &strlist) override{
    //do something
    }
    void getResultData(QStringList &strlist)override{
    //do something
    }

signals:
    // 实现由 moc 来完成
    void information() override;
};

#endif // PLUGIN_H

这时,alarm() 的具体的实现在内部是由 moc 来完成的。

void monitorInformation(Plugin *p_Plugin) {
        QObject *pluginObject = dynamic_cast<QObject *>(p_Plugin);
        if (pluginObject) {
            connect(pluginObject, SIGNAL(information()), this, SLOT(onInformation()));
        } else {
            qWarning() << "cannot monitor Information";
        }
    }

注意: 连接信号时,需要将其转换为 QObject

在接口中定义信号槽的连接方式

除了上述方式之外,还可以在接口中定义信号槽的连接方式。

首先,定义一个连接信号槽的接口 - connect_information()

#ifndef PLUGININTERFACE_H
#define PLUGININTERFACE_H
#include <QStringList>
class PluginInterface
{
public:
    virtual ~PluginInterface() {}

public:
    virtual void setInitData(QStringList &strlist) = 0;
    virtual void getResultData(QStringList &strlist) = 0;

   //connect to signals
    virtual bool connect_information(QObject *receiver, const char* pszSlot, bool isConnect = true) = 0;
};
#define PluginInterface_iid "QtPluginsTest.QtPluginsManager.PluginInterface"

Q_DECLARE_INTERFACE(PluginInterface, PluginInterface_iid)

#endif // PLUGININTERFACE_H

然后,在派生类中实现信号槽的具体连接:

bool GenericPlugin2::connect_information(QObject *receiver, const char *pszSlot, bool isConnect)
{
    if(isConnect)
        return connect(this, SIGNAL(information(QString&)), receiver, pszSlot);
    else
        return disconnect(this, SIGNAL(information(QString&)), receiver, pszSlot);
}

除了信号槽之外,Qt 还可以通过事件机制(sendEvent()postEvent())来实现接口之间的通信。正如上所示,只要通过接口来获得 QObject 即可。

Qt plugin 的创建和动态加载

Qt plugin 的创建和动态加载 介绍 plug in 是一个实现了一个或多个接口的DLL,下面我们将介绍在QT中如何创建PLUG IN 和如何动态加载PLUG IN ...
  • gxp
  • gxp
  • 2013-08-17 11:01:52
  • 840

QT_plugin的创建和调用方法

  • 2011年01月10日 19:33
  • 427KB
  • 下载

如何创建Qt Plugins (插件)之 使用高级api

Qt提供了2个api来创建插件:QStringList SimpleStylePlugin::keys() const { return QStringList() ...
  • penghuilater
  • penghuilater
  • 2016-11-17 13:41:49
  • 1195

qt和VS动态库调用示例

  • 2016年06月02日 17:33
  • 12.26MB
  • 下载

QT 窗体间通信

多窗体的实现我们可以在 1:在一个创体内控制另一个窗体显示(信号,槽的使用) 2:在一个窗体内触发另一个窗体内的信号,槽,函数 (信号,槽的使用) 3,在一个创体内修改另一个创体内部件的属性,值...
  • liang890319
  • liang890319
  • 2011-12-12 19:01:06
  • 9023

利用Qt进行接口间通信

> 接口的作用,就是提供一个与其他系统交互的方法。其他系统无需(也无法)了解内部的具体细节,只能通过对外提供的接口来与进行通信。 纯虚函数(槽也不例外)很容易理解,那么信号呢? > 在 Qt 中,...
  • u011012932
  • u011012932
  • 2017-09-29 19:56:24
  • 3914

C++ Qt 调用动态库 插件

1.隐式调用
  • tujiaw
  • tujiaw
  • 2014-07-20 22:55:42
  • 3268

Qt Quick 2 Extension Plugin 扩展插件

一.扩展插件的使用在我们使用Qml的时候都会看到类似下面的语句import QtQuick 2.2import QtQuick.Window 2.2import QtQuick.Controls 1....
  • qq_15024587
  • qq_15024587
  • 2018-03-16 16:45:02
  • 64

Qt一步一步实现插件调用(附源码)、Qt一步一步实现插件通信(附源码)

Qt一步一步实现插件调用(附源码) 最近手里几个项目都采用插件的方式进行开发工作,这里记录一下实现方法,给需要的同学一个参考, 在linux系统和window系统都能成功编译通过,不废话直...
  • zzwdkxx
  • zzwdkxx
  • 2014-07-13 18:04:35
  • 2212

Qt进程通信

  • 2012年02月27日 15:54
  • 10KB
  • 下载
收藏助手
不良信息举报
您举报文章:Qt学习--Qt Plugin创建及调用3(接口间通信)
举报原因:
原因补充:

(最多只允许输入30个字)