Qt如何将外部窗口嵌入部件中

news2024/9/29 21:28:29

一、简述

今天给大家讲解的是使用QWindow类通过窗口句柄将外部的应用程序嵌入到我们的部件中来显示。在讲解之前可以延伸一下,当时项目中使用QProcess启动一些本地软件或者执行脚本时,需要将启动的第三方窗口嵌入到我们自己写的窗口中,此时我们通过QProcess类的start方法执行相应的启动命令,并获取到启动程序的进程id(pid),然后通过pid获取到窗口对应的句柄,最后通过QWindow类创建容器将外部应用程序嵌入到我们的界面中来。

所以讲解之前,会先讲解下如何通过WinApi根据进程id(pid)获取到窗口的句柄,然后再通过窗口句柄使用QWindow来嵌入到我们的界面中来。

二、代码之路

我们先使用WinApi通过进程id(pid)获取到窗口句柄,具体接口以及示例代码如下,大家可直接拷贝即可:


struct FindWindowData
{
    DWORD processId;
    HWND hWnd;
};

BOOL FindWindowCB(HWND hWnd, LPARAM lParam)
{
    DWORD processId = 0;
    if (GetWindowThreadProcessId(hWnd, &processId)) {
        // 分配足够大的缓冲区来存储窗口标题
        const int MAX_TITLE_LENGTH = 255;
        WCHAR windowTitle[MAX_TITLE_LENGTH];

        // 调用 GetWindowTextW 来获取窗口标题
        int result = GetWindowTextW(hWnd, windowTitle, MAX_TITLE_LENGTH);
        // qDebug() << "the text:" << QString::fromWCharArray(windowTitle) << result << hWnd << processId;

        QString title = QString::fromWCharArray(windowTitle);

        FindWindowData* dataPtr = (FindWindowData*)lParam;
        // 这里的筛选条件可能需要继续优化
        if (processId == dataPtr->processId && IsWindowVisible(hWnd) && title.length() > 0) {
            qDebug() << QString("FindWindow  title:%1, hWnd:%2, pid:%3")
                .arg(title).arg((WId)hWnd).arg(processId);
            dataPtr->hWnd = hWnd;
        }

        return TRUE;
    }

    return FALSE;
}

// 寻找特定PID的窗口句柄
HWND findWindowByPID(DWORD dwProcessId)
{
    FindWindowData winData = { dwProcessId, 0 };
    LPARAM p = (LPARAM)&winData;
    EnumWindows((WNDENUMPROC)FindWindowCB, (LPARAM)p); // 遍历系统上打开的窗口

    return winData.hWnd;
}

HWND getWinIdByPid(int pid)
{
    return findWindowByPID(pid);
}

// 测试示例
void testFunc()
{
	 // 创建进程
    QProcess* process = new QProcess(this);
    connect(process, QOverload<int>::of(&QProcess::finished), this, [=]() {
        process->close();
        process->deleteLater();
    });

    QString command = "xxx.exe";
    process->start(command);
	// 这里等待500毫秒是执行完命令等待窗口显示出来,具体时间得看程序启动的快慢;
    QThread::msleep(500);

	// 获取到pid之后通过接口转为窗口句柄;
    int pid = process->processId();
	HWND hWnd = getWinIdByPid(pid);
}

参考自 https://blog.csdn.net/joyopirate/article/details/140928311。


下方代码将获取到的窗口具体通过QWindow::fromWinId方法将窗口句柄转为QWindow对象,通过QWidget::createWindowContainer方法创建一个QWidget,可以将刚刚的窗口对象嵌入到基于QWidget的应用程序中,可以在测试方法中看到具体用法,拿到最终QWidget对象大家就可以嵌入到我们界面的布局中去了。

QWidget* getWindowContainerWgt(int pid)
{
	QWidget* pContainerWgt = nullptr;
    HWND hWnd = getWinIdByPid(pid);
    if (hWnd != nullptr) {
		pContainerWgt = new QWidget;
		// 这里也可以设置具体的大小;
		pContainerWgt->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

        QWindow* pDestWindow = QWindow::fromWinId((WId)hWnd);
        pDestWindow->setFlags(pDestWindow->flags() | Qt::CustomizeWindowHint | Qt::WindowTitleHint);
        QWidget* pChildWidget = QWidget::createWindowContainer(pDestWindow, pContainerWgt);
        pChildWidget->setObjectName("WindowContainer");

		QHBoxLayout* hLayout = new QHBoxLayout(pContainerWgt);
		hLayout->addWidget(pChildWidget);
		hLayout->setMargin(0);
    }
    else {
        qDebug() << "Can not find winId by pid";
    }

	return pContainerWgt;
}

