【问题标题】:Using signals and slots between Qt shared library and Qt application在 Qt 共享库和 Qt 应用程序之间使用信号和槽
【发布时间】:2013-06-19 16:08:20
【问题描述】:

我有一个工作示例,它使用信号和插槽在 Qt 共享库 (dll) 和 Qt 应用程序之间进行通信。我的问题是,它是首选方式还是有更好的方式来处理 qt 共享库。以下是详细信息:

我开发的应用程序具有侦听网络上的设备和更新 GUI 的功能。共享库负责监听网络上的设备,Qt 应用程序模块负责 GUI 部分。

我有一个宏,它使用 Q_DECL_EXPORT / Q_DECL_IMPORT 来导出共享库和应用程序使用的公共类。这个通用类派生自 QObject 并定义了 Qt 信号和槽。这个公共类是作为共享库 (dll) 的一部分构建的。

Qt 应用程序在编译时加载共享库并为公共类创建一个实例,并使用该实例在 Qt 应用程序和 Qt 共享库模块之间设置信号和槽,如下所示:

Qt 应用程序初始化期间:

// Create shared libray API class instance to access dll module features.
mp_sharedlib_api = new shareLibAPIClass( this );

Qt 应用程序及更高版本:

// Connect signal/slot between shared library and Qt application
connect(
    mp_sharedlib_api , SIGNAL( SignalUpdateGUIStatus( QString ) ),
    this, SLOT( SlotUpdateGUIStatus( QString ) )
    );

这是开发使用共享库的 Qt 项目的正确方法吗?共享库的 API 文档包含哪些内容? API 文档是否列出了共享库发送/处理的信号和插槽?

提前致谢。

【问题讨论】:

  • 我想你忘记了 Qt 本身是一个共享库。那么,您为什么认为信号和共享库可能存在任何问题?

标签: qt shared-libraries


【解决方案1】:

您不应该想到通过信号和插槽连接的两个库,而是一组类/类实例、一组与后端相关的类和一组与 UI 相关的类。 UI 类使用后端类(但从不反过来)。这两组类位于不同的库中是部署的实现细节,与 C++ 级别的应用程序设计几乎无关。即使所有代码在一个应用程序中链接在一起,设计概念也是相同的。

拥有一个带有单个信号signalUpdateGUIStatus(QString) 的“公共类”很可能是错误的方法。仅仅因为它是一个单独的库,就将接口限制为单个类甚至信号是没有意义的。小接口很好 - 但除非您的后端代码只发送一种非常特定的更新,否则“signalUpdateUIStatus(QString whatChangedEncodedAsString)”将通过单个类/信号做太多事情。 signalUpdateGUIStatus 还暗示后端库知道有一个 UI。它不应该。它只是提供有关网络上设备的信息——无论是显示信息的 UI 还是某些通过电子邮件(或其他)发送通知的机器人都与它无关。

您可以拥有一个共享库,其中包含 LightSensorListener、TemperatureSensorListener 等(或只是 DeviceListener、depends)等导出类,这些类可能是 QObject 在值更改时发出信号,但也有任何其他 Q_PROPERTY、方法等。这些类将在应用程序中实例化,然后连接到 UI 代码。

想想你是如何在你的应用程序中使用 Qt 的。您的库将是另一个库,您可以使用其类从网络获取数据。就像您使用 QString、QWidget、QLineEdit 等来创建 UI 并与之交互一样,您将使用库中的类与网络进行交互:

假设我们的库“foo”有一个温度传感器类:

 //file TemperatureSensor.h

 /**
  * A temperature sensor on the network.
  * yaddayaddayadda
  */
 class FOO_EXPORT TemperatureSensor {
      Q_OBJECT
      Q_PROPERTY(QString address READ address WRITE setAddress NOTIFY addressChanged)
      Q_PROPERTY(bool available READ available NOTIFY availableChanged)
      Q_PROPERTY(qreal temperature READ temperature NOTIFY temperatureChanged) 
 public:
      /**
       * Creates a temperature sensor
       *
       * @param parent parent QObject
       */
      explicit TemperatureSensor(QObject* parent=0);

      /**
       * Returns whether the device is currently available and delivering data
       */
      bool available() const;
      /**
       * Returns the temperature reported by the sensor (In Celsius)
       */
      qreal temperature() const;

      /**
       * Makes the device explode. Use with caution!
       * Don't give this to little developers/children.
       */          
      void blowUp();

      //address(), setAddress() etc...
 Q_SIGNALS:
      /**
       * The availability of the sensor changed
       *
       * @param available whether the sensor is now available
       */
      void availableChanged(bool available);
      void temperatureChanged(qreal);
      void addressChanged(const QString&);
 };

然后是应用程序,您只需创建实例并将它们与您的 UI 挂钩:

 TemperatureSensor sensor;
 sensor.setAddress("/tempsensors/1234");

 TemperaturWidget widget;
 widget.show();
 //connect signals from sensor, or pass the whole sensor instance, etc.

对于文档,应记录库的所有公共类(即导出的所有内容)。信号/插槽通常像其他“正常”方法一样记录。

【讨论】:

  • 感谢您提供深入的解释。
  • 谢谢。我的共享库确实包含其他类并在设备发现之外执行其他工作。但共享库仅将包含多个信号的“shareLibAPIClass”类导出到应用程序模块。我认为我的实现符合您的解释,因为我正在创建导出类的实例并为来自该导出类的信号连接插槽。我应该对信号使用通用术语(避免使用 GUI 术语)。我看到的唯一问题是我有一个从 App 到共享库的信号,它启动了设备配置。不知道如何处理。有什么建议吗?
  • 通过从应用程序到库的信号/插槽触发搜索就可以了。我可能还会添加一些属性以提供有关状态(“空闲”、“搜索”)和潜在错误的信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-11-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多