将一个对象连接到许多相同类型的对象

时间:2015-10-12 14:30:08

标签: c++ qt signals-slots

所以我有以下设置:

|---- Device[1] Controller ---+---- Device[2] |---- Device[3] | : |---- Device[x]

每个对象都在自己的线程中。

对于从Deivce [x]到控制器的通信,这是相对简单的,我只是将所有设备信号连接到控制器中的插槽,并将设备索引作为参数传递,以便控制器可以识别哪个设备。

但是,我不确定如何在另一个方向(控制器到设备)上做同样的事情。我提出的最好的是一个类似的方案,我将控制器中的信号连接到每个设备的插槽。我仍然可以传递索引,因此如果消息指向Device [1],则Device [2]和Device [3]可以忽略它。但是,这在数据重复方面是一个巨大的开销吗? - 即数据是否已发送三次?

有更好的方法吗?

编辑1 我编辑了这个例子,表明我可以拥有任意数量的设备..它不是硬编码的数字,所以如果我需要为每个设备提供信号/插槽,则需要动态创建信号。

编辑2 看来你可以直接用以下方法调用方法: QMetaObject::invokeMethod(devices[x], "handleMessage", Qt::QueuedConnection, Q_ARG(QByteArray msgData)));

这允许我在任何对象上调用一个插槽(排队,所以它的线程安全)并传递我的数据....但是如果我这样做,感觉就像我打破了基本的Qt插槽/信号方法。

2 个答案:

答案 0 :(得分:1)

所以我在互联网上找不到这个问题。我看到有些人可能会尝试使用/回答问题:

<强> 1。 QSignalMapper

这有其局限性,我在ram的回答中已经评论过。

<强> 2。直接调用目标槽

你可以直接调用目标插槽(跨线程边界是!),这可以如下所示完成(只显示完整性):

QMetaObject::invokeMethod(devices[x], "handleMessage", Qt::QueuedConnection, Q_ARG(QByteArray msgData)));

其中:

  • Devices [x]是指向设备对象的指针
  • &#34;的handleMessage&#34;是插槽功能的名称
  • 排队连接用于确保其线程安全,而不是在调用线程中调用。
  • Q_ARG(...)是传递给插槽的参数,在本例中是一个名为msgData的QByteArray。注意:您可以拥有其中的多个。

这很好用,但它打破了插槽/信号的整个方法,因为我们在没有信号或连接的情况下调用异物中的插槽...有效地在墙上打孔并抓住我们想要的东西 - 所以它也打破了封装原则(不提及线程边界)。

第3。动态插槽创建

我在qt文档here, about halfway down中看到了这一点,但是看起来像是一个糟糕的代码需要编写/维护所以我甚至都没有尝试过。

我建议的解决方案

所以最后我决定要做些什么。因为我只知道运行时会有多少设备,所以每个设备注册时动态创建信号都很吸引人,但如上所述,不是很好。

但是我们可以动态地实例化对象,其中对象包含可用于将一对一映射到设备的信号。有效地创建一个&#34;邮箱&#34;对象,其信号可以在运行时连接到等效设备。设置如下所示:

|-------------------------| | | | Postbox[1]--+------Device[1] | Controller Postbox[2]--+------Device[2] | Postbox[3]--+------Device[3] | | : | Postbox[x]--+------Device[x] | | |-------------------------|

控制器对象包含邮箱对象的数组(或向量)。对于向控制器注册的每个设备,它会创建一个新的邮箱实例,将其信号连接到设备插槽,然后将邮箱添加到阵列。然后,为了向例如设备[3]发布消息,控制器只调用类似postboxes[3].postmessage(msgData);的函数,postmessage函数发出连接到设备的信号[3]。

据我所知,这是唯一的&#34;正确/简单&#34;这样做的方法是因为qt slot / signals似乎没有设置为进行消息路由。如果我错了,请有人纠正我!

答案 1 :(得分:0)

使用QSignalMapper

Controller::Controller()
{
    QSignalMapper* signalMapper = new QSignalMapper(this);
    for (int i = 0; i < deviceCount; ++i) {
        Device* d = new Device(...);
        connect(d, SIGNAL(somethingHappened)), signalMapper, SLOT(map()));
        signalMapper->setMapping(d, i);
    }

    connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(handleDevice(int)));
}

void Controller::handleDevice(int id)
{
 .....
}

更多信息:http://doc.qt.io/qt-5/qsignalmapper.html