void testFunc()
{
 	// 创建进程
    QProcess* process = new QProcess(this);
    connect(process, QOverload<int>::of(&QProcess::finished), this, [=]() {
        process->close();
        process->deleteLater();
    });

    QString command = "xxx.exe";
    process->start(command);
	// 这里等待500毫秒是执行完命令等待窗口显示出来,具体时间得看程序启动的快慢;
    QThread::msleep(500);

	// 获取到pid之后通过接口转为窗口句柄;
    int pid = process->processId();
	QWidget* windowWgt = getWindowContainerWgt(pid)
	// 如果获取到的widget不为空,说明已经成功将窗口嵌入到widget中
	if(windowWgt != nullptr){
		// todo
		// ...
	}
}

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

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

相关文章

《无机杀手》制作团队选择Blender的原因分析

《无机杀手》&#xff08;Murder Drones&#xff09;是一部备受欢迎的动画短片&#xff0c;其制作团队选择使用Blender软件进行制作&#xff0c;这一选择背后有着多方面的原因。【成都渲染101--blender渲染农场邀请码6666提供文案参考】 开源且免费 Blender是一个开源且免费的…

什么是数字化转型?数字化转型对企业有哪些优势?

一、什么是数字化转型&#xff1f; 定义&#xff1a; 数字化转型是指企业或组织将传统业务转化为数字化业务&#xff0c;利用人工智能、大数据、云计算、区块链、5G等数字技术提升业务效率和质量的过程。通俗来说&#xff0c;就是将数字技术应用到企业的各个方面&#xff0c;…

贝锐蒲公英网盘首发,秒建私有云,高速远程访问

虽然公共网盘带来了不少便利&#xff0c;但是大家对隐私泄露和重要数据泄密的担忧也随之增加。如果想要确保数据安全&#xff0c;自建私有云似乎是一条出路&#xff0c;然而面对搭建私有云的复杂步骤&#xff0c;许多人感到力不从心&#xff0c;NAS设备的成本也往往让人望而却步…

【MySQL】数据库中的内置函数

W...Y的主页 &#x1f60a; 代码仓库分享 &#x1f495; 目录 函数 日期函数 字符串函数 数学函数 ​编辑 其它函数 MySQL数据库提供了大量的内置函数&#xff0c;这些函数可以帮助你执行各种操作&#xff0c;如字符串处理、数值计算、日期和时间处理等&#xff01; 函数…

云计算Openstack Keystone

OpenStack Keystone是OpenStack平台中的一个核心组件&#xff0c;主要负责身份认证和授权管理服务。以下是关于OpenStack Keystone的详细介绍&#xff1a; 一、作用 身份认证&#xff1a;Keystone为OpenStack平台提供统一的身份认证服务&#xff0c;管理所有用户&#xff08;…

ElasticSearch系列:【Win10环境(版本8.11.1) 】elasticsearch+kibana纪实

一、环境 安装环境&#xff1a;win10 JDK&#xff1a;1.8 elasticsearch&#xff1a;8.11.1 kibana&#xff1a;8.11.1 下载地址1&#xff08;elasticsearchkibana&#xff09;&#xff1a;Past Releases of Elastic Stack Software | Elastic i下载地址2&#xff08;k分…

RS HMP4040 直流电源

R&S HMP404 直流电源 苏州新利通仪器仪表 产品综述 单台仪器中最多四个通道 R&SHMP4000 直流电源具有三个或四个输出通道&#xff0c;每个通道的输出电流高达 10 A&#xff0c;主要设计用于工业应用&#xff0c;例如&#xff1a; -生产测试 -维护 -工程实验室 这些…

关于git分支冲突问题

什么是冲突 在Git中&#xff0c;冲突是指两个或多个开发者对同一文件统一部份进行了不同的修改&#xff0c;并且在合并这些修改时&#xff0c;Git无法自动确定应该采用哪种修改而产生的情况。 分支冲突 如何出现并解决 在一个版本时&#xff0c;有一个master分支&#xff0c…

JAVA甜蜜升级情侣专属扭蛋机游戏系统小程序源码

甜蜜升级&#xff01;情侣专属扭蛋机游戏系统&#xff0c;让爱更有趣&#x1f496; &#x1f389; 开篇&#xff1a;爱的游戏新玩法 在爱情的旅途中&#xff0c;我们总在寻找那些能让彼此心跳加速、笑容满面的瞬间。现在&#xff0c;“甜蜜升级情侣专属扭蛋机游戏系统”为你和…

