调试信号和槽可能很困难,因为当信号被发射时,调试器不会跳转到槽。以下是一些Qt信号和槽调试的最佳实践。
具体来说:
- 如何确保连接成功建立?
- 何时应该使用信号和槽,何时应该避免使用它们?
- 根据您的经验,哪些是最有效的调试技巧?
调试信号和槽可能很困难,因为当信号被发射时,调试器不会跳转到槽。以下是一些Qt信号和槽调试的最佳实践。
具体来说:
有一篇博客文章叫做“20种调试Qt信号和槽的方法”,写得有一段时间了。
我认为它解决了你问题中的#1和#3。
对于#2,我认为没有必须使用或不使用信号/槽的硬性规定,因为它们是GUI框架的核心概念。信号是一种完美的方式来解耦一个组件与另一个组件的知识,允许您设计可重用的小部件,仅声明状态更改或通知。它还是一种非常好的方式来从非GUI线程循环通知GUI更改,通过发出主线程可以看到的信号。
有时候,你真正想要的不是信号/槽,而是使用事件,例如当父窗口应该成为多个子窗口的事件过滤器时。子项仍然不需要知道父项,而父项会获得更直接的事件,而不是信号连接。
在同一主题的事件上,有时候你真正想要的是从子项向父项->祖父项->等级传递事件。这里不应该使用信号,因为它们不是用于确定建议的事件是否应该导致操作(它们可以被这样使用)。事件允许您检查当前状态,决定此小部件是否应该执行任何操作,或者将其上升到链中供其他人检查。
有一个关于信号/槽和事件之间的区别非常好的答案。这里有一个好片段:
- 你“处理”事件
- 你“被通知”信号发射
我喜欢这个引用的原因是它描述了不同的需求情况。如果您需要在小部件中处理操作,则可能需要事件。如果您想被通知发生的事情,则可能需要信号。
-vs
参数传递给可执行文件,所有信号都将显示在控制台中。 QSignalDumper 类执行信号和插槽时会触发。但是,该API未被导出,可能随时中断。以下是我如何在Qt 5.10上使用GCC挂接所有信号和插槽的方法。
// QSignalSpyCallbackSet is defined in qt5/qtbase/src/corelib/kernel/qobject_p.h
struct QSignalSpyCallbackSet
{
typedef void (*BeginCallback)(QObject *caller, int signal_or_method_index, void **argv);
typedef void (*EndCallback)(QObject *caller, int signal_or_method_index);
BeginCallback signal_begin_callback,
slot_begin_callback;
EndCallback signal_end_callback,
slot_end_callback;
};
typedef void (*register_spy_callbacks)(const QSignalSpyCallbackSet &callback_set);
static void showObject(QObject *caller, int signal_index, const QString &msg)
{
const QMetaObject *metaObject = caller->metaObject();
QMetaMethod member = metaObject->method(signal_index);
qDebug() << msg << metaObject->className() << qPrintable(member.name());
}
static void onSignalBegin(QObject *caller, int signal_index, void **argv)
{
showObject(caller, signal_index, "onSignalBegin");
}
static void onSlotBegin(QObject *caller, int signal_index, void **argv)
{
showObject(caller, signal_index, "onSlotBegin");
}
int main(int argc, char *argv[])
{
static QSignalSpyCallbackSet set = { onSignalBegin, onSlotBegin, 0, 0 };
QLibrary qtcore("libQt5Core");
register_spy_callbacks reg = (register_spy_callbacks)qtcore.resolve("_Z32qt_register_signal_spy_callbacksRK21QSignalSpyCallbackSet");
if (reg) {
reg(set);
}
...
}
我认为Qt应该公开该API,因为我们可以将其用于除了调试之外的许多其他方面,例如监视槽中花费的时间、获取统计数据等。
QObject :: connect()
的文档中: