将qt的子程序窗口嵌入qt的主进程主窗口中(第二种方式)

上一篇文章,存在失去焦点问题,分析可能原因是直接将子进程的窗口句柄封装到QWindow对象中之后,窗口的键盘事件可能就qt自己处理,但是目前没有搞清楚怎么处理的.

下面这种方式也类似第一种方式,不同点在于处理窗口句柄的方式.

通过自定义一个QWindow的一个子类,在子类中通过window平台api将子进程窗口的句柄与子类对象形成父子关系.然后在将子类封装为QWidget供qt主进程的其他控件使用.这种方式的优点是不存在失去焦点问题.但是要处理win7下的其他问题.

笔者在win7下出现的问题:

1.当子进程非全屏模式时,当通过QProcess启动这个子进程窗口时,出现卡住的问题,并且不会显示该窗口. 只有将子进程的设置为 showFullScreen()后,就能正常启动了.分析可能原因时,window平台api设置窗口为无边框及工具窗口对于qt窗口无效,只能通过子进程内部设置好.

2.当主进程窗口是showFullScreen()状态时,子进程存在QDailog窗口,或者一些其他控件的操作时,会出现window桌面任务栏弹出的现象.win10下正常. 笔者通过判断当前操作系统版本,然后通过将任务栏的自动隐藏功能开启后,可通软件层面技术性解决该问题.将任务栏自动隐藏功能开启后,及时存在弹出现象,也因为隐藏后,不会显示. 当软件退出时,再取消该功能.

代码1: 自定义一个QWindow子类

#include <windows.h>
#include <QWindow>//创建子进程用的QWindow子类
class ChildWindowWrapper : public QWindow {
public:/// <summary>/// 构造一个Qwindow子类对象/// </summary>/// <param name="hwnd">子进程创建句柄</param>/// <param name="parent">Qwindow对象的父对象</param>ChildWindowWrapper(HWND hwnd, QWindow* parent = nullptr): QWindow(parent), m_hwnd(hwnd) {embedChildWindow();}~ChildWindowWrapper(){if (m_hwnd) {SetParent(m_hwnd, NULL);}}void embedChildWindow() {// 修改子窗口样式,去掉标题栏和边框  win7下,qt窗口好像无效了,所以通过子进程内部将窗口设置为全屏LONG style = GetWindowLong(m_hwnd, GWL_STYLE);style &= ~(WS_CAPTION | WS_THICKFRAME);style|= WS_EX_TOOLWINDOW;SetWindowLong(m_hwnd, GWL_STYLE, style);//关键点,通过window api 将当前QWindow对象设置为子进程窗口的父对象窗口SetParent(m_hwnd, (HWND)winId());//这个也很重要,将子进程窗口设置为无边框及标题栏的窗口 ,在win7下才不会弹出底下的状态栏.,win10没有这个也正常//SWP_FRAMECHANGED刷新一次上述更改的状态.SWP_NOZORDER保存窗口为层级不变SetWindowPos(m_hwnd, nullptr, 0, 0, width(), height(),  SWP_NOACTIVATE | SWP_FRAMECHANGED);// 显示子进程窗口//ShowWindow(m_hwnd, SW_SHOW);//SetForegroundWindow(m_hwnd);//SetFocus(m_hwnd);}protected:bool event(QEvent* event) override {if (event->type() == QEvent::Resize) {if (m_hwnd) {//SetWindowPos(m_hwnd, nullptr, 0, 0, width(), height(), SWP_NOZORDER | SWP_NOACTIVATE);SetWindowPos(m_hwnd, nullptr, 0, 0, width(), height(), SWP_NOACTIVATE);}}return QWindow::event(event);}private://子进程窗口的句柄HWND m_hwnd;
};
 //头文件中定义子类对象指针
ChildWindowWrapper* m_ChildVMWin{ nullptr };

 具体代码实现

//window 底层操作,隐藏window桌面的任务栏功能,在win7下/// <summary>
/// 获取window版本
/// </summary>
/// <returns>0为win7,1为win10,其他为-1</returns>
int CncOpWindows::GetWindowsVerson()
{int iType{ 0 };QString osName = QSysInfo::productType();//qDebug() << "Operating System:" << osName;if (osName == "windows"){ if (QSysInfo::windowsVersion() == QSysInfo::WV_WINDOWS7){//qDebug() << "Windows 7";iType = 0;}else if (QSysInfo::windowsVersion() == QSysInfo::WV_WINDOWS10) {//qDebug() << "Windows 10";iType = 1;}else{//其他windows系统iType = 2;}}else {//qDebug() << "Other OS";iType = -1;}return iType;
}void CncOpWindows::FindWindowsTaskBarHandle()
{
//windows任务栏句柄hwndWindowsTaskBar = FindWindow("Shell_TrayWnd", NULL);
}void CncOpWindows::HideWindowsTaskBar()
{if(hwndWindowsTaskBar)SetAutoHideWindowsTaskbar(true);}
void CncOpWindows::ShowWindowsTaskBar()
{if (hwndWindowsTaskBar)SetAutoHideWindowsTaskbar(false);
}void CncOpWindows::SetAutoHideWindowsTaskbar(bool enable) 
{
//开启/关闭任务栏自动隐藏功能APPBARDATA appBarData = { 0 };appBarData.cbSize = sizeof(APPBARDATA);appBarData.hWnd = hwndWindowsTaskBar;if (enable) {appBarData.lParam = ABS_AUTOHIDE ;}else {appBarData.lParam = 0;}SHAppBarMessage(ABM_SETSTATE, &appBarData);
}void CncOpWindows::CreateShareMem()
{
//创建共享内存,与子进程通信用, 通过变量控制子进程的退出与显示m_pShareMemObj = new qcShareMemory(nullptr);m_pThreadShareMem = new QThread(this);m_pThreadShareMem->setObjectName(tr("ShareMenThread"));m_pShareMemObj->moveToThread(m_pThreadShareMem);connect(m_pThreadShareMem, &QThread::started, m_pShareMemObj, &qcShareMemory::slotInit);connect(m_pThreadShareMem, &QThread::finished, m_pShareMemObj, &qcShareMemory::slotFinish);connect(this, &CncOpWindows::signalReadWriteShareMem, m_pShareMemObj, &qcShareMemory::slotReadWriteShareMem);connect(m_pShareMemObj, &qcShareMemory::signalShowLastWnd, this, &CncOpWindows::slotShowLastWnd);m_pThreadShareMem->start();m_pShareMemObj->m_bStart = true;emit signalReadWriteShareMem();
}bool CncOpWindows::LoadVisionMeasureApp()
{QString cmd= QCoreApplication::applicationDirPath();int iCamAppType = 0;switch (iCamAppType){case 0:cmd += "/ImageGrab.exe";//子程序执行文件地址break;case 5:cmd += "/MeasureVM.exe";//子程序执行文件地址break;}QStringList argList;argList << QString::number(ui->stackedWidget_sub->winId());//把父窗口的id给子进程传递过去m_pProcessVM = new QProcess(this);//使用进程运行子进程窗口connect(m_pProcessVM, &QProcess::readyReadStandardError, this, &CncOpWindows::slotCreateWaitingVM);//等待子进程窗口把自身的winId传递过来connect(m_pProcessVM, qOverload<int, QProcess::ExitStatus>(&QProcess::finished), this, qOverload<int , QProcess::ExitStatus>(&CncOpWindows::slotFinishedProcessVM));//connect(m_pProcessVM, &QProcess::readyRead, this, &CncOpWindows::slotReadProcessVM);m_pProcessVM->start(cmd, argList);return m_pProcessVM->waitForStarted(2000);
}void CncOpWindows::slotCreateWaitingVM()
{quint64 winId = m_pProcessVM->readAllStandardError().toLongLong();m_ChildVMWin = new ChildWindowWrapper((HWND)winId, ui->stackedWidget_sub->windowHandle());//m_ChildVMWin = QWindow::fromWinId(winId);if (m_ChildVMWin){//m_ChildVMWin->setParent(ui->stackedWidget_sub->windowHandle());m_WidgetVMProcess = QWidget::createWindowContainer(m_ChildVMWin);//获取一个子进程窗口的widget// 调整窗口大小以适应控件大小ui->stackedWidget_sub->addWidget(m_WidgetVMProcess);//这里是可以使用布局器管理子进程窗口的,不管理的话就在坐标0,0处}}void CncOpWindows::slotFinishedProcessVM(int exitCode, QProcess::ExitStatus exitStatus)
{qInfo() << "ImageGrab.exe quit"<<"[exitCode="<< exitCode << "ExitStatus=" << exitStatus << "]";//if (exitStatus== QProcess::NormalExit)//{//	//正常退出//}//else//{//	//非正常退出//}}void CncOpWindows::CloseVisionMeasureApp()
{//关闭当前视觉测量进程if (m_pProcessVM){////关键点,必须将嵌入的QWindow设置为没有父对象,在调用退出指令就正常了/*  if (m_ChildVMWin){m_ChildVMWin->setParent(nullptr);}*///正常退出程序terminate 发送一个close消息到顶层窗口.//m_pProcessVM->terminate();//结束app信号 共享内存与子进程通信if (PointGlobalParams()->m_pDataApp){PointGlobalParams()->m_pDataApp->bC2V[1] = true;}//等待结束不能省,bool bFinish=m_pProcessVM->waitForFinished(5000);if (!bFinish){//非正常退出qInfo() << "ImageGrab.exe crash quit";}}}

子进程实现

//mian函数中的实现,只需要传递子进程窗口的winid,也即window下的窗口句柄if (argc >1){//关键代码,触发错误之后,主进程能够响应fprintf(stderr, "%lld", (quint64)w.winId());//写入标准错误输出,stderr能立即输出,stdout则不行w.hide();}else{w.show();}
//定义一个定时器,时刻监控共享内存的状态,来执行下面这两个函数
//显示当前app
void ImageGrab::slotShowApp()
{//将当前窗口处于激活状态m_pGlobalPa->m_pDataApp->bV2C[0] = true;if (this->isHidden()){this->show();this->activateWindow();}
}void ImageGrab::slotCloseApp()
{//将当前app关闭this->close();
}

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

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

相关文章

TypeScript中的Symbol,确实唯一。。。

Symbol 目录 Symbol 目录自动推断symbol unique symbol区别 自动推断 let命令声明的变量&#xff0c;推断类型为 symbol。// let定义symbol推断为symbol let sym Symbol(); //symbol但是&#xff0c;const命令声明的变量&#xff0c;如果赋值为另一个 symbol 类型的变量&…

解释双向队列(Deque)的概念,Java 中的 ArrayDeque 和 LinkedList 作为 Deque 的实现,它们各自有什么优缺点?

双向队列&#xff08;Deque&#xff0c;全称为 Double Ended Queue&#xff09;是一种具有队列和栈特性的数据结构&#xff0c;允许在两端进行元素的添加和移除操作。这意味着你可以在队列的前端&#xff08;头部&#xff09;或后端&#xff08;尾部&#xff09;进行入队&#…

从 Acme.Sh V3.0 说说 ZeroSSL

熟悉明月的都知道&#xff0c;明月一直都在使用 acme.sh 作为服务器端申请、部署、续期免费 SSL 证书的主要工具&#xff0c;今天在帮一个站长申请 SSL 证书的时候发现 acme.sh v3.0 开始默认的免费 SSL 证书变更为&#xff1a;ZeroSSL 了&#xff0c;这个 ZeroSSL 其实跟明月一…

在 C++ 中使用不同平台的时间函数及比较

在 C 编程中&#xff0c;时间函数的选择对于性能测量、任务调度和时间戳记录至关重要。不同的操作系统提供了不同的时间函数&#xff0c;同时在同一个平台上&#xff0c;也可能有多种不同的时间函数可供选择。本文将介绍在 C 中常用的时间函数&#xff0c;并比较它们在不同平台…

通俗范畴论2 有向图与准范畴

退一步海阔天空&#xff0c;在正式进入范畴论之前&#xff0c;我们可以重新审视一下我们是如何认识世界的&#xff0c;有了这个对人类认识世界过程的底层理解&#xff0c;可以帮助我们更好地理解范畴论。 对于人类认识世界&#xff0c;最神奇的一点就是这个世界居然是可以认识…

map文件分析

以下是一个具体的map文件示例&#xff0c;并附上详细的描述&#xff0c;帮助你更好地理解如何读取和分析map文件&#xff1a; 示例map文件 Memory ConfigurationName Origin Length Attributes FLASH 0x08000000 0x0…

初识docker插件

文章目录 一、Docker插件概述二、Docker插件的优势三、Docker插件的使用例子1. 安装Docker插件2. 启用Docker插件3. 创建卷并使用 四、常用的Docker插件五、总结 Docker插件&#xff08;Docker Plugin&#xff09;是Docker扩展功能的一种重要方式&#xff0c;它允许用户为Docke…

Elasticsearch 认证模拟题 - 22

一、题目 索引 task 索引中文档的 fielda 字段内容包括了 hello & world&#xff0c;索引后&#xff0c;要求使用 match_phrase query 查询 hello & world 或者 hello and world 都能匹配该文档 1.1 考点 分词器 1.2 答案 # 创建符合条件的 task 索引&#xff0c;…

C++之 delete删除拷贝构造函数和拷贝赋值运算符

在 C 中&#xff0c;删除拷贝构造函数和拷贝赋值运算符是一种常见的方法&#xff0c;用于防止对象的拷贝和赋值。这在某些情况下是必要的&#xff0c;例如当类管理资源&#xff08;如线程、文件句柄或网络连接&#xff09;时&#xff0c;以确保资源的唯一性和避免潜在的资源泄漏…

算法人生(22):从“生成对抗网络”看“逆商提升”

​ 在图像生成与编辑、音频合成、视频生成领域里&#xff0c;有一个非常重要的深度学习方法——生成对抗网络&#xff08;简称GANs&#xff09;&#xff0c;它是由两个神经网络组成的模型&#xff0c;分别为生成器&#xff08;Generator&#xff09;和判别器&#xff08;Discr…

【Linux】I/O多路复用

文章目录 I/O多路复用select()select()缺点 poll()poll()缺点 epoll()LT(水平触发模式)ET(边缘触发模式)具体函数 I/O多路复用 多进程和多线程实现并发会消耗大量的资源&#xff0c;主进程/线程用于监听和接受连接&#xff0c;再创建多个子进程/子线程来完成与连接的各个客户端…

采煤vr事故灾害应急模拟救援训练降低生命财产损失

在化工工地&#xff0c;设备繁多、环境复杂&#xff0c;潜藏着众多安全隐患&#xff0c;稍有不慎便可能引发安全事故。为了保障工地的安全&#xff0c;我们急需一套全面、高效的安全管理解决方案。web3d开发公司深圳华锐视点研发的工地安全3D模拟仿真隐患排查系统&#xff0c;正…

可以用来制作硬模空心耳机壳的胶粘剂有哪些种类?

可以用来制作硬模空心耳机壳的胶粘剂有哪些种类&#xff1f; 制作耳机壳的胶粘剂有很多种类&#xff0c;常见的有环氧树脂胶水、UV树脂胶、快干胶、热熔胶等。 这些胶粘剂都有不同的特点和适用场景&#xff0c;可以根据自己的需求选择合适的类型。 例如&#xff1a; 环氧树脂…

css3新增伪类有哪些?

在 CSS3 中引入了一些新的伪类&#xff0c;用于向选择器添加特定的状态或行为。以下是一些常见的 CSS3 新增的伪类&#xff1a; :nth-child() 和 :nth-of-type()&#xff1a;根据元素在其父元素中的位置选择元素。例如&#xff0c;:nth-child(odd) 选择所有奇数位置的子元素。 …

pdf转图片,pdf转图片在线转

pdf转图片的方法&#xff0c;对于许多人来说可能是一个稍显陌生的操作。然而&#xff0c;在日常生活和工作中&#xff0c;我们有时确实需要将pdf文件转换为图片格式&#xff0c;以便于在特定的场合或平台上进行分享、展示或编辑。以下&#xff0c;我们将详细介绍一个pdf转成图片…

用宝塔部署vue+springboot上线公网详细步骤

首先自己在腾讯云中按照教程安装好宝塔。这是宝塔面板&#xff0c;获取登录宝塔的网址和账号密码。 1.在navicat新建数据库 如果出现权限问题&#xff0c;可以在宝塔数据库面板phpMyAdmin中进行权限设置 navicat可以修改用户权限 2.在宝塔面板新建数据库 3.将前端打包的dist文件…

linux 部署瑞数6实战(维普,药监局)第一部分

声明 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01;wx 本文章未经许可禁止转载&…

【星海随笔】云解决方案学习日志篇(二) kafka、Zookeeper、Fielbeat

Elastic 中国社区官方博客 https://blog.csdn.net/ubuntutouch/category_9209092.html Kafka kafka的源代码是基于Scala语言编写的&#xff0c;运行在Java虚拟机&#xff08;即:JVM&#xff09;上。因此&#xff0c;在安装kafka之前需要先安装JDK Kafka 为什么依赖 Zookeepe…

52. QT插件开发--插件程序(带ui文件)的创建与编译

1. 说明 一般情况下,针对代码量比较小的QT程序不需要进行插件集成化开发,但是针对大型程序来说,代码结构比较复杂,使用插件开发的方式可以提高代码开发和维护效率,团队之间的分工合作也会更加的明确。所谓插件式开发,实际上就是把程序的一部分功能封装起来,编译成一个单…

一血c++

题目描述 每一个竞赛选手都无法拒绝拿一血 "一血"其实就是同学们在榜单上看到的深绿色的标记&#xff0c;代表着某道题目&#xff0c;他是第一个通过的。 叶苡朋老师是一名资深信奥选手&#xff0c;在大学多次获奖&#xff0c;也是一个资深抢一血爱好者&#xff0…