Qt 多进程编程-将子程序嵌入到主窗口

关键字:GPT4QProcessFindWindowExQt嵌入

文章目录

    • 前言
    • 调用外部程序
      • 关于 QProcess
    • 嵌入到主程序显示
      • FindWindowEx & FindWindow
      • FindWindow
      • FindWindowEx
      • 使用场景
    • 结束

前言

今天计划是稍微研究一下Qt的多进程编程,因为最近的程序感觉有点慢,还有一个严重的问题就是会触发Windows的GDI限制,所以计划把程序分成几个进程来搞,变相的提高程序的性能多多几个GDI。
因为之前是搞过嵌入程序的,不过哪个是用的别人提供的SDK库,我只需要给他一个句柄来接他的UI即可,所以没有深入了解,今天需要我自己搭建一个框架出来。

调用外部程序

首先,如果想把程序嵌入进来,那我们就得先把程序启动了,不然就加载个空气进来了,所以这里先研究一下怎么启动一个进程。因为项目式理线开发,所以这里咱直接用GPT生成一段代码;

#include <QProcess>
#include <QDebug>// ...QProcess *process = new QProcess(this); // this 指定父对象,以便自动回收资源
QString program = "外部程序的路径"; // 比如 "notepad.exe"// 启动外部程序
process->start(program);// 等待程序启动完成或超时
if (!process->waitForStarted()) {qDebug() << "外部程序启动失败:" << process->errorString();return;
}// 发送数据到外部程序的标准输入(如果需要)
// process->write("一些输入数据\n");// 等待程序执行完成或超时
if (!process->waitForFinished()) {qDebug() << "外部程序执行失败:" << process->errorString();return;
}// 读取外部程序的标准输出和标准错误输出
QString standardOutput = process->readAllStandardOutput();
QString standardError = process->readAllStandardError();delete process; // 如果没有指定父对象,记得手动删除以避免内存泄漏// 打印输出结果
qDebug() << "标准输出:" << standardOutput;
qDebug() << "标准错误:" << standardError;

关于 QProcess

QProcess 类是属于 Qt 框架中的一个类,用于启动和管理外部程序的执行。它允许你的 Qt 应用程序来控制其他程序,并且与它们通过标准输入输出进行交互,这非常有用于那些需要从其他应用程序接收数据或者向其发送数据的情况。

以下是 QProcess 类的一些基本功能:

  1. 启动外部程序:你可以指定程序名称和所需的参数来启动一个程序。
  2. 读取和写入数据:你可以通过程序的标准输入、输出和错误输出流来与之交互。这意味着你可以发送命令给进程或读取其输出结果。
  3. 同步或异步操作QProcess 可以同步运行(阻塞当前线程直到外部程序完成执行),或者异步运行(在独立的线程中执行,不干扰当前线程的执行流程)。
  4. 信号和槽机制:作为一个 QObject 的子类,QProcess 使用 Qt 的信号和槽机制。例如,你可以连接到 finished 信号以获取当外部程序完成时的通知,或者连接到 readyRead 信号来读取可用的数据。
  5. 处理程序输出QProcess 提供了多种方法来读取程序的标准输出和错误输出,包括readAllStandardOutputreadAllStandardError
  6. 错误处理QProcess 也能提供关于启动或运行过程中发生错误的信息。

下面是一个简单的例子,展示了如何使用 QProcess 来运行一个外部的 ping 命令:

#include <QProcess>
#include <QDebug>int main(int argc, char *argv[])
{QCoreApplication app(argc, argv);QProcess pingProcess;pingProcess.start("ping", QStringList() << "-c 4" << "www.example.com");QObject::connect(&pingProcess, &QProcess::finished, [&](int exitCode) {qDebug() << "Process finished with exit code" << exitCode;app.quit();});QObject::connect(&pingProcess, &QProcess::readyReadStandardOutput, [&]() {qDebug() << pingProcess.readAllStandardOutput();});QObject::connect(&pingProcess, &QProcess::readyReadStandardError, [&]() {qDebug() << pingProcess.readAllStandardError();});return app.exec();
}

在这个例子中,QProcess 用来运行 ping 命令并打印出结果。当 ping 命令结束后,程序也随之退出。这个程序还演示了如何连接信号到一个 lambda 表达式,这允许你直接在信号槽连接中写入处理代码。

嵌入到主程序显示

这里就要说一下GPT了,开始用的GPT3 后面换成了GPT4 ,还是一样,一下午都开始怀疑这路子是否可以行的通了,最终还是一步一步Debug发现问题。我们看下 GPT 的答案:
在Qt中,如果你想嵌入一个外部程序的窗口到你的Qt应用程序中,你需要获取外部程序窗口的句柄(HWND在Windows中)并且将其设置为你的Qt窗口的子窗口。这通常涉及到Windows API的调用,因此这种方法是平台依赖的。

以下是一个在Windows平台上嵌入外部程序窗口至Qt应用程序中的基本示例:

首先,你需要启动一个外部程序并得到它的进程ID。然后,使用Windows API来查找窗口句柄并将其嵌入。

以下是示例代码:

#include <QProcess>
#include <QtWidgets>
#include <windows.h>class MyWidget : public QWidget {
public:MyWidget(QWidget *parent = nullptr) : QWidget(parent) {// Start the external applicationQProcess *process = new QProcess(this);process->start("notepad.exe");// Wait for the process to startprocess->waitForStarted();// Now we need to find the window handleHWND hwnd = 0;while (!hwnd) {hwnd = FindWindowEx(0, hwnd, "Notepad", NULL);if (hwnd) {// Embed the windowSetParent(hwnd, (HWND)this->winId());// Optionally resize the embedded window to fill the parent widgetSetWindowPos(hwnd, 0, 0, 0, this->width(), this->height(), SWP_NOZORDER);}Sleep(10); // Prevents freezing}}protected:// Overriding the resize event to resize the embedded window as wellvoid resizeEvent(QResizeEvent *event) override {QWidget::resizeEvent(event);// Resize the embedded window to fill the parent widgetHWND hwnd = FindWindowEx(0, 0, "Notepad", NULL);if (hwnd) {SetWindowPos(hwnd, 0, 0, 0, width(), height(), SWP_NOZORDER);}}
};int main(int argc, char *argv[]) {QApplication app(argc, argv);MyWidget widget;widget.show();return app.exec();
}

在这个例子中,我们启动了记事本程序(notepad.exe),并且尝试获取它的窗口句柄。一旦我们得到窗口句柄,我们就调用SetParent来把记事本的窗口嵌入到我们的Qt窗口中,并且通过SetWindowPos函数调整窗口大小。

请注意,这个方法并不是通用的,因为它依赖于外部程序的窗口类名(本例中为"Notepad")和标题,这些信息可能会在不同版本的Windows或不同的应用程序中有所不同。此外,由于这种方法依赖于Windows API,它只适用于Windows平台。

此外,这种方法也可能会遇到安全限制,特别是在Windows Vista及以后的操作系统版本中,因为嵌入的窗口可能属于不同的进程。这可能需要调整UIPI(用户界面特权隔离)设置。

对于跨平台的Qt应用程序,可能需要寻找其他方法或考虑是否必须嵌入外部程序。

不知道你有没有发现有问题的地方

FindWindowEx & FindWindow

FindWindowFindWindowEx 是 Windows API 中的函数,用于在桌面上查找窗口,但它们在功能上有所不同。

FindWindow

FindWindow 函数用于查找顶级窗口,其类名和窗口名与指定的字符串匹配。这个函数不搜索子窗口。调用 FindWindow 时,你可以指定完整的窗口类名或窗口标题,或者两者都指定,也可以只指定其中之一(另一个参数设为 NULL)。

函数原型如下:

HWND FindWindow(LPCSTR lpClassName,  // 窗口类名LPCSTR lpWindowName  // 窗口标题
);

如果函数成功,返回值是目标窗口的句柄;如果未找到符合条件的窗口,返回 NULL

FindWindowEx

FindWindowEx 函数用于查找子窗口,它不仅可以查找顶级窗口,还可以查找子窗口,其功能比 FindWindow 更加灵活。使用 FindWindowEx 时,你可以指定父窗口句柄,从而在特定父窗口的子窗口中进行搜索。此外,你还可以通过传递前一个兄弟窗口的句柄来继续搜索。

函数原型如下:

HWND FindWindowEx(HWND    hWndParent,   // 父窗口句柄HWND    hWndChildAfter, // 子窗口句柄LPCSTR  lpszClass,    // 窗口类名LPCSTR  lpszWindow    // 窗口标题
);

hWndParent 参数是父窗口的句柄,hWndChildAfter 参数是子窗口的句柄,函数会从该子窗口后开始搜索。如果 hWndChildAfterNULL,搜索从 hWndParent 的第一个子窗口开始。如果 hWndParenthWndChildAfter 都是 NULL,那么 FindWindowEx 会搜索任何顶级窗口以及消息窗口。

FindWindowEx 的返回值和 FindWindow 一样,找到的窗口句柄或者 NULL

使用场景

  • 当你只需要查找顶级窗口时,使用 FindWindow 即可。
  • 当你需要在已知的父窗口中查找子窗口,或者需要在同一父窗口的子窗口间进行顺序查找时,使用 FindWindowEx

两者都是通过类名和窗口名进行匹配查找,但是 FindWindowEx 提供了更精细的控制,允许你对窗口的层级关系和搜索顺序进行精确的指定和遍历。
按照解释是没有任何问题,但是当我使用 FindWindowEx 找到的始终都是空,不得不转而使用 FindWindow

结束

到这里就基本走通了,如果你在开发中也遇到了找不到窗口的问题,而碰巧你也用了 FindWindowEx,那你不妨试一下 FindWindow

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

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

相关文章

Docker简介、基本概念和安装

Docker简介、基本概念和安装 1.docker简介 1.1 什么是docker Docker 最初是 dotCloud 公司创始人 Solomon Hykes (opens new window)在法国期间发起的一个公司内部项目&#xff0c;它是基于 dotCloud 公司多年云服务技术的一次革新&#xff0c;并于 2013 年 3 月以 Apache 2…

Objective-C中使用STL标准库Queue队列

1.修改.m文件为mm 2.导入queue头 #include<queue> 3.使用&#xff1a; #import <Foundation/Foundation.h> #include <cmath> #include <queue> using namespace std;int main(int argc, const char * argv[]) {autoreleasepool {NSLog("C标准…

云计算任务调度仿真01

云计算任务调度的研究大多数以来仿真研究&#xff0c;现梳理一些做过的代码研究 结果无数次的排错&#xff0c;终于finish with code 0 了 这个代码以来的是比较老的TensorFlow版本&#xff0c;我们都知道TensorFlow1.x和TensorFlow2.x之间有很大差别&#xff0c;但其实&#…

AspectJ 基础

前两篇AspectJ入门的文章大致的介绍了AspectJ,本文更完整、更详细的介绍AspectJ的基础知识。包括了切点、连接点、类型间声明及thisJoinPoint的基础知识&#xff0c;来更好的理解AspectJ的语法。 1 切点和连接点 挑选切点的时候&#xff0c;我们还可以通过方法的访问权限、是…

C++ 字符串哈希 || 字符串前缀哈希法

字符串Hash就是构造一个数字使之唯一代表一个字符串。但是为了将映射关系进行一一对应&#xff0c;也就是&#xff0c;一个字符串对应一个数字&#xff0c;那么一个数字也对应一个字符串。 用字符串Hash的目的是&#xff0c;我们如果要比较一个字符串&#xff0c;我们不用直接比…

Realm Management Extension领域管理扩展之安全状态

RME基于Arm TrustZone技术。TrustZone技术在Armv6中引入,提供以下两个安全状态: 安全状态(Secure state)非安全状态(Non-secure state)以下图表显示了在AArch64中的这两个安全状态以及通常在每个安全状态中找到的软件组件: 该架构将在安全状态运行的软件与在非安全状态运…

openGauss学习笔记-190 openGauss 数据库运维-常见故障定位案例-服务启动失败

文章目录 openGauss学习笔记-190 openGauss 数据库运维-常见故障定位案例-服务启动失败190.1 服务启动失败190.1.1 问题现象190.1.2 原因分析190.1.3 处理办法 openGauss学习笔记-190 openGauss 数据库运维-常见故障定位案例-服务启动失败 190.1 服务启动失败 190.1.1 问题现…

【Leetcode】251.展开二维向量

一、题目 1、题目描述 请设计并实现一个能够展开二维向量的迭代器。该迭代器需要支持 next 和 hasNext 两种操作。 示例: Vector2D iterator = new Vector2D([[1, 2], [3], [4]]);iterator.next(); //返回1 iterator.next(); //返回2 iterator.next(); //返回3 iterator.h…

Copilot 插件的使用介绍:如何快速上手

