The Essential Noisy Debug Hook for Qt
If you’re using Qt, you might find that it can often be rather quiet about important and common programming errors. For instance: by default, it considers the inability to connect a signal and a slot—due perhaps to a typographic error—to be a warning worth only quietly pushing into your debug output window. It’s easy to miss, especially if you (or libraries you call) have a lot of monitoring information turned on!
I’m the sort who immediately bumps up every warning level in the compiler to turn them into errors. In a similar vein, I’ve found it useful to throw the following code into the main.cpp of any Qt GUI app I am writing. (Thanks to commenter kkoehne for feedback!)
#ifdef QT_DEBUG #include <QMessageBox> #include <QThread> #include <iostream> // By default, fairly big problems like QObject::connect not working due to not being able // to find a signal or slot goes to the debug output. There can be a lot of spew which // makes that easy to miss. While perhaps the release build would want to try and // keep going, it helps debugging to get told this ASAP. // // Would be nice to chain to the default Qt platform error handler // However, this is not feasible as there is no "default error handler" function // The default error handling is merely what runs in qt_message_output // http://qt.gitorious.org/qt/qt/blobs/4.5/src/corelib/global/qglobal.cpp#line2004 // void noisyFailureMsgHandler(QtMsgType type, const char * msgAsCstring) { QString msg (msgAsCstring); std::cerr << msgAsCstring; std::cerr.flush(); // Why on earth didn't Qt want to make failed signal/slot connections qWarning? if ((type == QtDebugMsg) && msg.contains("::connect")) { type = QtWarningMsg; } // this is another one that doesn't make sense as just a debug message. pretty serious // sign of a problem // http://www.developer.nokia.com/Community/Wiki/QPainter::begin:Paint_device_returned_engine_%3D%3D_0_(Known_Issue) if ((type == QtDebugMsg) && msg.contains("QPainter::begin") && msg.contains("Paint device returned engine")) { type = QtWarningMsg; } // This qWarning about "Cowardly refusing to send clipboard message to hung application..." // is something that can easily happen if you are debugging and the application is paused. // As it is so common, not worth popping up a dialog. if ((type == QtWarningMsg) && QString(msg).contains("QClipboard::event") && QString(msg).contains("Cowardly refusing")) { type = QtDebugMsg; } // only the GUI thread should display message boxes. If you are // writing a multithreaded application and the error happens on // a non-GUI thread, you'll have to queue the message to the GUI QCoreApplication * instance = QCoreApplication::instance(); const bool isGuiThread = instance && (QThread::currentThread() == instance->thread()); if (isGuiThread) { QMessageBox messageBox; switch (type) { case QtDebugMsg: return; case QtWarningMsg: messageBox.setIcon(QMessageBox::Warning); messageBox.setInformativeText(msg); messageBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); break; case QtCriticalMsg: messageBox.setIcon(QMessageBox::Critical); messageBox.setInformativeText(msg); messageBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); break; case QtFatalMsg: messageBox.setIcon(QMessageBox::Critical); messageBox.setInformativeText(msg); messageBox.setStandardButtons(QMessageBox::Cancel); break; } int ret = messageBox.exec(); if (ret == QMessageBox::Cancel) abort(); } else { if (type != QtDebugMsg) abort(); // be NOISY unless overridden! } } #endif
Then in the main() function, after the QApplication is initialized…I’ll say:
#ifdef QT_DEBUG // Because our "noisy" message handler uses the GUI subsystem for message // boxes, we can't install it until after the QApplication is constructed. But it // is good to be the very next thing to run, to start catching warnings ASAP. { QtMsgHandler oldMsgHandler (qInstallMsgHandler(noisyFailureMsgHandler)); Q_UNUSED(oldMsgHandler); // squash "didn't use" compiler warning } #endif
By re-prioritizing the default error levels to something more reasonable and being “noisier” when a serious problem is happening during debugging, it has been a huge time saver. Try it and let me know what you think!

October 7th, 2012 at 7:50 am
How about just getting the Connection error fixed upstream (Qt 5)?
Anyhow, to make your code bullet proof you should probably check whether the message handler is actually called from the GUI thread before trying to pop up the message box.
November 14th, 2012 at 11:03 pm
@kkoehne Indeed, thanks! Oddly enough I’d done this in my Hoist library, so I was actually using an abstraction other than
QMessageBoxwhich handled that case. I just forgot to mention it in the initial post!I’ve updated with an alternative that will abort on any non-debug-spew information in a worker thread, so you know what’s going on! Seems better than sweeping it under the rug, but that’s how I feel about compiler warnings too…
November 15th, 2012 at 8:36 pm
A better stackoverflow post to link to about warnings is probably this one: http://stackoverflow.com/questions/5088460/flags-to-enable-thorough-and-verbose-g-warnings/9862800#9862800
Of course, I may be biased because that is my post, but I used the page you linked as a starting point. I then went through the gcc documentation, removed warnings that were implied by other warnings and added anything that was missing. I then removed a few “bad warnings” and documented why I did so.
November 17th, 2012 at 4:56 pm
@DavidStone: Done!