C++检测多显示器并把窗口显示在不同显示器上(完整源码)

初级代码游戏的专栏介绍与文章目录-CSDN博客

        早先大部分应用都不考虑多显示的问题。

        如果是多窗口应用,子窗口不会被限制在父窗口里面的,可以轻松把窗口拖到不同的显示器上。

        但是很多流行的界面都是一个全屏主窗口,然后其他窗口都只能在主窗口范围内,这种程序就没法自动适应多显示器了。

        但是现在专门针对多显示器的需求增多了,比如视频监控类的应用,用户会很喜欢使用多显示器,像这样就需要程序支持多显示器,并且最好是自动使用多显示器而不需要用户拖放窗口。

目录

一、多显示器概要

二、获取显示器数量和坐标

三、显示窗口到副显示器

四、相关技术点

4.1 EnumDisplayDevices

4.2  EnumDisplaySettingsEx

4.3 GetSystemMetrics(SM_CMONITORS)

4.4 MFC的MoveWindow


一、多显示器概要

        多显示器共享同一个屏幕坐标空间,主显示器左上角为(0,0),其余显示器排列在其它位置,坐标可能是负值。具体如何取决于显示设置,可以用鼠标拖放显示器来控制显示器的位置关系。

        多个显示器的坐标可能会有间隔!原因是窗口最大化时阴影和边框位于显示器外面,但是又不能出现在别的显示器上,所以显示器之间有间隔。这些问题可以通过获取窗口坐标来验证。

二、获取显示器数量和坐标

        获取所有显示器信息的代码:

