qt执行终端命令_Qt模拟Linux终端Terminal与系统交互(QProcess)
最近在搞一个数据库备份和恢复的工具,想在自己的程序里显示过程,即将gnome-ternimal的打印信息输出到我的程序里。因为要和ternimal交互,自然就想到用QProcess启用终端然后互相开始对话交互。但其中遇到的一些问题网上查了很久才最后解决,由于网上的答案并不是现成的,需要自己理解后才能有思路解决,所以在这里把我的思路过程分享出来,避免后人再踩坑。认识真实的gnome-ternimal
最近在搞一个数据库备份和恢复的工具,想在自己的程序里显示过程,即将gnome-ternimal的打印信息输出到我的程序里。因为要和ternimal交互,自然就想到用QProcess启用终端然后互相开始对话交互。但其中遇到的一些问题网上查了很久才最后解决,由于网上的答案并不是现成的,需要自己理解后才能有思路解决,所以在这里把我的思路过程分享出来,避免后人再踩坑。
认识真实的gnome-ternimal
看这篇文章的绝大多数都想直接调用Linux的命令,但不想用QProcess启动ternimal时看到终端的界面。其实。。。。你的思路错了!!!!
gnome-terminal这个终端也是一个程序,就和你自己即将要开发的Qt程序一样,有GUI界面。但其实你输入命令后,这个terminal会调用Linux系统函数。例如,你输入ls命令,terminal程序接受后会执行system(char* c)函数。system(char* c)函数属于标准库中的函数,用来和系统内核(windows/Linux)进行交互。
市面上有很多终端,有gnome-terminal(CentOS自带)、xFace等,就像通讯软件有QQ、微信等,他们不是Windows/Linux系统级别的组件,而是方便人们和系统交互而开发出来的可视化程序。
所以你要开发一个终端?这是件很复杂的事。
首先,一般的终端都会自动识别输入内容是程序还是退出等。例如输入“mysql -uroot -p123456”就是启动mysql;输入“ls”就是显示当前列表下的文件信息,而不是启用一个叫“ls”的程序。这是如何实现的呢?能想到的是你得有个配置文件吧,就像~/.bashrc这样的;你还得有相应的算法来进行信息区分吧。所以想做一个类似终端的程序,看起来简单,实则复杂。因为它(terminal)不是系统组件,只是一个软件。启动软件有的会有GUI界面,如QQ、迅雷、Qt;有的没有界面,如"mysql"。无论有没有界面,只要启动一个软件,就是启动了一个进程。然后在这个进程运行的过程中,我们会和这个进程进行交互,而QProcess就是很方便的进程交互类。
mysql备份并显示结果
这里以我最近的需求来举例,我想做个一健备份mysql的工具。想在备份的过程中显示进度变化之类的信息。
先看最终效果:
我是启动了mysqlpump这个MySQL自带备份工具,然后左面的QTextdit显示标准输出,右面的QTextEdit显示标准错误输出。文尾附有源代码,这里捡重要的说。QProcess启动很简单
cmd->start("mysqlpump",QStringList() << "-uroot" << "-p123456");进程向外传递出来的信息很好捕获
/* 将QProcess的输出打印到界面 */
connect(cmd,&QProcess::readyReadStandardOutput,this,&MainWindow::on_readyReadStandardOutput);
connect(cmd,&QProcess::readyReadStandardError,this,&MainWindow::on_readyReadStandardError);
QProcess会自动监听启动的进程,当进程有什么话要告诉外界,就会发出对应的信号,然后我们读取即可。向进程传递信息也不难
cmd->waitForStarted();
cmd->write(ui->lineEdit->text().toLocal8Bit() + '\n');
这里需要注意的就是QString转化成toLocal8Bit()后,还要加个'\n'回车符,顺序不要搞错了。因为之前我是QString里加入回车符,然后再toLocal8Bit(),是错误的。回车符还是在char*层面加比较好,不要在QString层面加,容易出错。
关于标准输出想说的
我跟你们讲,正常在terminal输入“mysqlpump -uroot -p123456 > /filePath.sql”后会在你指定的路径生成SQL逻辑备份文件。而我们上文的例子是把文件内容直接输出到左面的QTextEdit了,所以要想输出成SQL文件,需要把mysqlpump发出的这些信息流进行设置,也就是QProcess中的 void setStandardInputFile(const QString &fileName)函数。
说完了,有问题留言讨论。
代码片段:
#include "mainwindow.h"#include
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
#include
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
/* 启动按钮 */
void on_pbStart_clicked();
/* 执行按钮 */
void on_pbCommand_clicked();
/* 标准输出 */
void on_readyReadStandardOutput();
/* 标准错误输出 */
void on_readyReadStandardError();
/* QProcess程序启动输出展示 */
void on_started();
/* QPRocess程序写入展示 */
void on_byteWritten();
private:
Ui::MainWindow *ui;
QProcess *cmd;
};
#endif // MAINWINDOW_H
MainWindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
cmd = new QProcess(this);
/* 将QProcess的输出打印到界面 */
connect(cmd,&QProcess::readyReadStandardOutput,this,&MainWindow::on_readyReadStandardOutput);
connect(cmd,&QProcess::readyReadStandardError,this,&MainWindow::on_readyReadStandardError);
/* 将QProcess的 "启动/写入/结束" 打印到界面 */
connect(cmd,&QProcess::started,this,&MainWindow::on_started);
connect(cmd,&QProcess::bytesWritten,this,&MainWindow::on_byteWritten);
connect(cmd, QOverload::of(&QProcess::finished),[=](int exitCode, QProcess::ExitStatus exitStatus){ Q_UNUSED(exitCode);Q_UNUSED(exitStatus);ui->textEdit2->append("cmd->Finished !"); });
}
MainWindow::~MainWindow()
{
delete ui;
if (cmd->state() == QProcess::Running)
{
cmd->terminate();
cmd->waitForFinished();
}
}
void MainWindow::on_pbCommand_clicked()
{
cmd->waitForStarted();
cmd->write(ui->lineEdit->text().toLocal8Bit() + '\n');
}
void MainWindow::on_pbStart_clicked()
{
QStringList arguments;
arguments<< "-uroot" << "-p123456";
cmd->setProgram("mysqlpump");
cmd->setArguments(arguments);
cmd->start();
}
void MainWindow::on_readyReadStandardOutput()
{
QString outStr = QString::fromLocal8Bit(cmd->readAllStandardOutput());
ui->textEdit1->append(outStr);
}
void MainWindow::on_readyReadStandardError()
{
QString outStr = QString::fromLocal8Bit(cmd->readAllStandardError());
ui->textEdit2->append(outStr);
}
void MainWindow::on_started()
{
ui->textEdit2->append("cmd->Started !");
}
void MainWindow::on_byteWritten()
{
ui->textEdit2->append("cmd->Written !");
}
界面:
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)