用友畅捷通-TPlus FileUploadHandler.ashx 任意文件上传

0x01 产品描述&#xff1a; ‌用友畅捷通-TPlus‌是由用友集团成员企业畅捷通公司开发的一款企业级财务管理工具&#xff0c;旨在帮助企业实现财务管理的现代化和智能化。作为畅捷通旗下的核心产品&#xff0c;TPlus集成了财务核算、资金管理、预算控制等多项核心功能&#xff…

spring boot 项目中redis的使用,key=value值 如何用命令行来查询并设置值。

1、有一个老项目&#xff0c;用到了网易云信&#xff0c;然后这里面有一个AppKey&#xff0c;然后调用的时候要在header中加入这些标识&#xff0c;进行与服务器进行交互。 2、开发将其存在了redis中&#xff0c;一开始的时候&#xff0c;我们测试用的老的key&#xff0c;然后提…

结合创新!小波变换+注意力机制,实现100%分类准确率

小波变换是一种先进的信号分析技术&#xff0c;它擅长捕捉信号的局部特征&#xff0c;但有时可能会忽略数据中的关键信息。为了克服这一局限&#xff0c;我们引入了注意力机制&#xff0c;这一机制能够强化模型对数据重要部分的关注。通过将小波变换与注意力机制相结合&#xf…

SD2.0 Specification之CRC(Cyclic Redundancy Code)

文章目录 本文章主要讲解关于SD2.0中的CRC应用&#xff0c;其它基础概念和其它内容请参考以下文章。 SD2.0 Specification简述 CRC全称为Cyclic Redundancy Code&#xff0c;中文名称是循环冗余校验&#xff0c;该方法通过附加冗余数据来保证数据的完整性&#xff0c;即用于检…

一类医疗器械产品分类目录 2002版

医疗医疗器械备案申请时&#xff0c;需要填写老的分类目录表&#xff08;2022版&#xff09; 在网上找了很多&#xff0c;都没有Word的&#xff0c;于是自己到官网上整理了一份分享给用到的朋友&#xff01; 下载地址&#xff1a; 一类医疗器械产品分类目录2002版资源-CSDN…

latex作者介绍添加,以及作者介绍段落间距调整(看这篇就够了)

文章目录 1.latex语句如何添加作者的介绍和照片2.作者介绍段落和段落之间的距离太大如何调整 1.latex语句如何添加作者的介绍和照片 \begin{IEEEbiography}[{\includegraphics[width1in,height1.25in,clip,keepaspectratio]{图像存放地址}}]{作者姓名} 这里写作者介绍 \end{IE…

Qt --- 界面优化 --- QSS和绘图API

界面优化 》美化 一个程序的界面是否好看&#xff0c;是否重要呢。 有些面向专业领域的程序&#xff0c;界面好看与否&#xff0c;不是看关键&#xff0c;更关键的是实际的效果。有些面向普通用户领域的程序&#xff0c;界面好看&#xff0c;还是很大的加分项。 界面优化 Qt…

基于单片机的多路温度检测系统

**单片机设计介绍&#xff0c;基于单片机CAN总线的多路温度检测系统设计 文章目录 前言概要功能设计设计思路 软件设计效果图 程序设计程序 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师&#xff0c;一名热衷于单片机技术探…

【Vue3】组件元素定义的ref属性和expose,setup返回值的关系

1、实例代码 首先一个测试结果: 1、在组件模版中元素定义的ref属性&#xff0c;会在编译阶段生成对应的props数据&#xff0c;作为参数传入到创建这个ref所在元素的vnode的方法中。 2、如果ref定义在一般的元素中&#xff0c;那么ref就指向这个元素的dom实例&#xff0c;如果re…

6.824 Lab 2C 学习记录

2C的test中的unreliable figure8算是给博主的迎头一棒&#xff0c;需要根据raft论文的figure8进行解决&#xff0c;leader无法提交不属于currentTerm的日志&#xff0c;当确定committed到当前term时才能apply。 这一步没做到时&#xff0c;报错大概率为applied error&#xff0…

leetcode 450.删除二叉搜索树中的结点

1.题目要求: 给定一个二叉搜索树的根节点 root 和一个值 key&#xff0c;删除二叉搜索树中的 key 对应的节点&#xff0c;并保证二叉搜索树的性质不变。返回二叉搜索树&#xff08;有可能被更新&#xff09;的根节点的引用。一般来说&#xff0c;删除节点可分为两个步骤&#…