调试Qt信号和插槽有哪些最佳实践?

时间:2012-08-13 16:38:20

标签: qt debugging signals-slots connection

调试信号和插槽可能很难,因为调试器在发出时不会跳转到信号的插槽。有什么调试Qt信号和插槽的最佳实践?

特别是

  1. 如何确保连接成功设置?
  2. 我应该何时使用信号和插槽,何时应该避开它们?
  3. 您的体验中最有效的调试技术是什么?

4 个答案:

答案 0 :(得分:5)

有一篇博客文章写了一段时间,名为20 ways to debug Qt signals and slots 它解决了我认为问题的第一和第三。

对于#2,我认为使用或不使用信号/插槽确实存在硬性和快速的原因,因为它们是GUI框架的一个非常核心的概念。信号是将一个组件的知识与另一个组件分离的完美方式,允许您设计可重用的小部件,只需声明状态更改或通知。通过发出主线程可以看到的信号,这也是从非GUI线程循环传递GUI更改的一种非常好的方法。

有时候您真正想要的不是信号/插槽就是使用事件,例如当父窗口小部件应该成为许多子窗口小部件的事件过滤器时。孩子们仍然不需要知道父母,父母得到的是更直接的事件,而不是信号连接。

在相同的事件主题上,有时你真正想要的是从孩子那里冒出一个事件 - >父母 - >祖父母 - >信号在这里没有意义,因为它们并不意味着确定所提出的事件是否应该导致一个动作(它们可以以这种方式显然使用)。事件允许您检查当前状态,确定此窗口小部件是否应该执行任何操作,或以其他方式将它们冒出来以供其他人检查。

The Difference Between Signals/Slots and Events有一个非常棒的答案。这是一个很好的片段:

  
      
  • 你“处理”事件
  •   
  • 您“收到”信号发射“的通知
  •   

我喜欢这句话的是它描述了不同的需求案例。如果您需要在窗口小部件中处理操作,那么您很可能想要一个事件。如果你想收到有关事情的通知,那么你可能想要一个信号。

答案 1 :(得分:1)

  

如何确保连接成功设置?

您将在应用程序的控制台输出中看到每个失败连接的警告。

  

我应该何时使用信号和插槽,何时应该避开它们?

在我看来,只要你想在课堂设计中保持关注点分离,就可以使用它们。您的班级可以发出一个信号,可能会或可能不会被您班级完全不知道的其他班级(或班级)回答。这可以减少你的耦合。

  

根据您的经验,最有效的调试技术是什么?

我真的无法添加任何超出此博客文章中所说的内容。 20 ways to debug Qt signals and slots

答案 2 :(得分:0)

关于#1,我只是添加我在上面或引用的博客文章中没有看到的另一条信息。

来自QObject::connect()的文档:

  

创建给定类型的连接,从发送方对象中的信号到接收方对象中的方法。如果连接成功,则返回true;否则返回false。

我更喜欢断言连接的返回值以确保连接成功,特别是因为并非所有Qt程序都有控制台输出。这也会导致更容易维护的代码,因为它会捕获日后对信号或插槽所做的更改,并强制进行更改的程序员也更新连接。

答案 3 :(得分:0)

除了上述内容外,还有其他技巧。

如果将QTest用于单元测试,则可以将-vs参数传递给可执行文件,所有信号都将显示在控制台中。

我研究了QTest的工作原理,它注册了使用QSignalDumper类执行信号和插槽时触发的回调。但是,此API不会导出,并且可能随时中断。这就是我使用GCC在Qt 5.10上钩住Linux上所有信号和插槽的方法。

// 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,因为我们可以将其用于调试之外的许多事情,例如监视在插槽中花费的时间,获取统计信息等。