【Python】实现一个类似于Glass2k的Windows窗口透明化软件

一 背景说明

        网上看到一款Windows下的窗口透明化工具Glass2k(Glass2k官网),可以简单地通过快捷键实现任意窗口的透明化,还挺方便的,想用Python自己实现一下类似的功能。

        软件已经开源到:窗口透明化小工具开源地址

        效果图如下:

二 设计实现

        工具包含以下几个模块:

        【1】用 tkinter 类实现工具的界面;

        【2】用 pystray 类实现工具最小化托盘的功能;

        【3】用pynput 类实现键盘快捷键的监听功能;

        【4】用ctypes 类实现Windows窗口透明化操作;

三 功能编写

        用GUI类包含设计中的几种功能:

【1】初始化中实现工具的主界面:

def __init__(self):self.root = tk.Tk()self.root.title('窗口透明化工具')self.root.geometry("400x90")# 当用户点击窗口右上角的关闭按钮时,Tkinter将自动发送WM_DELETE_WINDOW关闭事件。通过对其进行处理并调用self.hide_window()方法,可以改为将窗口隐藏到系统托盘中。# 该方法用于将程序窗口隐藏到系统托盘中而非直接退出应用程序self.root.protocol('WM_DELETE_WINDOW', self.hide_window)# 添加菜单和图标self.create_systray_icon()# 绘制界面frame1 = tk.Frame(self.root)frame1.pack(side='top')l1 = tk.Label(frame1,text='【窗口透明化操作】点击窗口,按Ctrl + Alt + [0-9]使其透明化。\nCtrl + Alt + 1:全透明\nCtrl + Alt + 5:半透明\nCtrl + Alt + 0:全填充\n')l1.pack()# 开启键盘监听t = threading.Thread(target=self.new_thread_start)# 开启守护线程,这样在GUI意外关闭时线程能正常退出t.setDaemon(True)t.start()

【2】最小化托盘包括:创建最小化托盘图标/隐藏窗口/打开窗口/退出程序 几个方法:

"""
[1]最小化托盘
"""
def create_systray_icon(self):# 使用 Pystray 创建系统托盘图标menu = (pystray.MenuItem('显示', self.show_window, default=True),pystray.Menu.SEPARATOR,  # 在系统托盘菜单中添加分隔线pystray.MenuItem('退出', self.quit_window))image = Image.open("TPWin.ico")self.icon = pystray.Icon("icon", image, "图标名称", menu)threading.Thread(target=self.icon.run, daemon=True).start()def hide_window(self):# 关闭窗口时隐藏窗口,并将 Pystray 图标放到系统托盘中self.root.withdraw()def show_window(self):# 打开主窗口self.icon.visible = Trueself.root.deiconify()def quit_window(self, icon: pystray.Icon):# 退出程序icon.stop()  # 停止 Pystray 的事件循环self.root.quit()  # 终止 Tkinter 的事件循环self.root.destroy()  # 销毁应用程序的主窗口和所有活动

【3】键盘的监听包括:监听键盘点击/监听键盘释放/启动监听线程 几个方法,其中组合键用一个无序不重复元素集来管理:

