Qt之进程通信-QProcess(含源码+注释)

news2025/1/12 11:58:02

文章目录

  • 一、QProcess进程通信示例
  • 二、QProcess通信个人理解
  • 三、源码
    • MainWindowProcessSender
      • MainWindowProcessSender.h
      • MainWindowProcessSender.cpp
      • MainWindowProcessSender.ui
    • MainWindowProcessRecv
      • MainWindowProcessRecv.h
      • MainWindowProcessRecv.cpp
      • MainWindowProcessRecv.ui
  • 总结
  • 相关文章

一、QProcess进程通信示例

下方为默认程序启动通信示例
在这里插入图片描述
下方为默认程序为空,然后指定启动的应用程序通信
在这里插入图片描述

二、QProcess通信个人理解

  1. 主进程给子进程发送数据:直接通过QProcess对象的write函数写入数据(给通过start函数启动的进程,并且写入数据需要以“\n”结尾,方便子进程识别且读取数据);
  2. 主进程接收数据:直接关联QProcess的readyReadStandardError()、readyReadStandardOutput()信号可接收读取错误输出和数据输出;
  3. 子进程接收数据:本文通过QTextStream和std::string对象读取数据,且两者对象都是在线程中循环识别数据,并通过信号输出显示到主界面中;
  4. 子进程发送数据:子进程通过QFile打开stdout流通道,直接通过QFile的write函数写入数据即可(此处不需要以“\n”结尾主线程都可以读取数据)。

三、源码

MainWindowProcessSender

MainWindowProcessSender.h

#ifndef MAINWINDOWPROCESSSENDER_H
#define MAINWINDOWPROCESSSENDER_H

#include <QMainWindow>
#include <QProcess>

namespace Ui {
class MainWindowProcessSender;
}

class MainWindowProcessSender : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindowProcessSender(QWidget *parent = nullptr);
    ~MainWindowProcessSender();

private slots:
    /**
     * @brief on_btnStartProcess_clicked 启动进程信号槽
     */
    void on_btnStartProcess_clicked();

    /**
     * @brief on_readyReadStandardError 错误信息信号槽
     */
    void on_readyReadStandardError();

    /**
     * @brief on_readyReadStandardOutput 输出信息信号槽
     */
    void on_readyReadStandardOutput();

    /**
     * @brief on_btnSend_clicked 数据发送信号槽
     */
    void on_btnSend_clicked();

private:
    Ui::MainWindowProcessSender *ui;

    QProcess    m_process;  // 进程对象

    QString     m_path; // 子进程路径

};

#endif // MAINWINDOWPROCESSSENDER_H

MainWindowProcessSender.cpp

#include "MainWindowProcessSender.h"
#include "ui_MainWindowProcessSender.h"

#include <QDebug>
#include <QFileDialog>
#include <QMessageBox>

MainWindowProcessSender::MainWindowProcessSender(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindowProcessSender)
    , m_path("")
{
    ui->setupUi(this);
    // 关联数据信号
    connect(&m_process, &QProcess::readyReadStandardError, this, &MainWindowProcessSender::on_readyReadStandardError);
    connect(&m_process, &QProcess::readyReadStandardOutput, this, &MainWindowProcessSender::on_readyReadStandardOutput);
}

MainWindowProcessSender::~MainWindowProcessSender()
{
    // 写入结束指令,使子进程读取线程停止
    m_process.write(u8"%kill%\n");
    // 结束子进程
    m_process.terminate();
    // 等待子进程结束
    m_process.waitForFinished(5000);
    delete ui;
}

void MainWindowProcessSender::on_btnStartProcess_clicked()
{
    QString path;
    if(!m_path.isEmpty()) {
        QFile file(m_path);
        if(!file.exists()) {
            QMessageBox::information(this, u8"提示", u8"启动程序不存在,请自主选择程序");
            m_path = "";
            return;
        }
        path = m_path;
    }
    else {
        path = QFileDialog::getOpenFileName(this, u8"选择启动程序", u8"./", "*.exe");
    }
    m_process.start(path);
    ui->btnStartProcess->setEnabled(false);
}

