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!