将一个对象连接到多个相同类型的对象
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)
{
.....
}
所以我在互联网上没有找到太多关于这个问题的信息。我看到人们尝试 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 似乎没有设置为进行消息路由。如果我错了请大家指正!
所以我有以下设置:
|---- 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)
{
.....
}
所以我在互联网上没有找到太多关于这个问题的信息。我看到人们尝试 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 似乎没有设置为进行消息路由。如果我错了请大家指正!