void MainWindowProcessSender::on_readyReadStandardError()
{
    // 错误信息追加
    ui->plainTextEdit->appendPlainText("Error:" + m_process.readAllStandardError());
}

void MainWindowProcessSender::on_readyReadStandardOutput()
{
    // 通信数据追加
    QByteArray data = m_process.readAllStandardOutput();
    ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit(data));
}

void MainWindowProcessSender::on_btnSend_clicked()
{
    // 发送数据
    if(!m_process.isOpen()) {
        return;
    }
    // 写入数据
    m_process.write((ui->lineEdit->text()).toStdString().data());
    // 写入结束符
    m_process.write("\n");
}

MainWindowProcessSender.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindowProcessSender</class>
 <widget class="QMainWindow" name="MainWindowProcessSender">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>400</width>
    <height>300</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindowProcessSender</string>
  </property>
  <widget class="QWidget" name="centralWidget">
   <layout class="QGridLayout" name="gridLayout">
    <item row="0" column="0">
     <widget class="QLineEdit" name="lineEdit">
      <property name="text">
       <string/>
      </property>
     </widget>
    </item>
    <item row="0" column="1">
     <widget class="QPushButton" name="btnSend">
      <property name="text">
       <string>发送</string>
      </property>
     </widget>
    </item>
    <item row="0" column="2">
     <widget class="QPushButton" name="btnStartProcess">
      <property name="text">
       <string>启动通信程序</string>
      </property>
     </widget>
    </item>
    <item row="1" column="0" colspan="3">
     <widget class="QPlainTextEdit" name="plainTextEdit"/>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menuBar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>400</width>
     <height>23</height>
    </rect>
   </property>
  </widget>
  <widget class="QToolBar" name="mainToolBar">
   <attribute name="toolBarArea">
    <enum>TopToolBarArea</enum>
   </attribute>
   <attribute name="toolBarBreak">
    <bool>false</bool>
   </attribute>
  </widget>
  <widget class="QStatusBar" name="statusBar"/>
 </widget>
 <layoutdefault spacing="6" margin="11"/>
 <resources/>
 <connections/>
</ui>

MainWindowProcessRecv

MainWindowProcessRecv.h

#ifndef MAINWINDOWPROCESSRECV_H
#define MAINWINDOWPROCESSRECV_H

#include <QFile>
#include <QMainWindow>
#include <QSocketNotifier>

namespace Ui {
class MainWindowProcessRecv;
}

class MainWindowProcessRecv : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindowProcessRecv(QWidget *parent = nullptr);
    ~MainWindowProcessRecv();

    void appendText(QString str);

signals:
    /**
     * @brief sigDataRead 数据输入信号
     * @param str 输入数据
     */
    void sigDataRead(QString str);

private slots:
    /**
     * @brief on_btnSend_clicked数据发送信号槽
     */
    void on_btnSend_clicked();

    /**
     * @brief on_btnStartRecv_clicked 数据接收信号槽
     */
    void on_btnStartRecv_clicked();

    /**
     * @brief on_loopReadInData 数据接收处理信号槽
     */
    void on_loopReadInData();

private:
    Ui::MainWindowProcessRecv   *ui;

    bool                        m_readFlag;         // 数据接收标记
};

#endif // MAINWINDOWPROCESSRECV_H

MainWindowProcessRecv.cpp

#include "MainWindowProcessRecv.h"
#include "ui_MainWindowProcessRecv.h"
#include <QFile>
#include <cstring>
#include <iostream>
#include <QtConcurrent/QtConcurrent>
#include <QTextStream>
#include <QMessageBox>

MainWindowProcessRecv::MainWindowProcessRecv(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindowProcessRecv)
    , m_readFlag(false) // 读取标记默认false
{
    ui->setupUi(this);
    // 连接输入流数据信号槽
    connect(this, &MainWindowProcessRecv::sigDataRead, this, [=](QString str){
        ui->editDebug->appendPlainText(str);
    });
}

