2013-06-19 63 views
0

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

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

在此先感谢。

+0

我想你忘记了Qt本身就是一个共享库。那么为什么你会认为信号和共享库可能会有问题呢? –

回答

4

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

使用单个信号signalUpdateGUIStatus(QString)的单个“通用类”最有可能是错误的方法。仅仅因为它是一个单独的库,将接口限制为单个类或甚至信号是毫无意义的。小接口是好的 - 但除非你的后端代码只发送一种非常特定的更新,“signalUpdateUIStatus(QString whatChangedEncodedAsString)”将通过单个类/信号做太多的事情。signalUpdateGUIStatus还意味着后端库知道有一个用户界面。它不应该。它只是提供有关网络设备的信息 - 无论是显示信息的用户界面,还是通过电子邮件发送通知(或其他任何内容)的bot都不是它的业务。

你可以有一个共享库,如LightSensorListener,TemperatureSensorListener等等(或者只是DeviceListener,depends),它们可能是QObject在值发生变化时发出信号,但也有其他的Q_PROPERTYs,方法等。类将在应用程序中实例化,然后连接到UI代码。

想想你如何在你的应用程序中使用Qt。您的图书馆将成为您用来从网络获取数据的另一个图书馆。就像你使用QString,QWidget,QLineEdit等一样创建和使用的UI交互,你会用你的库的类与网络接口:

比方说,我们的图书馆“富”有一类温度传感器节:

//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&); 
}; 

然后应用程序,你刚刚创建的实例和钩他们与你的用户界面:

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

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

有关文档,所有公共类(也就是出口即一切)库的应记录在案。信号/插槽通常与其他“正常”方法一样被记录。

+0

感谢您提供深入的解释。 – Rak

+0

谢谢。我的共享库包含其他类,并在设备发现旁边执行其他任务。但共享库仅将包含多个信号的'shareLibAPIClass'类导出到应用程序模块。我认为我的实现符合您的解释,因为我正在创建导出类的实例,并为来自该导出类的信号连接插槽。我应该使用信号的一般术语(避免GUI术语)。我看到的唯一问题是我有一个从应用程序到共享库的信号,它启动了设备配置。不知道该如何处理。有什么建议? – Rak

+0

通过从应用程序到库的信号/插槽触发搜索就好了。我可能还会添加一些属性,以提供关于状态(“空闲”,“搜索”)和潜在错误的信息。 –