有没有办法在连接到同一信号的许多插槽之一中消耗未来的插槽(并阻止它们执行)?
我的目标是向许多QObject发出带有消息的信号,并在消息所属的QObject找到它时消耗(停止迭代到未来的插槽)。
根据我在Qt Documentation中的理解:
如果有多个插槽连接到一个信号,则插槽将是 按照他们连接的顺序依次执行, 当信号发出时。
我希望能够从插槽中停止此过程。
建议?
答案 0 :(得分:1)
不,没有办法做到这一点,你不应该这样想。无论连接到信号的插槽数是多少,发送方都应该执行相同的操作。这是信号槽机制的基本合同:发送器完全与接收器分离,并且不知道接收器。
您要做的是合格调度:有多个接收器,每个接收器可以处理一种或多种消息类型。实现它的一种方法如下:
发出(发出信号)a QEvent
。这使您可以保持发送器和接收器之间的信号槽去耦。
然后,事件可由自定义事件调度程序使用,该事件调度程序知道哪些对象处理给定类型的事件。
对象以通常的方式发送给事件,并以event()
方法接收。
下面的实现允许接收器对象存在于其他线程中。这就是为什么它需要能够克隆事件。
class <QCoreApplication>
class <QEvent>
class ClonableEvent : public QEvent {
Q_DISABLE_COPY(ClonableEvent)
public:
ClonableEvent(int type) : QEvent(static_cast<QEvent::Type>(type)) {}
virtual ClonableEvent * clone() const { return new ClonableEvent(type()); }
}
Q_REGISTER_METATYPE(ClonableEvent*)
class Dispatcher : public QObject {
Q_OBJECT
QMap<int, QSet<QObject*>> m_handlers;
public:
Q_SLOT void dispatch(ClonableEvent * ev) {
auto it = m_handlers.find(ev->type());
if (it == m_handlers.end()) return;
for (auto object : *it) {
if (obj->thread() == QThread::currentThread())
QCoreApplication::sendEvent(obj, ev);
else
QCoreApplication::postEvent(obj, ev.clone());
}
}
void addMapping(QClonableEvent * ev, QObject * obj) {
addMapping(ev->type(), obj);
}
void addMapping(int type, QObject * obj) {
QSet<QObject*> & handlers = m_handlers[type];
auto it = handlers.find(obj);
if (it != handlers.end()) return;
handlers.insert(obj);
QObject::connect(obj, &QObject::destroyed, [this, type, obj]{
unregister(type, obj);
});
m_handlers[type].insert(obj);
}
void removeMapping(int type, QObject * obj) {
auto it = m_handlers.find(type);
if (it == m_handlers.end()) return;
it->remove(obj);
}
}
class EventDisplay : public QObject {
bool event(QEvent * ev) {
qDebug() << objectName() << "got event" << ev.type();
return QObject::event(ev);
}
public:
EventDisplay() {}
};
class EventSource : public QObject {
Q_OBJECT
public:
Q_SIGNAL void indication(ClonableEvent *);
}
#define NAMED(x) x; x.setObjectName(#x)
int main(int argc, char ** argv) {
QCoreApplication app(argc, argv);
ClonableEvent ev1(QEvent::User + 1);
ClonableEvent ev2(QEvent::User + 2);
EventDisplay NAMED(dp1);
EventDisplay NAMED(dp12);
EventDisplay NAMED(dp2);
Dispatcher d;
d.addMapping(ev1, dp1); // dp1 handles only ev1
d.addMapping(ev1, dp12); // dp12 handles both ev1 and ev2
d.addMapping(ev2, dp12);
d.addMapping(ev2, dp2); // dp2 handles only ev2
EventSource s;
QObject::connect(&s, &EventSource::indication, &d, &Dispatcher::dispatch);
emit s.indication(&ev1);
emit s.indication(&ev2);
return 0;
}
#include "main.moc"
答案 1 :(得分:0)
如果连接在一个线程中,我认为你可以抛出异常。但在这种情况下,你应该在发出信号时发现任何异常:
try {
emit someSignal();
} catch(...) {
qDebug() << "catched";
}
但我认为这是个坏主意。我将使用事件调度。