Qt是否提供了解特定插槽待处理的待处理排队信号数的功能?有没有办法清除它们?例如,如果对连接到给定插槽的信号进行了多次发射,那么有人可以知道这些发射信号的数量吗?
QMetaObject::Connection类具有简洁的界面,似乎不提供相关功能。删除接收信号的对象,从而破坏连接,解决了问题。但有没有办法在不断开插槽或删除接收对象的情况下执行此操作?
答案 0 :(得分:2)
您提出问题的原因很可能表明您的设计已被破坏。信号和插槽是解耦代码的机制。连接在一起的物体无论有多少发送者或接收者,都应该表现自己,当然不应该试图追踪这些事情!
通过改变设计从源头解决问题会更明智。如果您遇到事件风暴,例如由于更改了插槽中窗口小部件的数据,插槽应该非常轻量级,并且只能通过调用update()
计划更新窗口小部件,但永远不会强制立即重新绘制。这利用了Qt完成的重绘事件压缩。您可能希望compress your own events too。
Qt中的信号和插槽可以使用直接,排队或阻塞连接进行传递。自动类型实际上不是固定连接类型。这是一条指令解析每个接收器的类型在每个信号发射直接或排队类型。
直接连接就像任何间接函数调用一样:没有排队,并且从信号方法体内调用插槽:
// all direct-connected slots/functors are invoked before mySignal() returns
emit mySignal();
排队连接将QMetaCallEvent
发布到接收对象线程的事件循环。该事件包含调用的参数,或带有仿函数。是由QObject::event()
处理。你当然可以拦截这些事件。有关详细信息,请参阅this question。
答案 1 :(得分:0)
据我所知,无法访问队列。
首先,如果插槽位于 QWidget 子类中,则在GUI线程中,您只需更新成员变量并调用update()
,然后只使用当前调用时paintEvent()
中的值。它们会自动压缩,因此无论调用update()
多少次,都只会有一次重绘事件。
但是,如果插槽与绘画无关,或者根本不在GUI线程中,则需要其他内容。
许多需要此功能的案例的简单解决方案是使用延迟为0的第二个插槽和单次 QTimer (如果需要,甚至更长的延迟)。
这里有一些示例代码,可以让您了解我的意思:
// in constructor, set mActualSlotTimer to
// singleshot, interval 0, parent this (needed for multi-threaded use)
// and connect timeout() to privateActualSlot()
// public slot for receiving the signal from outside
void MyClass::actualSlot(int data) {
// class member to store the new data value until it can be set
mNewData = data;
// restart the timer, no matter if it was already running or not
mActualSlotTimer.start();
}
// "private" slot for actually doing the change
void MyClass::privateActualSlot() {
// maybe useful: if (this->mData == this->mNewData) return;
mData = mNewData;
// do whatever else needs to be done!
}
显然,如果您的公开广告位实际上没有采用任何参数,那么您就不需要mData
和mNewData
。
关于这种方法需要注意的一点是,它适用于所有连接,它不仅限于Qt::QueuedConnecton
。因此,它也使得使用Qt::BlockingQueuedConnection
有点毫无意义。
免责声明:我简要检查了Qt源代码,似乎使用间隔为0的计时器应该没问题:重新启动计时器将按预期工作。但是如果对privateActualSlot
的调用似乎仍然太多,那么提供合适的间隔可能是必要的。我通常想要稍微延迟(例如5毫秒)来减少比#34更频繁的事情和#34;,所以没有对间隔0进行广泛的测试。