MainWindowProcessRecv::~MainWindowProcessRecv()
{
    // 读取标志主动设置为false
    m_readFlag = false;
    delete ui;
}

void MainWindowProcessRecv::appendText(QString str)
{
    ui->editDebug->appendPlainText(str);
}

void MainWindowProcessRecv::on_btnSend_clicked()
{
    // 打开输出流通道
    QFile file;
    if(!file.open(stdout, QIODevice::ReadWrite)) {
        qDebug() << u8"打开失败";
        return;
    }

    // 写入数据
    file.write(ui->lineEdit->text().toLocal8Bit());
    // 关闭输出流通道
    file.close();
}

void MainWindowProcessRecv::on_loopReadInData()
{
    while(m_readFlag) {
#if 0
        // 通过文本流读取数据(因为stdin本身输入的就是流数据)
        QTextStream stream(stdin);
        stream.setCodec("utf8");    // 指定编码类型防止乱码
        QString str;
        stream.readLineInto(&str);  // 读取数据(读取一行数据,其中以\n"或"\r\n为结束标记)、
        // 数据接收信号
        emit sigDataRead(str);
#else
        // 创建数据接收数据
        std::string str;
        // 读取数据
        std::getline(std::cin, str);
        // 数据接收信号
        emit sigDataRead(QString::fromStdString(str));
#endif
        // 读取标记赋值(通过主进程发送数据识别关闭)
        m_readFlag = 0 != str.compare(u8"%kill%");
    }
}

void MainWindowProcessRecv::on_btnStartRecv_clicked()
{
    if(m_readFlag) {
        m_readFlag = false;
        ui->btnStartRecv->setText(u8"开始接收");
    }
    else {
        m_readFlag = true;
        ui->btnStartRecv->setText(u8"停止接收");
        // 以线程启动数据读取
        QtConcurrent::run(this, &MainWindowProcessRecv::on_loopReadInData);
    }
}

MainWindowProcessRecv.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindowProcessRecv</class>
 <widget class="QMainWindow" name="MainWindowProcessRecv">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>400</width>
    <height>300</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindowProcessRecv</string>
  </property>
  <widget class="QWidget" name="centralWidget">
   <layout class="QGridLayout" name="gridLayout">
    <item row="0" column="0">
     <widget class="QLineEdit" name="lineEdit">
      <property name="text">
       <string/>
      </property>
     </widget>
    </item>
    <item row="0" column="1">
     <widget class="QPushButton" name="btnSend">
      <property name="text">
       <string>发送</string>
      </property>
     </widget>
    </item>
    <item row="0" column="2">
     <widget class="QPushButton" name="btnStartRecv">
      <property name="text">
       <string>开始接收</string>
      </property>
     </widget>
    </item>
    <item row="1" column="0" colspan="3">
     <widget class="QPlainTextEdit" name="editDebug"/>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menuBar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>400</width>
     <height>23</height>
    </rect>
   </property>
  </widget>
  <widget class="QToolBar" name="mainToolBar">
   <attribute name="toolBarArea">
    <enum>TopToolBarArea</enum>
   </attribute>
   <attribute name="toolBarBreak">
    <bool>false</bool>
   </attribute>
  </widget>
  <widget class="QStatusBar" name="statusBar"/>
 </widget>
 <layoutdefault spacing="6" margin="11"/>
 <resources/>
 <connections/>
</ui>

总结

QProcess启动子进程后,主进程关闭会带着子进程一起关闭,但是如果通过startDetached启动子进程写入的数据将读取不到,大概如此,网络中还包含子进程使用QSocketNotifier关联数据读取,我个人并未尝试成功,后期打算再尝试一下。

相关文章

Qt之进程通信-IPC(QLocalServer,QLocalSocket 含源码+注释)
Qt之进程通信-共享内存(含源码+注释)

友情提示——哪里看不懂可私哦,让我们一起互相进步吧
(创作不易,请留下一个免费的赞叭 谢谢 ^o^/)