RECT m_ScrRect[10];
int GetScreenRect()
{int count = 0;for (int ScreenNo = 0;true; ++ScreenNo){BOOL flag;DISPLAY_DEVICE dd;ZeroMemory(&dd, sizeof(dd));dd.cb = sizeof(dd);//枚举显示器,获取后面要用的名字,注意这会返回系统所能支持的所有显示器,ScreenNo从0开始,直到返回FALSEflag = EnumDisplayDevices(NULL, ScreenNo, &dd, EDD_GET_DEVICE_INTERFACE_NAME);if (!flag){break;}DEVMODE dm;ZeroMemory(&dm, sizeof(dm));dm.dmSize = sizeof(dm);//返回当前设置,如果失败表明显示器不在线flag = EnumDisplaySettingsEx(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm, 0);if (!flag){continue;}m_ScrRect[count].left = dm.dmPosition.x;//如果副显示器在左边,则这个值是负的m_ScrRect[count].top = dm.dmPosition.y;m_ScrRect[count].right = m_ScrRect[count].left + dm.dmPelsWidth - 1;m_ScrRect[count].bottom = m_ScrRect[count].top + dm.dmPelsHeight - 1;++count;thelog << dd.DeviceName << " (dmBitsPerPel "<<dm.dmBitsPerPel <<" dmLogPixels" <<dm.dmLogPixels << ") " << dm.dmPosition.x << " " << dm.dmPosition.y << " " << dm.dmPelsWidth << " " << dm.dmPelsHeight << endi;}thelog << "检索到显示器 " << count << endi;return count;
}

        注意这段代码假设显示器最多有10个。thelog是日志,endi表示一般信息,可以用cout和endl代替。后面的测试代码会用这个函数获取多显示器信息。

        相关技术点:

  • EnumDisplayDevices 枚举系统所有的显示器,这是系统所支持的最大数量,每个都预先分配了名字
  • EnumDisplayDevices 获取显示器信息,如果显示器不存在就会返回失败,但是存在的显示器并不是连续的,所以每个都要检查

三、显示窗口到副显示器

        修改显示about对话框的代码(对话框项目),显示在副显示器上:

//这里改成了非模态对话框,用来验证多显示器支持,里面记录的奇怪的问题都是因为项目设置没有设置“每个监视器高DPI识别”导致的
CAboutDlg dlgAbout;
void CTestDlg::OnSysCommand(UINT nID, LPARAM lParam)
{if ((nID & 0xFFF0) == IDM_ABOUTBOX){//奇怪的问题,在副屏上如果已经是最大化,再次打开就会消失,但是主屏不会//计算得到的RECT和实测的不一样,实测的x似乎大一倍//由于尺寸问题,最大化可以在副屏显示,但是要先隐藏,不然再次打开就消失,而且再也不会出现if (!dlgAbout.GetSafeHwnd()){dlgAbout.Create(IDD_ABOUTBOX, this);}else { thelog << "无模式对话框已存在" << ende; }int monitors = GetSystemMetrics(SM_CMONITORS);//这个直接返回显示器个数if (GetScreenRect() != monitors){thelog << "检索显示器信息出错" << ende;}else{RECT* pMonitorRect = &m_ScrRect[monitors - 1];//取最后一个显示器RECT rect;dlgAbout.GetWindowRect(&rect);rect.right = pMonitorRect->left + rect.right - rect.left;rect.bottom = pMonitorRect->top + rect.bottom - rect.top;rect.left = pMonitorRect->left;rect.top = pMonitorRect->top;thelog << "目标 " << rect.left << " " << rect.top << " " << rect.right << " " << rect.bottom << endi;dlgAbout.MoveWindow(&rect);//很奇怪,这样就不显示,最大化就显示SW_SHOWMAXIMIZEDif (0 == dlgAbout.ShowWindow(SW_SHOW))thelog << "ShowWindow成功" << endi;else thelog << "ShowWindow已经是显示的" << ende;RECT curr;dlgAbout.GetWindowRect(&curr);thelog << "实际" << curr.left << " " << curr.top << " " << curr.right << " " << curr.bottom << endi;}if (0==dlgAbout.ShowWindow(SW_SHOW))thelog << "ShowWindow成功" << endi;else thelog << "ShowWindow已经是显示的" << ende;}else{CDialogEx::OnSysCommand(nID, lParam);}
}

        这个代码自动把窗口显示在副显示器上,并测试了放大缩小等窗口操作。

        自动显示到副显示器很简单,就是把窗口移动到副显示器的坐标范围内而已。 

        以上代码是win10+VS2017环境的。

四、相关技术点

4.1 EnumDisplayDevices

winuser.h
User32.dll/User32.libBOOL EnumDisplayDevicesA([in]  LPCSTR           lpDevice,[in]  DWORD            iDevNum,[out] PDISPLAY_DEVICEA lpDisplayDevice,[in]  DWORD            dwFlags
);

        这个函数列举所有设备,知道设备索引超出最大值。所以调用要这个函数需要一个循环,并不断递增iDevNum,直到调用失败。但每个成功返回的设备并不一定是在线的,看起来就是系统预先准备了所支持的最大数量的入口。

4.2  EnumDisplaySettingsEx

Winuser.h
User32.dll/User32.libBOOL EnumDisplaySettingsExA([in]  LPCSTR   lpszDeviceName,[in]  DWORD    iModeNum,[out] DEVMODEA *lpDevMode,[in]  DWORD    dwFlags
);

        这个函数获取具体一个显示器的信息,设备名来自之前的枚举过程,显示器不在线就会失败。系统分配显示器索引并不是连续的,所以要逐个检查之前用EnumDisplayDevices获得的有效设备名。

4.3 GetSystemMetrics(SM_CMONITORS)

Winuser.h
User32.dll/User32.libint GetSystemMetrics([in] int nIndex
);

        这个调用直接获取显示器个数,但是不能获取显示器信息。

        参数nIndex指示不同的功能,比如SM_CMOUSEBUTTONS表示鼠标按钮数量。

4.4 MFC的MoveWindow

        这个函数用来改变窗口位置。

(这里是文档结束)

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

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

相关文章

【docker】查看并拷贝容器内文件

一、查询容器 查询所有容器 docker ps查询名为os11的容器 docker ps | grep os11查询名为os11的容器&#xff08;包含不运行的&#xff09; docker ps -a| grep os11 docker ps [option] 显示结果介绍如下&#xff1a; 参考&#xff1a;[https://blog.51cto.com/u_15009374/31…

Linux离线部署gitLab及使用教程

一、下载gitLab的linux系统rpm包 地址&#xff1a;Index of /gitlab-ce/yum/el7/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 找到这个最新版 点击下载 二、上传到linux系统 笔者是在windows系统下的vmware虚拟机中部署安装的&#xff0c;虚拟机中安装了cent…

腾讯在GDC 2024展示GiiNEX AI游戏引擎现已投入《元梦之星》中开发使用,展示强大AIGC能力

在近日举行的GDC 2024游戏开发者大会上&#xff0c;腾讯揭开了其AI Lab团队精心打造的GiiNEX AI游戏引擎的神秘面纱。这款引擎依托先进的生成式AI和决策AI技术&#xff0c;为游戏行业带来了革命性的变革。 相关阅读&#xff1a;腾讯游戏出品&#xff01;腾讯研效AIGC&#xff…

【DataWhale学习】用免费GPU线上跑chatGLM、SD项目实践

用免费GPU线上跑chatGLM、SD项目实践 ​ DataWhale组织了一个线上白嫖GPU跑chatGLM与SD的项目活动&#xff0c;我很感兴趣就参加啦。之前就对chatGLM有所耳闻&#xff0c;是去年清华联合发布的开源大语言模型&#xff0c;可以用来打造个人知识库什么的&#xff0c;一直没有尝试…

分别使用TCP/UDP实现互相实时发送消息,接收消息功能

什么是TCP? TCP(传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层协议。它是互联网协议套件中的一部分,用于在网络上可靠地传输数据。TCP协议的主要特点包括: 面向连接:在TCP通信中,通信双方在通信之前必须先建立连接。连接建立后,数据传输完成后还需要显式…

Apache James数据库存储用户信息的密码加密问题

项目场景 Apache James邮件服务器使用数据库来存储用户信息的密码加密问题&#xff1a; 将James的用户改为数据库存储James密码是如何加密验证的 1.将James的用户改为数据库存储 1、修改存储方式 找到james-2.3.2\apps\james\SAR-INF\config.xml 找到<users-store>标…

elementUI(Vue2)和elementPlus(Vue3)图标icon差异

Vue2用法 <i class"el-icon-edit"></i><el-button type"primary" icon"el-icon-search">搜索</el-button> Vue3用法 <!-- 使用 el-icon 为 SVG 图标提供属性 --> <template><div><el-icon :siz…

Python的re模块进行正则表达式操作时的常用方法[回顾学习]

re 模块是 Python 中用于处理正则表达式的标准库模块。通过 re 模块&#xff0c;可进行字符串匹配、搜索和替换等各种操作。 有几个常用的方法&#xff1a;# re.match(pattern, string)&#xff1a;从字符串开头开始匹配模式&#xff0c;并返回匹配对象。适合用于确定字符串是否…

Doris的3种数据模型详解和数据仓库每一层的模型选用

Apache Doris是一个用于离线数据仓库开发的分布式SQL查询和分析引擎。在使用Doris进行离线数据仓库开发时,可以采用三种不同的数据模型:Duplicate模型、Aggregate模型和Unique模型。每种模型都有其适用的场景和特点,同时也对于不同层次的数据仓库有着不同的使用建议。 Dupl…

Python爬虫入门教程:从零开始学习网络数据采集(零基础入门,小白看的懂)

随着互联网的快速发展&#xff0c;数据成为了信息时代的核心。而网络爬虫&#xff08;Web Scraper&#xff09;作为一种自动化采集网络数据的工具&#xff0c;在数据获取和分析领域发挥着重要作用。Python作为一种简单易学、功能丰富的编程语言&#xff0c;被广泛用于编写网络爬…

HarmonyOS实战开发-编写一个分布式邮件系统

概述 本篇Codelab是基于TS扩展的声明式开发范式编程语言编写的一个分布式邮件系统&#xff0c;可以由一台设备拉起另一台设备&#xff0c;每次改动邮件内容&#xff0c;都会同步更新两台设备的信息。效果图如下&#xff1a; 说明&#xff1a; 本示例涉及使用系统接口&#xff…

深度学习之分层时间记忆(Hierarchical Temporal Memory,HTM)附代码解析

介绍 分层时间记忆(Hierarchical Temporal Memory,HTM)是一种基于神经科学原理的机器学习模型,用于处理时间序列数据,它模拟了大脑皮层中的一些关键特征。HTM模型由Numenta公司的研究人员Jeff Hawkins等人提出,旨在模拟大脑皮层的工作原理。 HTM模型的核心概念是将信息…

【数据结构】——排序之冒泡排序

&#x1f49e;&#x1f49e; 前言 hello hello~ &#xff0c;这里是大耳朵土土垚~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f4a5;个人主页&#x…

视频讲解|基于非对称纳什谈判的多微网电能共享运行优化策略

1 主要内容 该讲解视频对应的程序链接为基于非对称纳什谈判的多微网电能共享运行优化策略_吴锦领&#xff0c;主要内容是对《基于非对称纳什谈判的多微网电能共享运行优化策略》的matlab复现&#xff0c;解决的是微网间基于非对称纳什谈判的P2P电能交易共享问题&#xff0c;基…

SpringBoot接口防止重复提交(AOP+Redis)

方法一&#xff1a; 若依框架的实现 【具体靠请求地址URL参数列表来判断请求是否重复】 SpingBoot接口防止重复提交_springboot接口防抖(防重复提交)的一些实现方案-CSDN博客文章浏览阅读518次。3.根据缓存键获取缓存中对象&#xff0c;如果存在&#xff0c;判断当前请求参…

利用scipy求解方程组、拟合直线、圆、椭圆、抛物线

scipy.optimize作为优化模块可以实现任意曲线拟合&#xff0c;方程求根、非线性方程组求解、自定义代价函数求解等功能&#xff0c;下面给出了optimize中常用的几个子模块&#xff1a; minimize&#xff1a;需要自己构建代价函数&#xff08;有时也称损失函数&#xff0c;目标函…

MATLAB中的数学建模:基础知识、实例与方法论

前言 在当今科技高速发展的时代&#xff0c;数学建模成为了解析复杂世界的关键工具&#xff0c;而MATLAB作为一种专业的科学计算软件&#xff0c;为我们提供了强大的数学建模平台。MATLAB不仅仅是Matrix Laboratory的简称&#xff0c;更是一个集数值分析、矩阵计算、算法开发和…

【C#】C#踩坑三角函数之uvw平台

背景 最近再弄一个uvw平台&#xff0c;uvw平台厂商会提供一个公式里面用到了三角函数&#xff1a; 踩坑记录 一开始&#xff0c;我以为Math.Cos参数是度数&#xff0c;所以怎么算都不对! 一度怀疑C#的Math库。 后面才意识到&#xff0c;这个参数会不会是弧度&#xff1f;结…

携程20240320java暑假实习面经

1. 自我介绍 2. 多久开始学java的 3. ConcurrentHashMap 怎么保证线程安全 1.7 与 1.8 4. 讲一讲你对线程池的理解&#xff0c; 并讲一讲使用的场景 5. 单例模式 如何线程安全 6. 有哪些垃圾回收器 选一个讲一下垃圾回收的流程 7. 讲一讲mysql 的索引 &#xff0c; 如…

我的电脑win11系统安装了谷歌浏览器,桌面的快捷方式打不开

安装好浏览器以后双击打不开右键打开文件位置也弹窗报错提示 但是我发现开始栏里面可以打开 说明我的软件应该是没有问题的&#xff0c;研究了一下 我实际的安装目录在&#xff1a;C:\Program Files\Google\Chrome\Application 桌面的快捷方式右键查看属性显示的地址却不对&a…