"""
[2]键盘操作
"""
def on_key_press(self, key):if key == keyboard.Key.alt_l or key == keyboard.Key.alt_gr:keys.add('Alt')elif key == keyboard.Key.ctrl_l or key == keyboard.Key.ctrl_r:keys.add('Ctrl')elif str(key) == r"<48>":   # ctrl + 0组合键keys.add('0')elif str(key) == r"<49>":   # ctrl + 1组合键keys.add('1')elif str(key) == r"<50>":   # ctrl + 2组合键keys.add('2')elif str(key) == r"<51>":   # ctrl + 3组合键keys.add('3')elif str(key) == r"<52>":   # ctrl + 4组合键keys.add('4')elif str(key) == r"<53>":   # ctrl + 5组合键keys.add('5')elif str(key) == r"<54>":   # ctrl + 6组合键keys.add('6')elif str(key) == r"<55>":   # ctrl + 7组合键keys.add('7')elif str(key) == r"<56>":   # ctrl + 8组合键keys.add('8')elif str(key) == r"<57>":   # ctrl + 9组合键keys.add('9')if all(k in keys for k in ['Alt', 'Ctrl', '0']):self.set_transparency(0)elif all(k in keys for k in ['Alt', 'Ctrl', '1']):self.set_transparency(1)elif all(k in keys for k in ['Alt', 'Ctrl', '2']):self.set_transparency(2)elif all(k in keys for k in ['Alt', 'Ctrl', '3']):self.set_transparency(3)elif all(k in keys for k in ['Alt', 'Ctrl', '4']):self.set_transparency(4)elif all(k in keys for k in ['Alt', 'Ctrl', '5']):self.set_transparency(5)elif all(k in keys for k in ['Alt', 'Ctrl', '6']):self.set_transparency(6)elif all(k in keys for k in ['Alt', 'Ctrl', '7']):self.set_transparency(7)elif all(k in keys for k in ['Alt', 'Ctrl', '8']):self.set_transparency(8)elif all(k in keys for k in ['Alt', 'Ctrl', '9']):self.set_transparency(9)def on_key_release(self, key):if key == keyboard.Key.alt_l or key == keyboard.Key.alt_gr:keys.remove('Alt')elif key == keyboard.Key.ctrl_l or key == keyboard.Key.ctrl_r:keys.remove('Ctrl')elif str(key) == r"<48>":  # ctrl + 0组合键keys.remove('0')elif str(key) == r"<49>":  # ctrl + 1组合键keys.remove('1')elif str(key) == r"<50>":  # ctrl + 2组合键keys.remove('2')elif str(key) == r"<51>":  # ctrl + 3组合键keys.remove('3')elif str(key) == r"<52>":  # ctrl + 4组合键keys.remove('4')elif str(key) == r"<53>":  # ctrl + 5组合键keys.remove('5')elif str(key) == r"<54>":  # ctrl + 6组合键keys.remove('6')elif str(key) == r"<55>":  # ctrl + 7组合键keys.remove('7')elif str(key) == r"<56>":  # ctrl + 8组合键keys.remove('8')elif str(key) == r"<57>":  # ctrl + 9组合键keys.remove('9')if key == keyboard.Key.esc:return False  # 释放了esc 键,停止监听def new_thread_start(self):key_listen_thread = keyboard.Listener(on_press=self.on_key_press, on_release=self.on_key_release)# 运行线程key_listen_thread.start()

【4】设置透明度的操作包括:设置透明度/获取当前鼠标位置(获取窗口句柄用):

"""
[3]设置透明度操作(Ctrl + Alt + [0-9])
"""
def set_transparency(self, set_tp):global hwndhwnd = ctypes.windll.user32.WindowFromPoint(self.get_mouse_position())  # 获取窗口句柄p = create_string_buffer(256)windll.user32.GetWindowTextW(hwnd, byref(p), 256)  # 获取窗口标题title = str(p.raw, encoding='utf-16').strip('\x00')exstyle = windll.user32.GetWindowLongA(hwnd, GWL_EXSTYLE)exstyle |= WS_EX_LAYERED  # 使窗口具有能设置透明度的样式windll.user32.SetWindowLongA(hwnd, GWL_EXSTYLE, exstyle)    # 获取窗口名if set_tp == 0:alpha = 255else:alpha = set_tp * 25windll.user32.SetLayeredWindowAttributes(hwnd, 0, alpha, LWA_ALPHA) # 设置透明度print('窗口 ' + title + ' 透明度设置为 ' + str(set_tp) + '\n')def get_mouse_position(self):point = ctypes.wintypes.POINT()ctypes.windll.user32.GetCursorPos(ctypes.byref(point))return point

四 程序整合

        将上述功能整合:

import ctypes.wintypes
import threading
import tkinter as tk
import pystray
from PIL import Image
from pynput import keyboard
from ctypes import *WM_CLOSE = 0x10
WM_SETTEXT = 0x0c
GWL_STYLE = -16
GWL_EXSTYLE = -20
SW_MINIMIZE = 6
SW_MAXIMIZE = 3
SW_RESTORE = 9
WS_BORDER = 0x800000
WS_CAPTION = 0xC00000 # WS_BORDER Or WS_DLGFRAME
WS_CHILD = 0x40000000
WS_CLIPCHILDREN = 0x2000000
WS_CLIPSIBLINGS = 0x4000000
WS_POPUP = 0x80000000
WS_DLGFRAME = 0x400000
WS_DISABLED = 0x8000000
WS_OVERLAPPEDWINDOW = 0xcf0000
WS_THICKFRAME = 0x40000
WS_VISIBLE = 0x10000000
WS_EX_APPWINDOW = 0x40000
WS_EX_DLGMODALFRAME = 0x1
WS_EX_ACCEPTFILES = 0x10
WS_EX_CLIENTEDGE= 0x200
WS_EX_TOOLWINDOW = 0x80
WS_EX_WINDOWEDGE = 0x100
LWA_ALPHA = 0x2;LWA_COLORKEY=0x1
WS_EX_LAYERED = 0x80000keys = set()
hwnd = 0    # 窗口句柄class GUI:def __init__(self):#初始化窗口"""[1]最小化托盘""""""[2]键盘操作""""""[3]设置透明度操作(Ctrl + Alt + [0-9])"""if __name__ == '__main__':# 主界面TKDemo = GUI()TKDemo.root.mainloop()

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

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

相关文章

【Leetcode】889. 根据前序和后序遍历构造二叉树

文章目录 题目思路代码结果 题目 题目链接 给定两个整数数组&#xff0c;preorder 和 postorder &#xff0c;其中 preorder 是一个具有 无重复 值的二叉树的前序遍历&#xff0c;postorder 是同一棵树的后序遍历&#xff0c;重构并返回二叉树。 如果存在多个答案&#xff0c;…

CSS基础属性

【三】基础属性 【1】高度和宽度 &#xff08;1&#xff09;参数 width&#xff08;宽度&#xff09;&#xff1a;用于设置元素的宽度。可以使用具体的数值&#xff08;如像素值&#xff09;或百分比来指定宽度。 height&#xff08;高度&#xff09;&#xff1a;用于设置元…

Kubernetes 卷存储 NFS | nfs搭建配置 原理介绍 nfs作为存储卷使用

目录 1、NFS介绍2、NFS服务部署2.1安装nfs服务 (服务端配置)2.2启动NFS服务2.3 服务检查2.4 客户端配置 3、nfs作为存储卷使用3.1 nfs作为volume3.2 nfs存储的缺点3.3 nfs作为PersistentVolum 4、nfs作为动态存储提供5、总结 1、NFS介绍 NFS&#xff08;Network File System&a…

4.pom文件介绍Maven常用命令

1.pom.xml文件介绍. 1.1project标签和modelVersion标签介绍. pom.xml文件是maven的核心文件&#xff0c;POM(Project Object Model&#xff0c;项目对象模型)定义了项目的基本信息&#xff0c;用于描述如何构建&#xff0c;声明项目依赖;&#xff1b; 1.2依赖坐标介绍. 依赖的…

得物面试:Kafka消息0丢失,如何实现?

得物面试&#xff1a;Kafka消息0丢失&#xff0c;如何实现&#xff1f; 尼恩说在前面 在40岁老架构师 尼恩的读者交流群(50)中&#xff0c;最近有小伙伴拿到了一线互联网企业如得物、阿里、滴滴、极兔、有赞、希音、百度、网易、美团的面试资格&#xff0c;遇到很多很重要的面…

新版Java面试专题视频教程——多线程篇②

新版Java面试专题视频教程——多线程篇② 0. 问题汇总0.1 线程的基础知识0.2 线程中并发安全0.3 线程池0.4 使用场景 1.线程的基础知识2.线程中并发锁3.线程池3.1 说一下线程池的核心参数&#xff08;线程池的执行原理知道嘛&#xff09;3.2 线程池中有哪些常见的阻塞队列Array…

虚拟机的内存结构

一、摘要 熟悉 Java 语言特性的同学都知道&#xff0c;相比 C、C 等编程语言&#xff0c;Java 无需通过手动方式回收内存&#xff0c;内存中所有的对象都可以交给 Java 虚拟机来帮助自动回收&#xff1b;而像 C、C 等编程语言&#xff0c;需要开发者通过代码手动释放内存资源&…

MedicalGPT 训练医疗大模型,实现了包括增量预训练、有监督微调、RLHF(奖励建模、强化学习训练)和DPO(直接偏好优化)

MedicalGPT 训练医疗大模型&#xff0c;实现了包括增量预训练、有监督微调、RLHF(奖励建模、强化学习训练)和DPO(直接偏好优化)。 MedicalGPT: Training Your Own Medical GPT Model with ChatGPT Training Pipeline. 训练医疗大模型&#xff0c;实现了包括增量预训练、有监督微…

Linux第63步_为新创建的虚拟机添加必要的目录和安装支持linux系统移植的软件

1、创建必要的目录 1)、创建“/home/zgq/linux/”目录 打开终端&#xff0c;进入“/home/zgq/”目录 输入“mkdir linux回车”&#xff0c;创建“/home/zgq/linux/”目录 输入“ls回车”&#xff0c;列举“/home/zgq/”目录的所有文件和文件夹 创建好“/home/zgq/linux/”…

Go 中的 init 如何用?它的常见应用场景有哪些呢?

