簡體   English   中英

將 qDebug 重定向到 QTextEdit

[英]redirect qDebug to QTextEdit

我想使用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&)}'

如果我在全局中定義處理函數,就可以了。

我無法弄清楚這兩種行為之間的區別。

我真的很喜歡這種調試能力。 在我從事的最后幾個項目中,我已經完成了幾次。 以下是相關的代碼片段。

在 mainwindow.h 中,在MainWindow類中,在public

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 線程上運行的函數)創建一個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());

希望有幫助。

非靜態類方法和全局函數具有不同的簽名。 您不能將非靜態方法用作函數。

除了 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 中對此進行了測試。 如果有任何警告,請告訴我。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM