QT中QProcess 的使用举例(完整代码)

************************************************************
author: hjjdebug
date: 2024年 02月 03日 星期六 12:16:01 CST
description: QT中QProcess 的使用(完整代码)
目的: 用最简单的程序了解QT对象QProcess的使用
************************************************************
要求, 用QT编写程序,实现对test_print 程序的调用
test_print 是如下向控制台输出1-99个数字然后就退出的程序. 这个程序就自己实现一下吧。

或者看后面的附录:
 ./test_print 
1
2
3
4
5
6
7
8
9

qt 对进程的调用可以使用QProcess 类来实现
主程序还是一样的简单,我们创造一个QObject 子对象就可以了
$ cat main.cpp
#include <QApplication>
#include <unistd.h> //for gettid()
#include "myclass.h"

QApplication* gApp; 
int main(int argc, char *argv[])
{
    gApp = new QApplication(argc, argv);
    printf("main threadid:%d\n",gettid());
    MyClass myObject;
    return gApp->exec();
}

下面是 MyClass 的头文件
$ cat myclass.h
#ifndef _MYCLASS_H  
#define _MYCLASS_H  
#include <QObject>  
#include <QProcess>

class MyClass : public QObject 
{  
    Q_OBJECT  
public:  
    MyClass();  
    ~MyClass();  

private slots:  
    void openProcess();
    void slotRead();
    void slotReadError();
    void slotStateChanged(QProcess::ProcessState state);

private:  
    QProcess *m_process;  
};  

#endif // _MYCLASS_H 

这个头文件继承自QObject, 并包含Q_OBJECT以实现消息收发
它包含一个QProcess 对象m_process
能够读取进程对象的stdout --> slotRead()
和进程对象的stderr --> slotReadError()
能够感知进程对象的状态改变 -->slotStateChanged
下面看CMyClass 的具体实现

$ cat myclass.cpp
#include <QDebug>
#include "myclass.h"  
#include <unistd.h>
void printTime()
{
    const time_t now=time(NULL);
    struct tm *tm = localtime(&now);
    printf("%02d:%02d:%02d ",tm->tm_hour,tm->tm_min,tm->tm_sec);
}
void printTime2()
{
    printTime();
    printf("\n"); //加回车才能看到向屏幕输出时间
}
MyClass::MyClass()  
{  
    openProcess(); //构造函数中打开进程
}  

MyClass::~MyClass()  
{  
    // 析构中清理环境
    disconnect(m_process,SIGNAL(readyReadStandardOutput()),this,SLOT(slotRead()));
    disconnect(m_process,SIGNAL(readyReadStandardError()),this,SLOT(slotReadError()));
    m_process->close();
    delete m_process;
    printf("MyClass destructure!\n");
}  

void MyClass::openProcess()  
{   //创建一个进程, 启动它并打印其时间,状态,建立信号连接
    m_process = new QProcess(this);  
    printf("open process begin,threadid:%d\n",gettid());
    printTime();
    printf("state0:%d\n",m_process->state()); // 此时状态是0, NotRunning
    m_process->start("test_print");
    printTime();
    printf("state1:%d\n",m_process->state()); //此时状态是1, Starting,
    printf("processid:%d,sub_processid:%lld\n",getpid(),m_process->pid());
#define _WANT_READ_INFO
#ifdef _WANT_READ_INFO
    connect(m_process,SIGNAL(readyReadStandardOutput()),this,SLOT(slotRead()));
    connect(m_process,SIGNAL(readyReadStandardError()),this,SLOT(slotReadError()));
#else
    //,关闭通道读写,免得引起内存不断增长.
    m_process->closeReadChannel(QProcess::StandardOutput);    
    m_process->closeReadChannel(QProcess::StandardError);
    m_process->closeWriteChannel();
#endif
    connect(m_process,SIGNAL(stateChanged(QProcess::ProcessState)),this,SLOT(slotStateChanged(QProcess::ProcessState)));
    printTime();
    printf("state2:%d\n",m_process->state());  //此时状态是1, Starting,
    printf("open process end!\n");
}
void MyClass::slotStateChanged(QProcess::ProcessState state)
{
    printTime2();
    qDebug()<<"ProcessState changed: processid:"<<getpid();
    switch(state)
    {
    case QProcess::NotRunning:  // 0
        qDebug()<<"Not Running";
        break;
    case QProcess::Starting:  //1
        qDebug()<<"Starting";
        break;
    case QProcess::Running:  //2
        qDebug()<<"Running";
        break;
    default:
        qDebug()<<"otherState";
        break;
    }
}

