Electron 中创建透明窗口

在开发 Electron 应用时,可能需要创建完全透明的窗口,比如我们要做一个屏幕内容共享的功能,在特定矩形区域内的内容才会被共享出来,而这个区域是一个透明且可被穿透的区域。

首先我们需要再主进程上创建一个矩形窗口

const screenRegionShareWindow = new BrowserWindow({width: 800,height: 600,// 关键!创建无边框窗口,没有窗口的某些部分(例如工具栏、控件等)frame: false,// 关键!创建一个完全透明的窗口transparent: true,minHeight: Math.ceil(workAreaSize.height * 0.3),minWidth:  Math.ceil(workAreaSize.width * 0.3),// 窗口可移动movable: true,// 窗口可调整大小resizable: true,// 窗口不能最小化minimizable: false,// 窗口不能最大化maximizable: false,// 窗口不能进入全屏状态fullscreenable: false,// 窗口不能关闭closable: true,webPreferences: {nodeIntegration: true,contextIsolation: false // 否则页面无法用require}});

共享区域的窗口一定是透明的、可移动的、并且没有边框、可调整大小,但不能最小化和最大化,也不能进入全屏状态,窗口也不能在程序坞中关闭。

实现点击穿透

要创建一个点击穿透窗口,也就是使窗口忽略所有鼠标事件,可以调用 win.setIgnoreMouseEvents(ignore) API

screenRegionShareWindow.setIgnoreMouseEvents(true)

设置可拖动元素

默认情况下, 无边框窗口是不可拖拽的。 应用程序需要在 CSS 中指定 -webkit-app-region: drag 来告诉 Electron 哪些区域是可拖拽的(如操作系统的标准标题栏)在可拖拽区域内部使用 -webkit-app-region: no-drag 则可以将其中部分区域排除。

要使整个窗口可拖拽, 您可以添加 -webkit-app-region: drag 作为 body 的样式:

body {-webkit-app-region: drag;
}

前端部分实现如下:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><style>html,body {margin: 0;padding: 0;background: transparent;}.container {margin: 0px;padding: 0px;width: 100vw;height: 100vh;pointer-events: none;position: relative;background: transparent;}.line {background: #3876ff;-webkit-app-region: drag;cursor: move;position: absolute;pointer-events: auto;}.line1 {height: 24px;top: 0;left: 0;right: 0;}.line2 {height: 4px;bottom: 0;left: 0;right: 0;}.line3 {width: 4px;bottom: 0;left: 0;top: 0;}.line4 {width: 4px;bottom: 0;right: 0;top: 0;}#center {position: absolute;left: 4px;bottom: 4px;right: 4px;top: 24px;pointer-events: auto;}</style><body><div class="container"><div class="line line1"></div><div class="line line2"></div><div class="line line3"></div><div class="line line4"></div><div id="center"></div></div></body><script>const $ = document.querySelector.bind(document);const centerElm = $('#center');const ipcRenderer = require('electron').ipcRenderer;centerElm.addEventListener('mouseenter',() => {console.log('enter');ipcRenderer.send('ignoreMouseEvent', true);},false);centerElm.addEventListener('mouseleave',() => {console.log('leave');ipcRenderer.send('ignoreMouseEvent', false);},false);</script>
</html>

主进程代码:

ipcMain.on('ignoreMouseEvent',(event, ignore)=>{if(ignore){screenRegionShareWindow?.setIgnoreMouseEvents(true, { forward: true });}else{screenRegionShareWindow?.setIgnoreMouseEvents(false);}
});

上面代码我们设置了鼠标进入的时候只有点击事件会穿透窗口,鼠标移动事件仍会触发(forward: true的作用),当鼠标离开窗口后就不再忽略鼠标事件。

除此之外,我们还在 CSS 上的透明区域(.container)禁用鼠标事件,该元素就永远不会成为鼠标事件的target了,而给 .line.center 部分设置 pointer-events: auto; 让它们还可以成为鼠标事件的 target。

.line 是窗口的边框,并且设置 -webkit-app-region: drag; 让四周的边框可以拖动并且跟随鼠标移动。

.center 元素设置 pointer-events: auto; 可以监听到鼠标事件,由因为我们设置了点击穿透,因此鼠标事件会被传递到此窗口下面的窗口。

计算共享区域的大小

当窗口移动或者调整矩形区域大小时,我们需要更新窗口位置,然后获取新的屏幕像素信息。

核心代码:

function getContentWindowPhysicalRect() {let rect = { x: 0, y: 0, width: 0, height: 0 };if (screenRegionShareWindow) {const { x, y, width, height } = screenRegionShareWindow.getContentBounds();rect = screen.dipToScreenRect(null, {x: Math.ceil(x + 4) + 1,y: Math.ceil(y + 24) + 1,width: Math.floor(width - 8) - 1,height: Math.floor(height - 28) - 1,});}return rect;
}

首先调用 getContentBounds() API 获取到窗口的位置和大小,然后调用 dipToScreenRect 将屏幕DIP(设备独立像素)矩阵转换为屏幕物理矩阵。
可以把 DIP 的单位理解为浏览器中的 px,如果屏幕像素比(DPR)是2,则代表 1px = 2个物理像素,用 dipToScreenRect 转了之后 rect 中的值会变大。

然后就是窗口移动或者缩放时调用 getContentWindowPhysicalRect 即可。

screenRegionShareWindow.on('resized', () => {updateContentRegion();
});screenRegionShareWindow.on('moved', () => {updateContentRegion();
});// 移动之前,应该先把共享暂停,然后 moved 之后再更新共享区域
screenRegionShareWindow.on('will-move', () => {mainWindow?.webContents.send('regionSharingWindowWillChange');
});screenRegionShareWindow.on('will-resize', () => {mainWindow?.webContents.send('regionSharingWindowWillChange');
});

移动或者更新窗口大小之前,应该先把共享暂停,然后 moved/resized 之后再更新共享区域,不然在移动的时候在共享画面那能看到边框。

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

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

相关文章

简单电子报警器设计与制作方法

简单电子报警器设计与制作方法 注&#xff1a; 1、按上图连接好。 2、改变R&#xff58;的大小即使基极电路的电流发生改变&#xff0c;使频率发生改变。 3、增大电容&#xff0c;有利于低音向第一个三极管的基极反馈&#xff0c;因此最终 输出频率变低。 4、R2处接光敏电阻…

数据结构和算法-AOV与AOE网络和(逆)拓扑排序与关键路径

文章目录 AOV网络拓扑排序代码实现时间复杂度 逆拓扑排序实现DFS算法实现逆拓扑排序小结 AOE网络关键路径求关键路径求事件最早发生时间求事件最迟发生时间求活动最早发生时间求活动最迟发生时间求活动余量 关键活动 关键路径的特性小结 AOV网络 必须是DAG图&#xff08;有向无…

Microsoft刷题记录

PASS区 串联字符串的最大长度通知所有员工所需的时间单词搜索 PASS但非最优 合并区间实现 Trie (前缀树) 非PASS区 将石头分散到网格图的最少移动次数去除重复字母和为K的子数组颜色分类 注意 dfs 应该是i1&#xff0c;而不是idx1&#xff0c;老容易写错

本科论文降重修改技巧 神码ai

大家好&#xff0c;今天来聊聊本科论文降重修改技巧&#xff0c;希望能给大家提供一点参考。 以下是针对论文重复率高的情况&#xff0c;提供一些修改建议和技巧&#xff0c;可以借助此类工具&#xff1a; 本科论文降重修改技巧 对于本科论文的写作&#xff0c;降重修改是一个…

C++ I/O操作---输入输出

本文主要介绍C I/O操作中的输入输出流。 目录 1 输入输出 2 输入输出流分类 3 C中的输入输出流 4 iostream 5 std::ofstream 6 std::fstream 7 std::getline 1 输入输出 C的输入输出是数据在不同设备之间的传输&#xff0c;即在硬盘、内存和外设之间的传输。 数据如水流…

飞天使-docker知识点6-容器dockerfile各项名词解释

文章目录 docker的小技巧dockerfile容器为什么会出现启动了不暂停查看docker 网桥相关信息 docker 数据卷 docker的小技巧 [rootlight-test playbook-vars[]# docker inspect -f "{{.NetworkSettings.IPAddress}}" d3a9ae03ae5f 172.17.0.4docker d3a9ae03ae5f:/etc…

【idea】解决sprintboot项目创建遇到的问题

目录 一、报错Plugin ‘org.springframework.boot:spring-boot-maven-plugin:‘ not found 二、报错java: 错误: 无效的源发行版&#xff1a;17 三、java: 无法访问org.springframework.web.bind.annotation.CrossOrigin 四、整合mybatis的时候&#xff0c;报java.lang.Ill…

电子元器件介绍——二极管(四)

电子元器件介绍 文章目录 电子元器件介绍前言一、二极管的基础知识二、二极管的分类三、二极管的应用总结 前言 这一节我们看一下二极管。 一、二极管的基础知识 PN结&#xff1a;是指一块半导体单晶&#xff0c;其中一部分是P型区&#xff0c;其余部分是N型区。 在电场作用…

听GPT 讲Rust源代码--src/tools(14)

File: rust/src/tools/rust-analyzer/crates/cfg/src/lib.rs 在Rust源代码中&#xff0c;rust/src/tools/rust-analyzer/crates/cfg/src/lib.rs这个文件是Rust语言分析器&#xff08;Rust Analyzer&#xff09;的一部分&#xff0c;用于处理和管理条件编译指令&#xff08;Cond…

打破涨粉瓶颈!如何通过视频号找热门话题?

如果你正在运营视频号&#xff0c;相信你一定会遇到这样的瓶颈&#xff0c;视频号播放不理想&#xff0c;牟足劲想涨几个粉丝&#xff0c;结果还掉粉了&#xff1f;今天我们就聊聊如何通过视频号找热门话题! 当你的播放和粉丝增长停滞 数据不好的的时候需要更新迭代 同时还需…

DeciLM-7B:突破极限,高效率、高精准度的70亿参数AI模型

引言 在人工智能领域&#xff0c;语言模型的发展速度令人瞩目。Deci团队最近推出了一款具有革命性意义的语言模型——DeciLM-7B。这款模型在速度和精确度上都实现了显著的突破&#xff0c;以其70亿参数的规模&#xff0c;在语言模型的竞争中脱颖而出。 Huggingface模型下载&am…

数据库通用语法DML-MySQL

DML&#xff08;数据操作语言&#xff09; 添加数据 指定字段&#xff1a; INSERT INTO 表名 (字段名1, 字段名2, ...) VALUES (值1, 值2, ...); 全部字段&#xff1a; INSERT INTO 表名 VALUES (值1, 值2, ...); 批量添加数据&#xff1a; INSERT INTO 表名 (字段名1, 字段…

torch中张量与数据类型的介绍

PyTorch张量的定义介绍 PyTorch最基本的操作对象是张量&#xff0c;它表示一个多维数组&#xff0c;类似NumPy的数组&#xff0c;但是前者可以在GPU上加速计算 初始化张量 ttorch.tensor([1,2]) # 创建一个张量 print(t) t.dtype #打印t的数据类型为torch.int…

尺度函数与小波函数

尺度函数与小波函数 尺度函数 设存在函数 φ j , k ( x ) 2 j / 2 φ ( 2 j x − k ) \varphi_{j,k}(x)2^{j/2}\varphi(2^{j}x-k) φj,k​(x)2j/2φ(2jx−k) 对所有的 j j j, k ∈ Z k{\in}\mathbb{Z} k∈Z 和 φ ( x ) ∈ L 2 ( R ) \varphi(x){\in}L^2(R) φ(x)∈L2(R)…

为什么Apache Doris适合做大数据的复杂计算,MySQL不适合?

为什么Apache Doris适合做大数据的复杂计算&#xff0c;MySQL不适合&#xff1f; 一、背景说明二、DB架构差异三、数据结构差异四、存储结构差异五、总结 一、背景说明 经常有小伙伴发出这类直击灵魂的疑问&#xff1a; Q&#xff1a;“为什么Apache Doris适合做大数据的复杂计…

大数据与深度挖掘:如何在数字营销中与研究互动

数字营销最吸引人的部分之一是对数据的内在关注。 如果一种策略往往有积极的数据&#xff0c;那么它就更容易采用。同样&#xff0c;如果一种策略尚未得到证实&#xff0c;则很难获得支持进行测试。 数字营销人员建立数据信心的主要方式是通过研究。这些研究通常分为两类&…

【教3妹学编程-算法题】找出峰值

3妹&#xff1a;2哥2哥&#xff0c;你有没有看到新闻&#xff1a;北京地铁事故中102人骨折&#xff01; 2哥 : 看到了&#xff0c;没想到坐个地铁还出事故了。 3妹&#xff1a;事故原因为雪天轨滑导致前车信号降级&#xff0c;紧急制动停车&#xff0c;后车因所在区段位于下坡地…

二维数组——特征匹配(c++)

右上左下遍历 给定一个n行m列的整数数组a&#xff0c;要求从a[0][0] 元素开始&#xff0c;按从右上到左下的对角线顺序遍历整个数组。 输出 按遍历顺序输出每个整数。每个整数占一行。 样例输入 3 3 1 2 4 3 5 7 6 8 9 样例输出 1 2 4 3 5 7 6 8 9 #include <iostream&g…

【️Java是值传递还是引用传递?】

✅Java是值传递还是引用传递&#xff1f; ✅Java是值传递还是引用传递&#xff1f;✅典型理解 ✅增加知识仓✅Java的求值策略✅Java中的对象传递✅值传递和共享对象传递的现象冲突吗? ✅总结 ✅Java是值传递还是引用传递&#xff1f; ✅典型理解 编程语言中需要进行方法间的…

一句话分清C/C++声明和定义

定义告诉编译器在在哪个位置存储变量&#xff0c;声明没有 声明&#xff1a;告诉编译器&#xff0c;变量类型和名字 定义&#xff1a;告诉编译器变量存储的位置。 举例子 int i; // 这是声明定义。声明&#xff1a;告诉编译器变量类型int,变量名字i&#xff0c; // 定义&…