注:文章为作者编程过程中所遇到的问题和总结,内容仅供参考,若有错误欢迎指出。
注:如有侵权,请联系作者删除

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1071289.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【算法——双指针】LeetCode 18 四数之和

题目描述&#xff1a; 解题思路&#xff1a;双指针 四数之和与前面三数之和思路一样&#xff0c;排序后&#xff0c;枚举 nums[a]作为第一个数&#xff0c;枚举 nums[b]作为第二个数&#xff0c;那么问题变成找到另外两个数&#xff0c;使得这四个数的和等于 target&#xff0c…

吃鸡玩家必备神器!一站式提升战斗力、分享干货!

大家好&#xff0c;我是吃鸡玩家。在这个视频中&#xff0c;我要分享一个让你瞬间提高战斗力的神器&#xff0c;同时让你享受到顶级游戏作战干货的盛宴&#xff01;让我们一起来了解吧&#xff01; 首先&#xff0c;我们推荐绝地求生作图工具。通过这款工具&#xff0c;你可以轻…

用这些IDEA插件,让你早下班两小时

GenerateAllSetter:一键调用一个对象的所有setter方法 RestfulTool:自动显示所有URL接口&#xff0c;快速检索接口 SequenceDiagram:以图形界面形式显示方法调用链&#xff0c;方便阅读源码、梳理代码 CamelCase:变量下划线转驼峰命名 Rainbow Brackets:帮助程序员识别代码中括…

十五、异常(5)

本章概要 异常限制构造器 异常限制 当覆盖方法的时候&#xff0c;只能抛出在基类方法的异常说明里列出的那些异常。这个限制很有用&#xff0c;因为这意味着与基类一起工作的代码&#xff0c;也能和导出类一起正常工作&#xff08;这是面向对象的基本概念&#xff09;&#…

基于SSM的校园资讯推荐系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

关联规则挖掘:Apriori算法的深度探讨

目录 一、简介什么是关联规则挖掘&#xff1f;什么是频繁项集&#xff1f;什么是支持度与置信度&#xff1f;Apriori算法的重要性应用场景 二、理论基础项和项集支持度&#xff08;Support&#xff09;置信度&#xff08;Confidence&#xff09;提升度&#xff08;Lift&#xf…

SSM - Springboot - MyBatis-Plus 全栈体系(十八)

第四章 SpringMVC SpringMVC 实战&#xff1a;构建高效表述层框架 一、SpringMVC 简介和体验 1. 介绍 Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架&#xff0c;从一开始就包含在 Spring Framework 中。正式名称“Spring Web MVC”来自其源模块的名称&#xff08…

OCR让点读笔如虎添翼

点读笔是一种智能学习工具&#xff0c;它可以通过识别文字来提供相应的语音或图像反馈。在实现文字识别功能时&#xff0c;点读笔通常会借助OCR&#xff08;Optical Character Recognition&#xff0c;光学字符识别&#xff09;技术。下面将详细介绍点读笔如何利用OCR技术实现文…

浅析人脸活体检测技术的两种方法

随着人脸识别技术日趋成熟,商业化应用愈加广泛,然而人脸极易用照片、视频等方式进行复制,因此对合法用户人脸的假冒是人脸识别与认证系统安全的重要威胁。目前基于动态视频人脸检测、人脸眨眼、热红外与可见光人脸关联等领先业界的人脸活体检测算法&#xff0c;已经取得了一定的…

Linux0.12内核源码解读(2)-Bootsect.S

作者&#xff1a;小牛呼噜噜 | https://xiaoniuhululu.com 计算机内功、源码解析、科技故事、项目实战、面试八股等更多硬核文章&#xff0c;首发于公众号「小牛呼噜噜」 文章目录 回顾计算机启动过程8086、80x86是什么意思?寄存器初始化CS:IPCPU是如何和ROM相连的?加载MBR到…

餐饮蛋糕鲜花便利店水果店外卖自提小程序开发

