最近在搞一个数据库备份和恢复的工具,想在自己的程序里显示过程,即将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 !");

}

界面:

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