实时从QProcess获取响应 我在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(); } void QPConsole::command(QString cmd){ QProcess*process=新的QProcess(); 连接(进程,&QProcess::readyReadStandardOutput,[=](){print(进程->readAllStandardOutput());}); 连接(进程,&QProcess::readyReadStandardError,[=](){print(进程->readAllStandardError());}); connect(进程,QOverload::of(&QProcess::finished),[=](int-exitCode,QProcess::ExitStatus-ExitStatus){prepareCommandLine();return;}); 进程->设置程序(“/bin/bash”); 进程->开始(); 进程->写入(cmd.toStdString().c_str()); //进程->写入(“\n\r”); 进程->closeWriteChannel(); }
接下来的问题是: 若我不关闭写入通道(进程->closeWriteChannel),那个么我就会陷入无限循环。如果我真的关闭了它,那么我就记不起状态(有点像创建新会话),例如,如果我执行“pwd”,我会得到结果,但是如果我执行下一个“cd..”然后执行“pwd”,结果与“pwd”的第一个输出相同 所以,我的问题是,是否有可能通过QProcess实现某种实时输出+记住以前的状态(如在real terminal中),或者我必须以其他方式完成。在Python中,我用管道处理子进程,但不知道C++的等值是什么。实时从QProcess获取响应 我在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(); } void QPConsole::command(QString cmd){ QProcess*process=新的QProcess(); 连接(进程,&QProcess::readyReadStandardOutput,[=](){print(进程->readAllStandardOutput());}); 连接(进程,&QProcess::readyReadStandardError,[=](){print(进程->readAllStandardError());}); connect(进程,QOverload::of(&QProcess::finished),[=](int-exitCode,QProcess::ExitStatus-ExitStatus){prepareCommandLine();return;}); 进程->设置程序(“/bin/bash”); 进程->开始(); 进程->写入(cmd.toStdString().c_str()); //进程->写入(“\n\r”); 进程->closeWriteChannel(); },c++,qt,c++11,qt5,C++,Qt,C++11,Qt5,接下来的问题是: 若我不关闭写入通道(进程->closeWriteChannel),那个么我就会陷入无限循环。如果我真的关闭了它,那么我就记不起状态(有点像创建新会话),例如,如果我执行“pwd”,我会得到结果,但是如果我执行下一个“cd..”然后执行“pwd”,结果与“pwd”的第一个输出相同 所以,我的问题是,是否有可能通过QProcess实现某种实时输出+记住以前的状态(如在real terminal中),或者我必须以其他方式完成。在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"
#包括
#包括
#包括
类Bash:公共QObject
{
Q_对象
公众:
显式Bash(QObject*parent=nullptr):QObject(parent)
{
}
~Bash()
{
closePrivate();
}
信号:
无效readyRead(QString);
公众时段:
布尔打开(整数超时=-1)
{
if(m_bash_进程)
返回false;
m_timeout=超时;
返回openPrivate();
}
无效关闭()
{
closePrivate();
}
布尔写入(常量QString&cmd)
{
返回writePrivate(cmd);
}
void SIGINT()
{
SIGINTPrivate();
}
私人:
//功能
bool openPrivate()
{
if(m_bash_进程)
返回false;
m_bash_进程=新的QProcess();
m_bash_进程->设置程序(“/bin/bash”);
//在标准输出通道中合并标准输出和标准输出
m_bash_进程->设置进程通道模式(QProcess::MergedChannel);
连接(m_bash_进程,&QProcess::readyRead,this,&bash::readyReadPrivate);
连接(m_bash_进程、QOverload::of(&QProcess::finished)、this和&bash::closePrivate);
m_bash_进程->开始();
bool started=m_bash_进程->waitForStarted(m_超时);
如果(!已启动)
m_bash_进程->deleteLater();
返回开始;
}
void closePrivate()
{
if(!m_bash_进程)
返回;
m_bash_进程->closeWriteChannel();
m_bash_进程->waitForFinished(m_超时);
m_bash_进程->终止();
m_bash_进程->deleteLater();
}
void readyReadPrivate()
{
if(!m_bash_进程)
返回;
而(m_bash_进程->字节可用()>0)
{
QString str=QLatin1String(m_bash_进程->readAll());
发射readyRead(str);
}
}
bool writePrivate(常量QString&cmd)
{
if(!m_bash_进程)
返回false;
if(runningPrivate())
返回false;
m_bash_进程->写入(cmd.toLatin1());
m_bash_进程->写入(“\n”);
返回m_bash_进程->WaitForBytesWrited(m_超时);
}
void SIGINTPrivate()
{
if(!m_bash_进程)
返回;
QProcess::StartDetailed(“pkill”,QStringList()addWidget(&m_cmd_edit);
布局->添加小部件(&m_sigint_btn);
m_message_board.setReadOnly(真);
m_cmd_edit.setEnabled(false);
m_sigint_btn.setText(“发送sigint(CTRL+C)”);
连接(&m_cmd_edit,&QLineEdit::returnPressed,this,&MainWindow::writeToBash);
连接(&m_sigint_btn,&QPushButton::clicked,this,&main窗口::sigint);
setCentralWidget(中央窗口小部件);
调整大小(640480);
QTimer::singleShot(0、this和main窗口::startBash);
}
~main window()
{
m_bash.close();//不是必需的,由析构函数调用
}
专用插槽:
void startBash()
{
//打开并给每个操作最多1秒的时间来完成,使用-1表示无限
如果(m_bash.open(1000))
{
m_cmd_edit.setEnabled(真);
m_cmd_edit.setFocus();
}
其他的
{
QMessageBox::critical(这是“错误”,“无法打开bash”);
}
}
void writeToBash()
{
QString cmd=m_cmd_edit.text();
m_cmd_edit.clear();
if(!m_bash.write(cmd))
{
QMessageBox::critical(这是“错误”,“无法写入bash”);
}
}
void readyRead(常量QString和str)
{
m_消息板。附加纯文本(str);
}
void SIGINT()
{
m_bash.SIGINT();
}
私人:
巴什穆巴什;
QPlainTextEdit m_留言板;
QLineEdit m_cmd_edit;
QPushButton m_sigint_btn;
};
int main(int argc,char*argv[])
{
质量保证申请a(argc、argv);
主窗口w;
w、 show();
返回a.exec();
}
#包括“main.moc”
我曾经为发布了一个示例。我不确定它是否正是您想要的。为了简单起见,我将(控制台)输入和输出的小部件分开。不过,它可能会为您想要的东西提供一些灵感