对于实体门店小微商家来说&#xff0c;做私域和复购永远是最划算的买卖。店里每天有新客到老客到&#xff0c;做好私域就可以零成本形成稳定客流而且还可以通过活动形成社交裂变和口碑效应。不做好私域和留存就是白白看着自己客户被同行一口一口吃掉。因此也就有了自提外卖小程…

制作婚礼邀请函只需三步,轻松制作走心请柬

制作自己的婚礼邀请函是一种流行的方式来传达你的婚礼信息给你的亲朋好友。在这个数字化的时代&#xff0c;你可以使用在线制作平台来创建自定义的婚礼邀请函。下面是一个简单的步骤指南&#xff0c;教你如何使用乔拓云网在线制作平台制作出超有感觉的婚礼请柬。 首先&#xff…

【Overload游戏引擎分析】从视图投影矩阵提取视锥体及overload对视锥体的封装

overoad代码中包含一段有意思的代码&#xff0c;可以从视图投影矩阵逆推出摄像机的视锥体&#xff0c;本文来分析一下原理 一、平面的方程 视锥体是用平面来表示的&#xff0c;所以先看看平面的数学表达。 平面方程可以由其法线N&#xff08;A, B, C&#xff09;和一个点Q(x0,…

【发表案例】计算机类SCIE,2区,2个月2天录用

计算机类SCIE 【期刊简介】IF&#xff1a;4.0-5.0&#xff0c;JCR2区&#xff0c;中科院3区 【检索情况】SCIE 在检&#xff0c;正刊 【征稿领域】提高安全性和隐私性的边缘/云的智能方法的研究&#xff0c;如数字孪生等 录用案例&#xff1a;2个月2天录用 2023.09.27 | A…

吃鸡玩家必备!提升战斗力,分享干货,保护账号安全!

你好&#xff01;吃鸡玩家们的福利来了&#xff01;在这里&#xff0c;我将为大家分享一些关于提高游戏战斗力、分享顶级游戏作战干货以及保护账号安全的实用技巧。 首先&#xff0c;让我们来谈提高游戏战斗力的技巧。绝地求生是一款战略性的游戏&#xff0c;而好的作图工具可以…

Java笔记八(instanceof,类型转换,static详解,抽象类,接口,内部类以及异常)

instanceof 引用类型&#xff0c;判断一个对象是什么类型 使用方法&#xff1a; System.out.println&#xff08;X instanceof Y&#xff09;&#xff1b; 代码理解&#xff1a; public class Application {public static void main(String[] args) {//Obiect>String//…

如何成为合格的测试开发工程师?

是入职两年半的测试开发工程师小编&#xff0c;虽然目前很菜&#xff0c;但还是希望自己继续努力&#xff0c;早日成为一名合格的测试开发工程师&#xff0c;本篇文章也是通过对身边同事的了解&#xff0c;整理了几点对自己的要求&#xff0c;以及重新梳理了下今后的学习路径&a…

CI522 13.56MHZ电动车NFC测试资料

Ci522是一颗工作在13.56MHz频率下的非接触式读写芯片&#xff0c;支持读A卡&#xff08;CI523支持读A/B卡&#xff09;&#xff0c;可做智能门锁、电动车NFC一键启动、玩具NFC开锁等应用。为部分要求低成本&#xff0c;PCB小体积的产品提供了可靠的选择。 Ci522与Si522/MFRC52…

母婴店做微信小程序开发的重要性

随着移动互联网的发展&#xff0c;母婴店传统的线下销售模式已经无法满足现代年轻父母的需求。微信小程序作为一种新型的应用形态&#xff0c;为母婴店提供了新的销售渠道和推广方式。本文将探讨母婴店做微信小程序开发的作用。 一、拓展销售渠道 微信小程序是一种轻量级的应用…

混沌工程初分享

混沌工程初分享 一、什么是混沌工程 1、什么是混沌 混沌是一种现象&#xff0c;在一个动力系统中&#xff0c;因为各种不同的参数变化导致的一系列的连锁反应。比如&#xff1a; 在南美洲亚马逊河流域热带雨林中的蝴蝶&#xff0c;偶尔的几次振翅&#xff0c;可以在两周以后引…