簡體   English   中英

在 Qt 應用程序中捕獲標准輸出

[英]Capture stdout in a Qt Application

我正在嘗試捕獲我的 Qt 應用程序的 output 但沒有成功。 (我正在調用一個輸出到控制台的外部庫,我想在我的 UI 中顯示它。它不是 QProcess,它是我自己進程中的一個 calss 實例)。

問題:寫入 std::cout 時我的 lambda 插槽永遠不會被調用。

這是我的代碼提煉成一個小型可測試應用程序。

這是我最近的嘗試,到目前為止,我得到了“最遠”的意義,即 std::cout output 已成功重定向到 QFile。 但是我不明白的是,為什么沒有觸發連接到該文件的 QTextStream?

#include <QCoreApplication>
#include <QFile>
#include <QTextStream>
#include <iostream>
#include <QTimer>
int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
    
    QFile file("output.txt");
    file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate);
    
    // Redirect stdout to the QFile
    std::freopen(file.fileName().toStdString().c_str(), "w", stdout);
    QTextStream stream(&file);
    std::string output; //to spy on in debugger
    //this lambda never gets called!?
    QObject::connect(&file, &QFile::readyRead, [&stream,&output] {
        // Read from the QTextStream whenever new data is available
        output += stream.readLine().toStdString();
        qApp->quit();
    });

    //This succefully writes to the QFile on disk
    QTimer::singleShot(100, [] {
        std::cout << "This will be written to output.txt" << std::endl<<std::flush;
    });
    
    
    app.exec();
    
    // Close the stream
    std::fclose(stdout);
    file.close();
}

下面列出了我以前的嘗試,但仍未得到答復,因此,如果您知道如何解決任何一種方法,我將非常感激!

請注意,在代碼末尾,我直接輸出到 std::cout 和 QTextStream。 所有這些輸出都可以在控制台上看到,包括 output 到stream - 這意味着 QTextStream object 已使用標准輸出正確初始化。

知道為什么 lambda 插槽沒有被調用嗎? (我知道由於輸出到標准輸出而在 lambda 中會發生遞歸。但這只是一個測試代碼,沒問題 - 問題是 lambda 根本沒有被調用)

#include <QCoreApplication>
#include <iostream>
#include <QTextStream>
#include <QTimer>

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
    
    QTextStream stream(stdout);

    QObject::connect(stream.device(), &QIODevice::bytesWritten, [&stream](qint64 bytes) {
        // This lambda function is called when new data is available to be read
        std::cout<<"in lambda"<<std::endl;
     });
    
    QTimer::singleShot(100, [&stream]{
        std::cout << "Hello, world!" << std::endl<<std::flush;
        std::cout << "This is some output." << std::endl<<std::flush;
        stream<< "Stream output\n";
        stream.flush();
    });

    return app.exec();

}

經過更多思考,我想到嘗試使用 QSocketNotifier 監聽stdout 使用這種方法,通知程序槽會被觸發,但是,有兩件事:

  1. 通知器插槽在 QTimer 插槽之前被調用 - 就像在無限循環中一樣重復。
  2. 我從 stream 中什么也得不到,這讓我很困惑——當stdout被寫入時我會收到通知(即使沒有任何東西寫入它,但是)並且在嘗試讀取該數據時我什么也得不到嗎? (事實上我什么也沒得到並不奇怪,因為我還沒有寫任何東西到stdout它更多的是它一直被觸發的事實)

任何人都知道如何解釋這個?

這是代碼:

#include <QCoreApplication>
#include <iostream>
#include <QTextStream>
#include <QTimer>
#include <QSocketNotifier>

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
    
    QTextStream stream(stdout);

    int stdoutFd = fileno(stdout);

    std::string output; //allows me to spy the content in the debuger

    QSocketNotifier notifier(stdoutFd, QSocketNotifier::Write );
    QObject::connect(&notifier, &QSocketNotifier::activated, [&stream, &output] {
        auto s = stream.readAll(); 
        output += s.toStdString();
    });

   
    QTimer::singleShot(100, [&stream]{
        std::cout << "This is some output." << std::endl<<std::flush;
        stream << "Stream output\n";
    });
    return app.exec();
}

提前謝謝了!

我已經設法實現了我想要的,不是很優雅,但它確實有效。
我將我的解決方案放在這里供其他可能也遇到此問題的人使用。
一方面,我喜歡這個解決方案,因為它基本上是純 C++,不需要 Qt。
另一方面,它需要輪詢,這非常“笨拙”。
因此,我讓我的 OP 保持開放狀態,希望能提供更優雅的解決方案,我很好奇為什么我的 Qt 解決方案不起作用。

此解決方案使用std::stringstreamstd::streambuf 我在這里放一個簡單的例子main() ,然后你可以根據你擁有的任何應用程序調整它,因為它非常簡單。
https://onlinegdb.com/AixVsxUyy

#include <sstream>
#include <iostream>
int main(int argc, char *argv[]) {

    //Redirect stdout to streambuf - this "grabs" the stdout
    std::stringstream buffer;
    std::streambuf *streamBuff = std::cout.rdbuf(buffer.rdbuf());

    std::cout << "this is redirected to streambuf" << std::endl;
   
    //Read our buffer
    std::string text = buffer.str();

    // Release stdout back to original buffer
    std::cout.rdbuf(streamBuff);

   
    std::cout << "Grabbed text:" << text << std::endl;
    std::exit(0);

}

由於這是同步的,我求助於輪詢buffer.str() 如果有人知道當 streambuff 有新數據時如何通知我,請分享。

注意:輪詢時,如果在調用之間沒有新數據寫入標准輸出,則將再次讀取相同的字符串,因為緩沖區仍然完好無損。 如果您想在讀取緩沖區時清除緩沖區,請調用:

buffer.clear();
buffer.str("");

我希望這可以幫助別人!

暫無
暫無

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

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