Qt执行dos命令并获取控制台输出

应用场景与问题描述

问题是这样的,我写了很多命令行程序用于处理遥感影像,这种方式很方便,可以通过dos或shell脚本来实现批处理。但这也引起一个问题,当我在集成时偷懒,不想做界面,而用户又必须要求有个界面时,我不得不做一个窗口来体现我是有界面的,于是我决定直接调用我的可执行程序或者批处理脚本,但这些命令和脚本不能在终端或dos窗口里执行。这个问题简单的抽象为执行一个"ping localhost"的命令,并且把输出重定向到我的消息窗口里。

我们习惯于先看看别人有没有做过这个事,于是先百度一下,就直接看到这篇博客:点击打开链接,参照这个博客的例子,我做了如下的实验:

头文件:

#ifndef QTWINMSG_H
#define QTWINMSG_H

#include <QtWidgets/QMainWindow>
#include "ui_qtwinmsg.h"
#include "Worker.h"

class QtWinMsg : public QMainWindow
{
	Q_OBJECT

public:
	QtWinMsg(QWidget *parent = 0);
	~QtWinMsg();

public slots:
	void onTest();

private:
	Ui::QtWinMsgClass ui;
};

#endif // QTWINMSG_H

源文件:

#include "qtwinmsg.h"
#include <QMessageBox>

#include <conio.h>  
#include <stdio.h>  
#include <windows.h> 

QtWinMsg::QtWinMsg(QWidget *parent)
	: QMainWindow(parent)
{
	ui.setupUi(this);
	ui.lineEdit->setText(tr("ping localhost"));
	ui.textEdit->setLineWrapMode(QTextEdit::NoWrap);

	connect(ui.pushButton,SIGNAL(clicked()),this,SLOT(onTest()));
}

QtWinMsg::~QtWinMsg()
{
}


void QtWinMsg::onTest()
{
	QString qsCmd =  ui.lineEdit->text();
	QByteArray qbCmd = qsCmd.toLocal8Bit();
	char* pszCmd = qbCmd.data();
	LPWSTR ppCmd = new TCHAR[100];
	LPSTR p = pszCmd;
	MultiByteToWideChar(CP_ACP, 0, p, -1, ppCmd, 100);

	SECURITY_ATTRIBUTES   sa;   
	HANDLE   hRead,hWrite;   

	sa.nLength   =   sizeof(SECURITY_ATTRIBUTES);   
	sa.lpSecurityDescriptor   =   NULL;   
	sa.bInheritHandle   =   TRUE;   
	if   (!CreatePipe(&hRead,&hWrite,&sa,0))     
	{   
		return  ;   
	}     

	STARTUPINFO   si;   
	PROCESS_INFORMATION   pi;     
	si.cb   =   sizeof(STARTUPINFO);   
	GetStartupInfo(&si);     
	si.hStdError   =   hWrite;   
	si.hStdOutput   =   hWrite;   
	si.wShowWindow   =   SW_HIDE;   
	si.dwFlags   =   STARTF_USESHOWWINDOW   |   STARTF_USESTDHANDLES;   
	//关键步骤,CreateProcess函数参数意义请查阅MSDN   
	if   (!CreateProcess(NULL,   ppCmd   
		,NULL,NULL,TRUE,NULL,NULL,NULL,&si,&pi))     
	{   
		return  ;   
	}   
	CloseHandle(hWrite);   

	char   buffer[4096]   =   {0};   
	DWORD   bytesRead;     
	//ofstream outfile("log.txt");  

	while   (true)     
	{   
		if   (ReadFile(hRead,buffer,4095,&bytesRead,NULL)   ==   NULL)   
			break;   
		//buffer中就是执行的结果,可以保存到文本,也可以直接输出   
		//printf(buffer);   
		//outfile << buffer << endl;  
		//Sleep(1000);   


		QString qsMsg = QString::fromLocal8Bit(buffer);
		ui.textEdit->append(qsMsg);
		this->update();
	}  

	//outfile.close(); 
}

运行效果:


这样可以实现目标,但是在Qt程序里使用了Win32 API,这是有点别扭,另外输出的消息并不是动态的输出,而是在执行完毕后一下子刷出来,即使我们通过QThread,把处理过程放到其它线程里,然后通过异步的事件来刷新消息输出也是实现不了动态消息效果。总体来说,这种方式是不完美的。

我想Qt应该有自己的方式。通过查看Qt的帮助,很快就可以找到做这个事情的类QProcess,QProcess可以同于执行外部程序和命令,并且支持消息重定向和标准输入、输出,有了QProcess类,前面讲到的问题就可以简单的通过下面的方式来实现了:

头文件:

#ifndef TEST2_H
#define TEST2_H

#include <QWidget>
#include <QProcess>
#include "ui_Test2.h"

class Test2 : public QWidget
{
	Q_OBJECT
public:
	Test2(QWidget *parent = 0);
	~Test2();
	public slots:
		void onTest();
		void onOutput();
private:
	Ui::Test2 ui;
	QProcess  *m_Process;
};

#endif // TEST2_H

源文件:

#include "Test2.h"
#include <QTextEdit>

Test2::Test2(QWidget *parent)
	: QWidget(parent),m_Process(new QProcess)
{
	ui.setupUi(this);
	ui.lineEdit->setText(tr("ping localhost"));
	ui.textEdit->setLineWrapMode(QTextEdit::NoWrap);
	m_Process->setProcessChannelMode(QProcess::MergedChannels);
	connect(ui.pushButton,SIGNAL(clicked()),this,SLOT(onTest()));
	connect(m_Process,SIGNAL(readyReadStandardOutput()),this,SLOT(onOutput()));
}

Test2::~Test2()
{
	m_Process->terminate();
}

void Test2::onTest()
{
	QString qsCmd = ui.lineEdit->text();
	m_Process->start( qsCmd);
}

void Test2::onOutput()
{
	QByteArray qbt = m_Process->readAllStandardOutput();
	QString msg = QString::fromLocal8Bit(qbt);
	ui.textEdit->append(msg);
	ui.textEdit->update();
}

运行效果:



  • 6
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

深蓝静音

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值