GitHub Copilot 本文主要介绍如何通过脚本工具激活 GitHub Copilot 插件&#xff0c;提供安装及激活图文教程&#xff0c;大家按下面操作即可激活GitHub Copilot插件&#xff0c;免费使用Ai编码工具 一、GitHub Copilot 介绍 GitHub Copilot 是由 GitHub 和 OpenAI 共同开发的…

告别冗余空白,批量删除空白行

你是否遇到过这样的尴尬情况&#xff1a;花费了大量时间整理的文档&#xff0c;却在最后发现其中充斥着无用的空白行&#xff0c;这些多余的空行不仅影响美观&#xff0c;还让整个文档显得杂乱无章。今天&#xff0c;我要给大家介绍一款强大且实用的工具——首助编辑高手&#…

移动端对大批量图片加载的优化方法(三)

移动端对大批量图片加载的优化方法&#xff08;三&#xff09;Flutter 本篇主要从Flutter开发中可以使用到的对大批量图片加载的优化方法进行整理。 1.合适的图片格式 详情请参考移动端对大批量图片加载的优化方法&#xff08;一&#xff09;。 2.缓存机制 在Flutter中&am…

浅谈对Promise的理解。

一、Promise定义 JS中用于处理异步操作的编程模式。一个Promise是一个代理&#xff0c;它代表一个创建Promise时不一定已知的值。它允许我们将处理的程序与异步操作的最终成功值或失败值原因想关联起来。这使得异步方法可以像同步方法一样返回值&#xff1a;异步方法不会立即返…

uniapp最简单的底部兼容安全区域显示

效果图&#xff1a; 1.html写上动态padding-bottom <view class"button-wrap" :style"padding-bottom:bottomPaddingrpx"><view class"com-btn cencel-btn">取消</view><view class"com-btn confirm-btn " cl…

神经网络中的梯度爆炸

梯度爆炸是深度学习中的一种常见问题&#xff0c;指的是在反向传播过程中&#xff0c;某些梯度的值变得非常大&#xff0c;导致数值溢出或趋近于无穷大。梯度爆炸通常会导致训练不稳定&#xff0c;模型无法收敛&#xff0c;或者产生不可靠的结果。 梯度爆炸可能发生在深度神经…

【PostgreSQL创建索引的锁分析和使用注意】

1.1 创建普通B-tree索引的整体流程 如下是梳理的创建普通B-tree索引的大概流程&#xff0c;可供参考。 1.校验新索引的Catalog元数据|语法解析 ---将创建索引的sql解析成IndexStmt结构&#xff5c;校验B-Tree的handler -----校验内核是否支持该类型的索引,在pg_am中查找&q…

java 体育明星管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 java Web 体育明星管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysq…

Clojure 实战(4):编写 Hadoop MapReduce 脚本

Hadoop简介 众所周知&#xff0c;我们已经进入了大数据时代&#xff0c;每天都有PB级的数据需要处理、分析&#xff0c;从中提取出有用的信息。Hadoop就是这一时代背景下的产物。它是Apache基金会下的开源项目&#xff0c;受Google两篇论文的启发&#xff0c;采用分布式的文件…

Spark Core--加强

RDD的持久化 RDD缓存 当RDD被重复使用&#xff0c;或者计算该RDD比较容易出错&#xff0c;而且需要消耗比较多的资源和时间的时候&#xff0c;我们就可以将该RDD缓存起来。 主要作用: 提升Spark程序的计算效率 注意事项: RDD的缓存可以存储在内存或者是磁盘上&#xff0c;甚至…

小程序开发之uniapp项目框架搭建

出于对技术的实践&#xff0c;以及博主最近刚刚拥有了一台自己的云服务器&#xff0c;本着闲着也是闲着的态度&#xff0c;准备着手开发一款快递下单、查询快艇实时状态的多端小程序&#xff0c;又不想在各个小程序平台重复开发&#xff0c;因此选择了uinapp 。 博主先讲诉一下…

【数据结构】二叉树链式结构详解

目录 1.前言2.快速创建一颗二叉树3.二叉树的遍历3.1前序遍历3.2中序遍历3.3后序遍历3.4层序遍历 4.二叉树节点个数与高度4.1二叉树节点个数4.2二叉树叶子节点个数4.3二叉树高度4.4二叉树第k层节点个数4.5二叉树查找值为x的节点 5.二叉树的基础oj题练习6.二叉树的创建和销毁6.1通…