2009-09-28 6 views
10

Recentemente ho migrato il mio progetto Qt da Linux a Vista, e ora sto eseguendo il debug dei segnali ciecamente.App GUI Qt: avviso se QObject :: connect() non è riuscito?

Su Linux, se QObject :: connect() non riesce in una build di debug, viene visualizzato un messaggio di avviso su stderr. Su Windows, non è disponibile l'output della console per le applicazioni GUI, solo una chiamata OutputDebugString.

Ho già installato DebugView e cattura correttamente il mio output qDebug(), ma ancora nessun avviso sui segnali non riusciti.

Una possibile soluzione sarebbe utilizzare il completamento automatico di QtCreator per i segnali, ma mi piace Eclipse e l'utilizzo di entrambi è un PITA. Qualche idea su come ottenere informazioni sul segnale/slot in fase di runtime?

Modifica: ho appena realizzato connect() restituisce bool, che risolve il problema immediato, per quanto brutto possa essere. Tuttavia, questo non risolve i casi in cui QMetaObject::connectSlotsByName() non riesce e questo viene eseguito automaticamente con i widget.

risposta

10

Chiamare la funzione statica QErrorMessage :: qtHandler().

Come per la documentazione, questo 'installa un gestore di messaggi utilizzando qInstallMsgHandler() e crea un messaggio QErrorMessage che visualizza i messaggi qDebug(), qWarning() e qFatal()'.

In alternativa, installare un gestore di messaggi con qInstallMsgHandler().

Un'altra alternativa (descritta in un post-qt interessi) è qualcosa di simile:

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

... e per quello che vale, qui ci sono alcuni segnali e slot debug suggerimenti che ho compilato: http://samdutton.wordpress.com/2008/10/03/debugging-signals-and-slots-in-qt/

+1

Questo è veramente utile! – Pepe

1

Se si utilizza Visual Studio è possibile aggiungere una console a qualsiasi applicazione QT.
Vai alle proprietà del progetto, sotto Linker-> Impostazioni cambia il "Sottosistema" per dire "Console"

Ora ricompila il tuo codice e vedrai apparire la console quando si attiva l'applicazione. Se vuoi liberartene, cambia nuovamente il sottosistema in "Windows"

Non sono sicuro se questo è possibile con QtCreator.

Un'altra opzione consiste nell'utilizzare chiamate native win32 come AttachConsole() per creare manualmente la console e collegarla a stdout e stderr. vedi here per ulteriori dettagli su questo.

0

è possibile reindirizzare stdout/stderr abbastanza facilmente: creare una classe derivata da std :: basic_streambuf e overloads xsputn() e overflow(), quindi utilizzare ad esempio std :: cerr.rdbuf (instanceOfYourRedirectClass) per reindirizzare tutto stderr ouptut a una funzione di callback fornita dall'utente.

Ecco una versione semplificata di ciò che utilizzo; a seconda delle esigenze potrebbe essere necessario aggiungere la logica in più per giocherellare con la gestione dei caratteri di fine linea, ecc

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

Usage:

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

    Redirector<> redirect(std::cout, mycallback); 
+0

Reindirizza lo stdout anche con printf() o solo std :: cout? Sospetto quest'ultimo, il che lo rende meno utile in questo caso. – Macke

2

Il mio approccio è quello di associare nuovamente il motore di registrazione Qt con qInstallMsgHandler e faccio il mio logging sia per file che per console.

In questo modo, so che tutti i messaggi di errore/avviso sono registrati e posso analizzarli anche dopo che il programma ha interrotto l'esecuzione.

P.S: QtCreator intercetta tali messaggi e li visualizza nel riquadro di output dell'applicazione.

+0

Grazie, questo sicuramente aiuta, anche se sto iniziando a credere che la DLL Qt sia semplicemente silenziosa. Posso già vedere l'output di qDebug(), quindi, in teoria, dovrebbe essere mostrato anche in DebugView. –

1

È possibile utilizzare l'ID Qt ufficiale: QtCreator. Contiene una console di output in cui vedrai qualsiasi problema con i segnali. L'errore del segnale viene emesso durante il debug AND release run.

4

La soluzione che mi piace per questo è di impostare

QT_FATAL_WARNINGS=1 

nell'ambiente del programma durante il debug. Questo fa sì che il programma si arresti in modo anomalo, dandoti un buon backtrace, specialmente se esegui il codice in un debugger. Se non vuoi il crash, vedi la risposta sopra.

+0

Nessun backtrace, purtroppo, con MinGW: solo "Un'applicazione ha ... in un modo insolito" (Probabilmente funziona meglio con MSVC). – mlvljr

+0

Preferisco questo come soluzione (in VS 2012 viene mostrato il callstack) poiché la ridefinizione di CONNECT non ha funzionato, specialmente se il problema del binding si trova in una dll diversa – Samuel

0

La maggior parte delle volte mi interessa solo qualche ora: Basta inserire un punto di interruzione sulla linea "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);