void MyClass::slotRead()
{
    
    QByteArray array=m_process->readAllStandardOutput();
    qDebug()<<"receive:"<<array;
    printf("slotRead, state:%d,pid:%d,threadid:%d\n",m_process->state(),getpid(),gettid()); //此时状态是2, Running
    
}

void MyClass::slotReadError()
{
    QByteArray array=m_process->readAllStandardError();
    qDebug()<<"err:"<<array;
    printf("slotReadError, state:%d\n",m_process->state()); //此时状态是2, Running
}

下面是执行结果: 可以看到,读写子进程信息都是在主进程中进行的.
$ ./test_qprocess 
main threadid:10465
open process begin,threadid:10465
12:13:31 state0:0
12:13:31 state1:1
processid:10465,sub_processid:10471
12:13:31 state2:1
open process end!
receive: "1\n"
slotRead, state:1,pid:10465,threadid:10465
12:13:31 
ProcessState changed:
Running
receive: "2\n"
slotRead, state:2,pid:10465,threadid:10465
receive: "3\n"
slotRead, state:2,pid:10465,threadid:10465
receive: "4\n"
slotRead, state:2,pid:10465,threadid:10465
receive: "5\n"
slotRead, state:2,pid:10465,threadid:10465
receive: "6\n"
slotRead, state:2,pid:10465,threadid:10465
receive: "7\n"
slotRead, state:2,pid:10465,threadid:10465
receive: "8\n"
slotRead, state:2,pid:10465,threadid:10465
receive: "9\n"
slotRead, state:2,pid:10465,threadid:10465
12:13:40 
ProcessState changed:
Not Running
 

补充: 再剧透一下主线程是如何调用到槽函数的. 当然它是通过gApp->exec,具体的过程我调试了一下是这样的,通过20层调用才到达了槽函数. 当然具体实现是Qt完成的,我们了解一下就可以了。

0  in MyClass::slotRead() of myclass.cpp:77
1  in MyClass::qt_static_metacall(QObject*, QMetaObject::Call, int, void**) of moc_myclass.cpp:86
2  in void doActivate<false>(QObject*, int, void**)
3  in QProcess::readyReadStandardOutput(QProcess::QPrivateSignal)
4  in QProcessPrivate::tryReadFromChannel(QProcessPrivate::Channel*)
5  in QProcess::qt_static_metacall(QObject*, QMetaObject::Call, int, void**)
6  in void doActivate<false>(QObject*, int, void**)
7  in QSocketNotifier::activated(int, QSocketNotifier::QPrivateSignal)
8  in QSocketNotifier::event(QEvent*)
9  in QApplicationPrivate::notify_helper(QObject*, QEvent*)
10 in QApplication::notify(QObject*, QEvent*)
11 in QCoreApplication::notifyInternal2(QObject*, QEvent*)
12 in socketNotifierSourceDispatch(_GSource*, int (*)(void*), void*)
13 in g_main_context_dispatch
14 in 
15 in g_main_context_iteration
16 in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>)
17 in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>)
18 in QCoreApplication::exec()
19 in main(int, char**) of main.cpp:11

附录: test_print 代码

$ cat main.cpp 
#include <stdio.h>
#include <unistd.h>

int main()
{
	for(int i=1;i<10;i++)
	{
		printf("%d\n",i);
		fflush(stdout);
		sleep(1);
	}
	return 0;
}

我发现要想获取子进程的打印输出, 有3个关键点

1. 利用QProcess 调用start()时候可以像所给例子一样调用,千万不要加NULL参数.否则父进程收不到信号

2.子进程必需要加fflush 刷新才能实时输出。

3. 子进程必需要加一次sleep 函数调用,哪怕只sleep(0.1)也行,否则父进程就收不到信号,

   不知道是不是QT的bug, 我用的是QT5.14.0, 反正坑都绕过了,

demo程序只是我复杂程序的一个浓缩.

  • 19
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值