嗨&#xff0c;大家好&#xff01;我是波罗学。本文是系列文章 Go 技巧第十六篇&#xff0c;系列文章查看&#xff1a;Go 语言技巧。 Go 中有一个特别的 init() 函数&#xff0c;它主要用于包的初始化。init() 函数在包被引入后会被自动执行。如果在 main 包中&#xff0c;它也…

QT基本组件

四、基本组件 Designer 设计师&#xff08;重点&#xff09; Qt包含了一个Designer程序&#xff0c;用于通过可视化界面设计开发界面&#xff0c;保存文件格式为.ui&#xff08;界面文件&#xff09;。界面文件内部使用xml语法的标签式语言。 在Qt Creator中创建文件时&#xf…

滚雪球学Java(67):深入理解 TreeMap:Java 中的有序键值映射表

咦咦咦&#xff0c;各位小可爱&#xff0c;我是你们的好伙伴——bug菌&#xff0c;今天又来给大家普及Java SE相关知识点了&#xff0c;别躲起来啊&#xff0c;听我讲干货还不快点赞&#xff0c;赞多了我就有动力讲得更嗨啦&#xff01;所以呀&#xff0c;养成先点赞后阅读的好…

机器人内部传感器阅读笔记及心得-位置传感器-旋转变压器、激光干涉式编码器

旋转变压器 旋转变压器是一种输出电压随转角变化的检测装置&#xff0c;是用来检测角位移的&#xff0c;其基本结构与交流绕线式异步电动机相似&#xff0c;由定子和转子组成。 旋转变压器的原理如图1所示&#xff0c;定子相当于变压器的一次侧&#xff0c;有两组在空间位置上…

MyBatis-Plus 优雅实现数据加密存储

文章目录 前言一、数据库字段加解密实现1. 定义加密类型枚举2. 定义AES密钥和偏移量3. 配置定义使用的加密类型4. 加密解密接口5. 解密解密异常类6. 加密解密实现类6.1 AES加密解密实现类6.2 Base64加密解密实现类 7. 实现数据库的字段保存加密与查询解密处理类8. MybatisPlus配…

Selenium安装与配置

文章目录 一、selenium安装1. Python环境准备&#xff1a;2. 安装Selenium&#xff1a;3. 浏览器驱动安装&#xff1a;4. 验证安装&#xff1a; 二、常见问题1. Selenium版本与浏览器驱动程序不兼容&#xff1a;2. 浏览器驱动程序路径未正确设置&#xff1a; Selenium是一个用于…

2024年1月手机市场行业分析:苹果手机份额骤降,国产高端手机成功逆袭!

小米Ultra发布。 一方面&#xff0c;我们有望看到国产手机再一次超越自己的决心&#xff0c;继续创新追逐高端&#xff1b;另一方面&#xff0c;我们也不得不正视目前手机市场所面临的危机状态。 2024年1月的线上手机市场远不如去年。根据鲸参谋数据显示&#xff0c;今年1月京…

Java面试题之分布式/微服务篇

经济依旧不景气啊&#xff0c;如此大环境下Java还是这么卷&#xff0c;又是一年一次的金三银四。 兄弟们&#xff0c;你准备好了吗&#xff1f;冲冲冲&#xff01;欧里给&#xff01; 分布式/微服务相关面试题解 题一&#xff1a;CAP理论&#xff0c;BASE理论题二&#xff1a;…

【2024软件测试面试必会技能】Postman(1): postman的介绍和安装

Postman的介绍 Postman 是一款谷歌开发的接口测试工具,使API的调试与测试更加便捷。 它提供功能强大的 Web API & HTTP 请求调试。它能够发送任何类型的HTTP 请求 (GET, HEAD, POST, PUT..)&#xff0c;附带任何数量的参数 headers。 postman是一款支持http协议的接口调试…

springboot整合mybatisPlus超级详细

springboot整合mybatis-plus超级详细 一、环境二、springboot整合myBatisPlus2.1新建2.2 添加Mybatis-plus和mysql依赖2.3 修改配置文件2.4 新建包和文件2.5 新建表2.6 创建实体类2.7 创建Mapper接口2.8 创建Service接口2.9 创建Service实现类2.10 增删改查 MyBatis-Plus&#…

C# Onnx 使用onnxruntime部署实时视频帧插值

目录 介绍 效果 模型信息 项目 代码 下载 C# Onnx 使用onnxruntime部署实时视频帧插值 介绍 github地址&#xff1a;https://github.com/google-research/frame-interpolation FILM: Frame Interpolation for Large Motion, In ECCV 2022. The official Tensorflow 2…