gpt4 book ai didi

c++ - 实时获取 QProcess 的响应

转载 作者:行者123 更新时间:2023-11-30 04:52:27 27 4
gpt4 key购买 nike

我是 C++ 编程的新手,所以我需要逻辑方面的帮助(代码会很棒)。我想让 QTextEdit 像小部件一样作为终端工作。我正在尝试使用 QProcess 来实现这一目标:

void QPConsole::command(QString cmd){
QProcess* process = new QProcess();
connect(process, &QProcess::readyReadStandardOutput, [=](){ print(process->readAllStandardOutput()); });
connect(process, &QProcess::readyReadStandardError, [=](){ print(process->readAllStandardError()); });
connect(process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),[=](int exitCode, QProcess::ExitStatus exitStatus){ prepareCommandLine(); return; });

process->setProgram("/bin/bash");
process->start();
process->write(cmd.toStdString().c_str());
// process->write("\n\r");

process->closeWriteChannel();
}

接下来的问题是:如果我不关闭写入 channel (process->closeWriteChannel),那么我就会陷入无限循环。如果我确实关闭它,那么我就记不起状态(有点像创建新 session ),例如,如果我执行“pwd”我会得到结果,但是如果我执行下一个“cd ..”然后“pwd”,结果与“pwd”的第一个输出

所以,我的问题是,是否可以使用 QProcess 实现某种实时输出 + 记住之前的状态(如在真实终端中),或者我必须以其他方式实现。在 python 中,我使用管道调用子进程,但我不知道 C++ 的等价物是什么。

代码示例会很棒。我有 QTextEdit 部分(正在发送 QString 参数来运行),我需要参与与控制台的交互。

最佳答案

想法很简单:保留一个 QProcess 实例并向其写入命令,然后是 \n!

这是一个完整的例子,有一个QMainWindow 和一个Bash 类,把它放在main.cpp 中:

#include <QtCore>
#include <QtGui>
#include <QtWidgets>

class Bash : public QObject
{
Q_OBJECT
public:
explicit Bash(QObject *parent = nullptr) : QObject(parent)
{

}

~Bash()
{
closePrivate();
}

signals:
void readyRead(QString);

public slots:
bool open(int timeout = -1)
{
if (m_bash_process)
return false;

m_timeout = timeout;

return openPrivate();
}

void close()
{
closePrivate();
}

bool write(const QString &cmd)
{
return writePrivate(cmd);
}

void SIGINT()
{
SIGINTPrivate();
}

private:
//Functions
bool openPrivate()
{
if (m_bash_process)
return false;

m_bash_process = new QProcess();

m_bash_process->setProgram("/bin/bash");

//Merge stdout and stderr in stdout channel
m_bash_process->setProcessChannelMode(QProcess::MergedChannels);

connect(m_bash_process, &QProcess::readyRead, this, &Bash::readyReadPrivate);
connect(m_bash_process, QOverload<int>::of(&QProcess::finished), this, &Bash::closePrivate);

m_bash_process->start();

bool started = m_bash_process->waitForStarted(m_timeout);

if (!started)
m_bash_process->deleteLater();

return started;
}

void closePrivate()
{
if (!m_bash_process)
return;

m_bash_process->closeWriteChannel();
m_bash_process->waitForFinished(m_timeout);
m_bash_process->terminate();
m_bash_process->deleteLater();
}

void readyReadPrivate()
{
if (!m_bash_process)
return;

while (m_bash_process->bytesAvailable() > 0)
{
QString str = QLatin1String(m_bash_process->readAll());
emit readyRead(str);
}
}

bool writePrivate(const QString &cmd)
{
if (!m_bash_process)
return false;

if (runningPrivate())
return false;

m_bash_process->write(cmd.toLatin1());
m_bash_process->write("\n");

return m_bash_process->waitForBytesWritten(m_timeout);
}

void SIGINTPrivate()
{
if (!m_bash_process)
return;

QProcess::startDetached("pkill", QStringList() << "-SIGINT" << "-P" << QString::number(m_bash_process->processId()));
}

bool runningPrivate()
{
if (!m_bash_process)
return false;

QProcess process;
process.setProgram("pgrep");
process.setArguments(QStringList() << "-P" << QString::number(m_bash_process->processId()));
process.setProcessChannelMode(QProcess::MergedChannels);

process.start();

process.waitForFinished(m_timeout);

QString pids = QLatin1String(process.readAll());

QStringList pid_list = pids.split(QRegularExpression("\n"), QString::SkipEmptyParts);

return (pid_list.size() > 0);
}

//Variables
QPointer<QProcess> m_bash_process;
int m_timeout;
};

class MainWindow : public QMainWindow
{
Q_OBJECT

public:
MainWindow(QWidget *parent = nullptr) : QMainWindow(parent)
{
connect(&m_bash, &Bash::readyRead, this, &MainWindow::readyRead);

QWidget *central_widget = new QWidget(this);

QVBoxLayout *layout = new QVBoxLayout(central_widget);
layout->addWidget(&m_message_board);
layout->addWidget(&m_cmd_edit);
layout->addWidget(&m_sigint_btn);

m_message_board.setReadOnly(true);

m_cmd_edit.setEnabled(false);

m_sigint_btn.setText("Send SIGINT(CTRL+C)");

connect(&m_cmd_edit, &QLineEdit::returnPressed, this, &MainWindow::writeToBash);

connect(&m_sigint_btn, &QPushButton::clicked, this, &MainWindow::SIGINT);

setCentralWidget(central_widget);

resize(640, 480);

QTimer::singleShot(0, this, &MainWindow::startBash);
}

~MainWindow()
{
m_bash.close(); //Not mandatory, called by destructor
}

private slots:
void startBash()
{
//Open and give to each operation a maximum of 1 second to complete, use -1 to unlimited
if (m_bash.open(1000))
{
m_cmd_edit.setEnabled(true);
m_cmd_edit.setFocus();
}
else
{
QMessageBox::critical(this, "Error", "Failed to open bash");
}
}

void writeToBash()
{
QString cmd = m_cmd_edit.text();

m_cmd_edit.clear();

if (!m_bash.write(cmd))
{
QMessageBox::critical(this, "Error", "Failed to write to bash");
}
}

void readyRead(const QString &str)
{
m_message_board.appendPlainText(str);
}

void SIGINT()
{
m_bash.SIGINT();
}

private:
Bash m_bash;
QPlainTextEdit m_message_board;
QLineEdit m_cmd_edit;
QPushButton m_sigint_btn;
};

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();

return a.exec();
}

#include "main.moc"

关于c++ - 实时获取 QProcess 的响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54368585/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com