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

Connect one object to many objects of same type

所以我有以下设置:

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

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

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

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

有没有更好的方法?

编辑 1 我已经编辑了示例以表明我可以拥有任意数量的设备..它不是硬编码的数字,所以如果我需要为每个设备使用 signal/slot,则需要动态创建信号。

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

这允许我在任何对象上调用一个槽(排队,因此它的线程安全)并传递我的数据....但如果我这样做,我感觉我正在破坏基本的 Qt slots/signals 方法.

使用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

所以我在互联网上没有找到太多关于这个问题的信息。我看到人们尝试 use/answer 问题的一些可能性是:

1。 QSignalMapper

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

2。直接调用目标槽

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

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

其中:

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

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

3。动态插槽创建

我在 qt 文档 here, about halfway down 中读到了这个 here, about halfway down,但它看起来像可怕的代码 write/maintain 所以我什至没有尝试这个。

我提出的解决方案

所以最后我决定我必须梦想一些东西。因为我只知道在 运行 时间我将拥有多少设备,所以在每个设备注册时动态创建信号很有吸引力,但如上所述,不是很好。

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

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

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

据我所知,这是唯一的 "correct/simple" 方法,因为 qt slots/signals 似乎没有设置为进行消息路由。如果我错了请大家指正!