场景
Win10 QT5.9
使用QProcess调用cmd,利用qt自带的槽函数把原本打印到cmd的信息,打印到界面
界面
保存按钮 ui.pushButton:点击运行cmd,所以需要一个槽函数Slot_Test()
connect(ui.pushButton, SIGNAL(clicked()), this, SLOT(Slot_Test()));
运行cmd是借助qt自带的QProcess (在头文件中定义 成员变量 m_Process)
QProcess 自带的信号:
- 读就绪-readyRead()
- 标准读就绪-readyReadStandardOutput()
- 产生错误-errorOccurred()
- 进程完成-finished()
编写对应的槽函数即可输出到 界面 ui.textBrowser->append(msg);
参考文献:https://blog.csdn.net/Hxj_CSDN/article/details/89066330?spm=1001.2014.3001.5506
代码
logs.h
#pragma once
#include <QDialog>
#include "ui_logs.h"
#include <QProcess>
class logs:public QDialog
{
Q_OBJECT
public:
logs(QWidget *parent = Q_NULLPTR);
~logs();
private slots:
void Slot_errorProcess();
void Slot_finishedProcess(int exitCode);
void Slot_value_changed(int nValue);
void Slot_Test();
private:
Ui::logs ui;
QProcess m_Process;
logs.cpp
首先是槽函数
logs::logs(QWidget *parent)
: QDialog(parent)
{
ui.setupUi(this);
init();
connect(ui.pushButton, SIGNAL(clicked()), this, SLOT(Slot_Test()));//cmd
connect(&m_Process, SIGNAL(readyRead()), this, SLOT(Slot_readData()));//读就绪
connect(&m_Process, SIGNAL(readyReadStandardOutput()), this, SLOT(Slot_readData()));//标准读就绪
connect(&m_Process, SIGNAL(errorOccurred()), this, SLOT(Slot_errorProcess()));//产生错误
connect(&m_Process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(Slot_finishedProcess(int, QProcess::ExitStatus)));//进程完成
}
启动cmd 使用start
void logs::Slot_Test()
{
QString strBasePath = QApplication::applicationDirPath() + "\\" + POSITIVESAMPLE_PATH;
QString pythonCommand = QString("python main_test.py --pretrained_path %1 ").arg(m_strPretrainedModelPath);
QString strBat = QString("positiveSampleTool.bat");
QFile file;
file.setFileName(strBasePath + strBat);
if (file.open(QIODevice::WriteOnly))
{
file.write("@echo off\r\n");
file.write("cd ..\ \r\n");
file.write("cd bin/train/PaddleX_Train \r\n");
file.write("call activate\r\n");
file.write(pythonCommand.toLocal8Bit());
file.write("\r\n");
file.write("exit");
file.close();
}
else
{
return;
}
m_Process.start(strBasePath+"\\positiveSample\\positiveSampleTool.bat");
}
打印到界面
void logs::Slot_readData()
{
QByteArray qbt = m_Process.readAllStandardOutput();
QString msg = QString::fromLocal8Bit(qbt);
ui.textBrowser->append(msg);
}
void logs::Slot_errorProcess()
{
QString msg = m_Process.errorString();
ui.textBrowser->append("<font color=\"#FF0000\">" + msg + + "</font>");
}
void logs::Slot_finishedProcess(int exitCode)
{
ui.textBrowser->append("finished");
ui.textBrowser->append("end");
InitDatas();
}
坑
我的QProcess 写为成员变量 m_Process;
在类的构造函数中 编写信号槽
logs::logs(QWidget *parent)
: QDialog(parent)
{
ui.setupUi(this);
init();
connect(ui.pushButton, SIGNAL(clicked()), this, SLOT(Slot_Test()));//cmd
connect(&m_Process, SIGNAL(readyRead()), this, SLOT(Slot_readData()));//读就绪
connect(&m_Process, SIGNAL(readyReadStandardOutput()), this, SLOT(Slot_readData()));//标准读就绪
connect(&m_Process, SIGNAL(errorOccurred()), this, SLOT(Slot_errorProcess()));//产生错误
connect(&m_Process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(Slot_finishedProcess(int, QProcess::ExitStatus)));//进程完成
}
然后就坑了,信号槽只有第一次好使,再启动进程就不行了
于是添加以下代码:
if (m_Process.atEnd())
{
runTestFile();
disconnect(&m_Process, SIGNAL(readyRead()), this, SLOT(Slot_readData()));//读就绪
disconnect(&m_Process, SIGNAL(readyReadStandardOutput()), this, SLOT(Slot_readData()));//标准读就绪
disconnect(&m_Process, SIGNAL(errorOccurred()), this, SLOT(Slot_errorProcess()));//产生错误
disconnect(&m_Process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(Slot_finishedProcess(int, QProcess::ExitStatus)));//进程完成
connect(&m_Process, SIGNAL(readyRead()), this, SLOT(Slot_readData()));//读就绪
connect(&m_Process, SIGNAL(readyReadStandardOutput()), this, SLOT(Slot_readData()));//标准读就绪
connect(&m_Process, SIGNAL(errorOccurred()), this, SLOT(Slot_errorProcess()));//产生错误
connect(&m_Process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(Slot_finishedProcess(int, QProcess::ExitStatus)));//进程完成
}
如果是在类的构造函数中,定义QProcess 的信号槽。那么QProcess 第二次启动时,信号槽就失效了。
因为QProcess 的主体变了。‘所以每次有新的进程需要启动,都需要手动disconnect和connect一次
保存QProcess 每次都正确连上了信号槽
坑二:
disconnect(&m_Process, SIGNAL(readyReadStandardError()), this, SLOT(Slot_readErrorData()));//错误就绪
connect(&m_Process, SIGNAL(readyReadStandardError()), this, SLOT(Slot_readErrorData()));//错误就绪
void xx::Slot_readErrorData()
{
QByteArray qbt = m_Process.readAllStandardError();
QString msg = QString::fromLocal8Bit(qbt);
ui.textBrowser->append(msg);
}
如果不加readyReadStandardError 相关操作,下面的信息就收不到:
Traceback (most recent call last):
File "./semi/tools/train_ad.py", line 99, in <module>
AttributeError: module 'jcutils.base' has no attribute 'savepath'
坑三 实时显示
QT QProcess 使用及实时输出回显
网上都说 加 fflush(stdout)
但是我不管用,后来在被调用的pytho程序里
每一行print 后面后刷新一遍缓存,QProcess 就能实时显示了