在Qt中异步运行控制台输出和GUI

时间:2011-07-06 18:07:53

标签: qt user-interface console

我正在围绕控制台应用程序构建GUI。我希望能够单击按钮来运行控制台应用程序并在GUI本身内显示控制台输出。我怎么能做到这一点?我在Linux工作。

4 个答案:

答案 0 :(得分:7)

您也可以尝试QProcess。它提供了一个Qt接口来启动外部进程,读取它们的I / O并等待或不等待它们完成。

出于您的目的,听起来您希望进程异步运行,因此代码可能如下所示:

myprocessstarter.h:

#include <QObject>
#include <QProcess>
#include <QDebug>


class MyProcessStarter : public QObject
{
    Q_OBJECT
public:
    MyProcessStarter() : QObject() {};
    void StartProcess();
private slots:
    void readStandardOutput();
private:
    QProcess *myProcess;
};

main.cpp中:

#include "myprocessstarter.h"

void MyProcessStarter::StartProcess()
{
    QString program = "dir";
    QStringList arguments;
    // Add any arguments you want to be passed

    myProcess = new QProcess(this);
    connect(myProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(readStandardOutput()));
    myProcess->start(program, arguments);
}

void MyProcessStarter::readStandardOutput()
{
    QByteArray processOutput;
    processOutput = myProcess->readAllStandardOutput();

    qDebug() << "Output was " << QString(processOutput);
}

void main(int argc, char** argv)
{
    MyProcessStarter s;
    s.StartProcess();
}

答案 1 :(得分:2)

我想在我的一个应用程序中做类似的事情。我将标准流(cout)的所有输出重定向到我的控制台窗口。为了定期读出流内容,我使用了一个定时器循环。对我来说很好。

StdRedirector.cpp

#include "StdRedirector.h"

QMutex coutMutex;

void outcallback(const char* ptr, std::streamsize count, void* bufferString)
{
    string *b = (string *) bufferString;    
    string t;

    for (int i=0; i < count; i++)
    {
        if (ptr[i] == '\n')
        {
            t = t + "\n";
        } else {
            t = t + ptr[i];
        }
    }       

    coutMutex.lock();
    *b = *b + t;
    coutMutex.unlock();
}

void ConsoleWindow::updateTimer(void)
{   
    coutMutex.lock();
    if (bufferString.size() > 0)
    {
        consoleBox->insertPlainText(QString(bufferString.c_str()));
        bufferString.clear();

        QScrollBar *sb = consoleBox->verticalScrollBar();
        sb->setValue(sb->maximum());        
    }
    coutMutex.unlock();
}

ConsoleWindow::ConsoleWindow(QWidget *parent) : QWidget(parent)
{
    consoleBox = new QTextEdit(this);
    consoleBox->setReadOnly(true);

    stdRedirector = new StdRedirector<>(std::cout, outcallback, &bufferString);

    QVBoxLayout *vb = new QVBoxLayout();
    vb->addWidget(consoleBox);
    vb->setMargin(0);
    vb->setSpacing(0);  

    setLayout(vb);

    QTimer *timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(updateTimer()));
    timer->start(100);
}

ConsoleWindow::~ConsoleWindow()
{
    delete stdRedirector;
}

StdRedirector.h

#ifndef STD_REDIRECTOR
#define STD_REDIRECTOR

#include <QWidget>
#include <QTextEdit>
#include <QString>
#include <QVBoxLayout>
#include <QTimer.h>
#include <QMutex>
#include <QScrollBar>

#include <iostream>
#include <string>

using namespace std;

template<class Elem = char, class Tr = std::char_traits<Elem>>

class StdRedirector : public std::basic_streambuf<Elem, Tr>
{
    typedef void (*pfncb) ( const Elem*, std::streamsize _Count, void* pUsrData );

    public:
        StdRedirector(std::ostream& a_Stream, pfncb a_Cb, void* a_pUsrData) :
            m_Stream(a_Stream),
            m_pCbFunc(a_Cb),
            m_pUserData(a_pUsrData)
        {
            m_pBuf = m_Stream.rdbuf(this);
        }

        ~StdRedirector()
        {
            m_Stream.rdbuf(m_pBuf);
        }

        std::streamsize xsputn(const Elem* _Ptr, std::streamsize _Count)
        {
            m_pCbFunc(_Ptr, _Count, m_pUserData);
            return _Count;
        }

        typename Tr::int_type overflow(typename Tr::int_type v)
        {
            Elem ch = Tr::to_char_type(v);
            m_pCbFunc(&ch, 1, m_pUserData);
            return Tr::not_eof(v);
        }

    protected:
        std::basic_ostream<Elem, Tr>& m_Stream;
        std::streambuf* m_pBuf;
        pfncb m_pCbFunc;
        void* m_pUserData;
};

class ConsoleWindow : public QWidget
{
Q_OBJECT

    public:
        ConsoleWindow(QWidget *parent = 0);
        ~ConsoleWindow();

    public slots:
        void updateTimer(void);

    public:
        QTextEdit *consoleBox;
        StdRedirector<> *stdRedirector;
        string bufferString;
};

#endif

StdRedirector类基于此论坛帖子的代码:http://www.qtforum.org/article/24554/displaying-std-cout-in-a-text-box.html

答案 2 :(得分:0)

看看popen()功能,它可能会做你需要的。

然后你可以将FILE *传递给QTextStream并使用Qt风格。

答案 3 :(得分:0)

我建议,不要在GUI中显示stdout,而是拥有自己的控制台输出,这实际上意味着要向要发送到自己输出的用户显示的所有消息。

通过这种方式,您可以获得调试消息,这些消息仍然可以从控制台获得,具有连接的潜在错误以及可能发生的任何事情,并且在GUI应用程序中具有完全控制的控制台输出。当然这个输出也可以输出到stdout,因此它在控制台中可见,但它也允许你附加一个前缀,如WARNING LOG NOTICE NO_THIS_WENT_WRONG或任何你想要显示给用户作为你的控制台条目。