Приложение Qt GUI: предупреждение, если QObject:: connect() не удалось?

Недавно я перенес свой проект Qt с Linux на Vista, и теперь я отслежу сигналы вслепую.

В Linux, если QObject:: connect() терпит неудачу в сборке отладки, я получаю предупреждение о stderr. В Windows нет консольного вывода для графических приложений, только вызов OutputDebugString.

Я уже установил DebugView, и он отлично поймал мой собственный qDebug(), но все еще не предупреждал о неисправных сигналах.

Одним из возможных решений было бы использовать автозаполнение QtCreator для сигналов, но мне нравится Eclipse, и использование обоих - это PITA. Любые идеи о том, как получить информацию о сигнале/слоте во время выполнения?

Изменить: я только что понял, что connect() возвращает bool, что решает ближайшую проблему, уродливую, как это может быть. Однако это не решает случаи, когда QMetaObject:: connectSlotsByName() терпит неудачу, и этот файл запускается автоматически с помощью виджетов.

Ответ 1

Вызвать статическую функцию QErrorMessage:: qtHandler().

В соответствии с документацией это "устанавливает обработчик сообщений с помощью qInstallMsgHandler() и создает QErrorMessage, который отображает сообщения qDebug(), qWarning() и qFatal().

В качестве альтернативы установите обработчик сообщений с помощью 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

в среде программы при отладке. Это приводит к сбою программы, что дает вам хорошую обратную трассировку, особенно если вы запускаете код в отладчике. Если вы не хотите сбой, см. Ответ выше.

Ответ 3

Мой подход заключается в том, чтобы перестроить механизм ведения журнала Qt с помощью qInstallMsgHandler и выполнить мой собственный журнал как для файлов, так и для консоли.

Таким образом, я знаю, что все сообщения об ошибке/предупреждении записываются, и я могу анализировать их даже после прекращения выполнения программы.

P.S: QtCreator перехватывает эти сообщения и отображает их в панели вывода приложения.

Ответ 4

Если вы используете Visual Studio, вы можете добавить консоль в любое приложение QT.
Перейдите к свойствам проекта, в Linker- > Settings измените "SubSystem", чтобы сказать "Консоль"

Теперь перекомпилируйте свой код, и консоль появится при активации приложения. Если вы хотите избавиться от него, просто замените SubSystem на "Windows"

Я не уверен, возможно ли это с QtCreator.

Другой вариант - использовать собственные вызовы win32, такие как AttachConsole(), чтобы вручную создать консоль и прикрепить ее к stdout и stderr. см. здесь для получения более подробной информации об этом.

Ответ 5

Вы можете использовать официальный Qt IDE: QtCreator. Он содержит выходную консоль, где вы увидите какие-либо проблемы с сигналами. Сигнальная ошибка выводится в прогоне отладки AND.

Ответ 6

вы можете легко перенаправить stdout/stderr: создать класс, который происходит из std:: basic_streambuf и перегружает xsputn() и overflow(), а затем использовать, например, std:: cerr.rdbuf(instanceOfYourRedirectClass), чтобы перенаправить все stderr ouptut на функцию обратного вызова, которую вы предоставляете.

Вот упрощенная версия того, что я использую; в зависимости от ваших потребностей вам, возможно, придется добавить дополнительную логику, чтобы играть с обработкой символов конца строки и т.д.

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 );

Ответ 7

В большинстве случаев мне нужно только некоторое время: Просто поставьте точку останова на строке "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);