【问题标题】:Qt GUI app: warning if QObject::connect() failed?Qt GUI 应用程序:如果 QObject::connect() 失败则发出警告?
【发布时间】:2009-09-28 11:21:39
【问题描述】:

我最近将我的 Qt 项目从 Linux 迁移到了 Vista,现在我正在盲目地调试信号。

在 Linux 上,如果 QObject::connect() 在调试构建中失败,我会在 stderr 上收到警告消息。在 Windows 上,GUI 应用程序没有控制台输出,只有一个 OutputDebugString 调用。

我已经安装了DebugView,它很好地捕获了我自己的 qDebug() 输出,但仍然没有对失败的信号发出警告。

一种可能的解决方案是使用 QtCreator 的信号自动完成功能,但我喜欢 Eclipse,并且两者都使用是 PITA。关于如何在运行时获取信号/插槽信息的任何想法?

编辑:我刚刚意识到 connect() 返回 bool,它解决了当前的问题,尽管它可能很丑陋。但是,这并不能解决QMetaObject::connectSlotsByName() 失败的情况,并且这个会自动与小部件一起运行。

【问题讨论】:

    标签: c++ qt signals-slots


    【解决方案1】:

    调用静态函数QErrorMessage::qtHandler()。

    根据文档,这“使用 qInstallMsgHandler() 安装消息处理程序并创建显示 qDebug()、qWarning() 和 qFatal() 消息的 QErrorMessage”。

    或者,使用 qInstallMsgHandler() 安装消息处理程序。

    另一种选择(在 qt-interest 帖子中描述)是这样的:

    #ifdef _DEBUG
    #define connect( connectStmt ) Q_ASSERT( connect( connectStmt ) ) 
    #endif
    

    ...对于它的价值,这里有一些我编译的信号和插槽调试建议:http://samdutton.wordpress.com/2008/10/03/debugging-signals-and-slots-in-qt/

    【讨论】:

      【解决方案2】:

      我喜欢的解决方案是设置

      QT_FATAL_WARNINGS=1
      

      调试时在程序的环境中。这会使程序崩溃,给你一个很好的回溯,特别是如果你在调试器中运行代码。如果您不想崩溃,请参阅上面的答案。

      【讨论】:

      • 遗憾的是,MinGW 没有回溯:只有“应用程序具有……以一种不寻常的方式”(可能这对 MSVC 更有效)。
      • 我更喜欢这个作为解决方案(在 VS 2012 中显示了调用堆栈),因为重新定义 CONNECT 没有成功,尤其是在绑定问题在不同的 dll 中时
      【解决方案3】:

      我的方法是用qInstallMsgHandler 重新绑定Qt 日志引擎,并自己记录到文件和控制台。

      这样,我知道所有错误/警告消息都被记录下来,即使在程序停止执行后我也可以分析它们。

      P.S:QtCreator 截获这些消息并将它们显示在应用程序输出窗格中。

      【讨论】:

      • 谢谢,这当然有帮助,尽管我开始相信 Qt DLL 是完全沉默的。我已经可以看到 qDebug() 的输出,所以理论上它应该也出现在 DebugView 中。
      【解决方案4】:

      如果您使用 Visual Studio,您可以将控制台添加到任何 QT 应用程序。
      转到项目属性,在 Linker->Settings 下将“SubSystem”更改为“Console”

      现在重新编译您的代码,您将在激活应用程序时出现控制台。如果你想摆脱它,只需将 SubSystem 再次更改为“Windows”

      我不确定这是否可能与 QtCreator 相关。

      另一种选择是使用像AttachConsole() 这样的本机win32 调用来手动创建控制台并将其附加到stdout 和stderr。有关更多详细信息,请参阅here

      【讨论】:

        【解决方案5】:

        大多数时候我只是不时想要一些关注: 只需在“int dummyPutBreakpointHere=23;”行上放一个断点

        in main.C:
        
        static QtMessageHandler defaultMessageHandler;
        void myRazorsharpMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg) 
        {
            if ( type > QtDebugMsg ) {
                int dummyPutBreakpointHere= 23;
            }
            defaultMessageHandler(type, context, msg);
        }
        ...
        later in main(): defaultMessageHandler= qInstallMessageHandler(0);
        

        【讨论】:

          【解决方案6】:

          您可以使用官方的 Qt IDE:QtCreator。它包含一个输出控制台,您可以在其中看到任何信号问题。在调试和发布运行中输出信号错误。

          【讨论】:

            【解决方案7】:

            您可以很容易地重定向 stdout/stderr:创建一个派生自 std::basic_streambuf 并重载 xsputn() 和 overflow() 的类,然后使用例如 std::cerr.rdbuf( instanceOfYourRedirectClass ) 将所有 stderr 输出重定向到您提供的回调函数。

            这是我使用的简化版本;根据您的需要,您可能需要添加额外的逻辑来处理行尾字符等的处理。

            template< class Elem = char, class Tr = std::char_traits<Elem> >
            class Redirector : public std::basic_streambuf<Elem, Tr>
            {
              typedef void (*pfncb) ( const Elem*, std::streamsize );
            
            public:
              Redirector( std::ostream& a_Stream, pfncb a_Cb ) :
                m_Stream( a_Stream ),
                m_pCbFunc( a_Cb ),
              {
                  //redirect stream
                m_pBuf = m_Stream.rdbuf( this );
              };
            
              ~Redirector()
              {
                  //restore stream
                m_Stream.rdbuf( m_pBuf );
              }
            
              std::streamsize xsputn( const Elem* _Ptr, std::streamsize _Count )
              {
                m_pCbFunc( _Ptr, _Count );
                return _Count;
              }
            
              typename Tr::int_type overflow( typename Tr::int_type v )
              {
                Elem ch = Tr::to_char_type( v );
                m_pCbFunc( &ch, 1 );
                return Tr::not_eof( v );
              }
            
             protected:
              std::basic_ostream<Elem, Tr>& m_Stream;
              std::streambuf*               m_pBuf;
              pfncb                         m_pCbFunc;
            };
            

            用法:

              void outcallback( const char *ptr, std::streamsize count )
              {
                if( *ptr != gc_cEOL )  //ignore eof
                  OutputDebugString( ptr );
              }
            
              Redirector<> redirect( std::cout, mycallback );
            

            【讨论】:

            • 这是否也使用 printf() 重定向 stdout,或者只是 std::cout?我怀疑后者,这在这种情况下不太有用。
            猜你喜欢
            • 2014-03-08
            • 1970-01-01
            • 2020-09-29
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-09-09
            • 1970-01-01
            • 2022-07-22
            相关资源
            最近更新 更多