将 qDebug 重定向到 QTextEdit

5

我希望使用qInstallMessageHandler(handler)qDebug重定向到QTextEdit

我在一个类中定义了一个处理函数:

void Spider::redirect(QtMsgType type, const QMessageLogContext& context, const QString& msg)
{
    console->append(msg);
}

在类(Spider)的构造函数中调用qInstallMessageHandler(redirect)

但是,当我编译这个程序时,我得到了一个错误:

无法将“Spider :: redirect”从类型“void(Spider ::)(QtMsgType,const QMessageLogContext&,const QString&)”转换为类型“QtMessageHandler {aka void(*)(QtMsgType,const QMessageLogContext&,const QString& )}“

如果我在全局定义处理程序函数,则可以。

我想不出这两种行为之间的区别。

3个回答

12

我非常喜欢拥有这种调试能力,我在最近几个项目中已经用了几次。以下是相关的代码片段。

MainWindow类下的public中的mainwindow.h文件中:

static QTextEdit * s_textEdit;

在mainwindow.cpp中,不在任何函数之内

QTextEdit * MainWindow::s_textEdit = 0;

在 MainWindow 构造函数中

s_textEdit = new QTextEdit;
// be sure to add the text edit into the GUI somewhere, 
// like in a layout or on a tab widget, or in a dock widget

在 main.cpp 文件中,main() 函数之前。

void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    if(MainWindow::s_textEdit == 0)
    {
        QByteArray localMsg = msg.toLocal8Bit();
        switch (type) {
        case QtDebugMsg:
            fprintf(stderr, "Debug: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
            break;
        case QtWarningMsg:
            fprintf(stderr, "Warning: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
            break;
        case QtCriticalMsg:
            fprintf(stderr, "Critical: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
            break;
        case QtFatalMsg:
            fprintf(stderr, "Fatal: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
            abort();
        }
    }
    else
    {
        switch (type) {
        case QtDebugMsg:
        case QtWarningMsg:
        case QtCriticalMsg:
            // redundant check, could be removed, or the 
            // upper if statement could be removed
            if(MainWindow::s_textEdit != 0)
                MainWindow::s_textEdit->append(msg);
            break;
        case QtFatalMsg:
            abort();
        }
    }
}

在main.cpp的main()函数内,在初始化QApplication实例之前。

qInstallMessageHandler(myMessageOutput);

注意:这对于任何单线程应用程序都非常有效。一旦您在GUI线程之外使用qDebug(),应用程序将崩溃。然后,您需要从任何非运行在GUI线程上的函数(任何不运行在GUI线程上的东西)创建一个QueuedConnection,以连接到您的MainWindow::s_textEdit实例,如下所示:

QObject::connect(otherThread, SIGNAL(debug(QString)),
                 s_textEdit, SLOT(append(QString)), Qt::QueuedConnection);

如果您最终使用 QDockWidget 并利用 QMenu,那么您可以做一些额外的很棒的事情。最终结果是一个非常用户友好、易于管理的控制台窗口。

QMenu * menu;
menu = this->menuBar()->addMenu("About");
menu->setObjectName(menu->title());

// later on...

QDockWidget *dock;
dock = new QDockWidget("Console", this);
dock->setObjectName(dock->windowTitle());
dock->setWidget(s_textEdit);
s_textEdit->setReadOnly(true);
this->addDockWidget(Qt::RightDockWidgetArea, dock);
this->findChild<QMenu*>("About")->addAction(dock->toggleViewAction());
希望这有所帮助。

1
非静态类方法和全局函数具有不同的签名。您不能将非静态方法用作函数。

因为这个回答没有回答“如何将 qDebug 重定向到 QTextEdit”的问题,所以我要给它一个负评。这个回答解释了提问者遇到错误的原因,但没有解决提问者的问题。 - Cuadue

0

对phyatts答案的补充。 为了使事情线程安全,您还可以创建以下内容。这将解决该应用程序的任何线程可能想要发送其调试流的问题。

namespace Mainwindow_ {
class Emitter : public QObject 
{
    Q_OBJECT
    public:
    Emitter(){};
    ~Emitter(){};
    signals:    
    void append_log(QString msg);
};
}

s_textEdit 类似,创建上述类的静态对象。 在头文件中:

static QTextEdit * s_text_edit;
static Mainwindow_::Emitter s_emitter;

在 .cpp 文件中:

QTextEdit * MainWindow::s_text_edit = 0;
Mainwindow_::Emitter MainWindow::s_emitter;

在它的构造函数中:

s_text_edit = new QTextEdit("Starting .. ");
connect(&s_emitter, SIGNAL(append_log(QString)), s_text_edit, SLOT(append(QString)));

你可以在 myMessageOutput 中使用以下代码调用 append_log

emit MainWindow::s_emitter.append_log(msg);

请原谅命名差异。我在Qt 5.7和5.9版本中进行了测试。如果有任何注意事项,请告诉我。


我发布这篇文章是因为 QObject::connect(otherThread, SIGNAL(debug(QString)), s_textEdit, SLOT(append(QString)), Qt::QueuedConnection); 这种解决方法对我不起作用。 - student

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接