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

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

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

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

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

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


person György Andrasek    schedule 28.09.2009    source источник


Ответы (7)


Вызовите статическую функцию 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/

person Sam Dutton    schedule 28.09.2009

Решение, которое мне нравится для этого, - установить

QT_FATAL_WARNINGS=1

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

person Esben Mose Hansen    schedule 28.09.2009
comment
К сожалению, с MinGW нет обратной трассировки: только приложение имеет... необычным образом (возможно, это лучше работает с MSVC). - person mlvljr; 24.05.2012
comment
Я предпочитаю это как решение (в VS 2012 показан стек вызовов), поскольку переопределение CONNECT не сработало, особенно если проблема с привязкой находится в другой dll. - person Samuel; 19.02.2014

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

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

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

person rpg    schedule 28.09.2009
comment
Спасибо, это, безусловно, помогает, хотя я начинаю верить, что Qt DLL просто молчит. Я уже вижу вывод qDebug(), поэтому теоретически он должен был появиться и в DebugView. - person György Andrasek; 28.09.2009

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

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

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

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

person shoosh    schedule 28.09.2009

Большую часть времени мне просто нужно время от времени обращать внимание: просто поставьте точку останова на строку "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);
person user65947    schedule 20.11.2014

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

person Patrice Bernassola    schedule 28.09.2009

вы можете легко перенаправить 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 );
person stijn    schedule 28.09.2009
comment
Это также перенаправляет стандартный вывод с помощью printf() или просто std::cout? Я бы подозревал последнее, что делает его менее полезным в этом случае. - person Macke; 30.09.2009