【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 = True
    self.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 hwnd
    hwnd = 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 = 255
    else:
        alpha = set_tp * 25
    windll.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 = 0x80000

keys = set()
hwnd = 0    # 窗口句柄

class GUI:
    def __init__(self):
        #初始化窗口

    """
    [1]最小化托盘
    """

    """
    [2]键盘操作
    """

    """
    [3]设置透明度操作(Ctrl + Alt + [0-9])
    """



if __name__ == '__main__':
    # 主界面
    TKDemo = GUI()
    TKDemo.root.mainloop()

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vue大文件读取部分内容,避免重复加载大文件,造成流量浪费

使用场景&#xff1a;项目点云地图是pcd文件&#xff0c;但是文件可能上百兆&#xff0c;我需要获取到文件中的版本信息&#xff0c;跟本地的缓存文件做比较&#xff0c;如果不一致&#xff0c;才会加载整个文件。从而节省流量。 避免重复加载整个“.pcd文件&#xff0c;以最大…

Linux篇:Shell命令以及运行原理 和 权限

一. Shell命令及原理 Linux操作系统狭义上是Linux内核&#xff0c;广义上是指Linux内核Linux外壳(Shell)和对应的配套程序 Linux外壳&#xff1a;Linux 外壳是用户与内核之间的接口&#xff0c;用户通过外壳与操作系统进行交互和操作。在 Linux 系统中&#xff0c;用户可以选…

软件确认测试流程和作用简析,出确认测试报告的软件测评公司分享

软件确认测试是指对软件产品进行验证和确认&#xff0c;以确保其满足预先设定的需求和规格。它是软件开发过程中的重要一步&#xff0c;旨在发现和解决潜在的问题和错误&#xff0c;以提高软件的质量和可靠性。 一、软件确认测试的流程有哪些?   1、需求分析和测试计划制定…

【Spring】SpringBoot 创建和使用

目 录 一.什么是Spring Boot&#xff1f;为什么要学Spring Boot&#xff1f;二.Spring Boot 优点三.Spring Boot 项目创建3.1 使用 Idea 创建3.2 网页版创建注意事项&#xff1a;包路径错误小结&#xff1a;约定大于配置 一.什么是Spring Boot&#xff1f;为什么要学Spring Boo…

C#串口 Modbus通讯工具类

一、安装Modbus包 二、创建modbushelper类 1、打开串口 public bool IfCOMOpend; //用于实例内的COM口的状态 public SerialPort OpenedCOM;//用于手动输入的COM转成SERIAL PORT /// <summary> /// 打开串口 /// </summary> /// <param name="COMname&quo…

VMware虚拟机文件夹共享失效

问题现象 今天开启虚拟机的时候就看到这个&#xff0c;感觉又要有不好的事情发生了。 果不其然&#xff0c;开机之后弹出这个&#xff0c;我当时还没意识到这个dll文件会对我的正常使用产生什么样的影响。 然后就发现文件根本拷贝不进去虚拟机里面&#xff0c;连虚拟机里面的共…

Transformer 架构—Encoder-Decoder

文章目录 前言 一、Encoder 家族 1. BERT 2. DistilBERT 3. RoBERTa 4. XML 5. XML-RoBERTa 6. ALBERT 7. ELECTRA 8. DeBERTa 二、Decoder 家族 1. GPT 2. GPT-2 3. CTRL 4. GPT-3 5. GPT-Neo / GPT-J-6B 三、Encoder-Decoder 家族 1. T5 2. BART 3. M2M-100 4. BigBird 前言 …

VS Code如何统计代码量

1、插件统计 在 VS Code 中&#xff0c;可以使用插件来统计文件夹里的代码行数。以下是使用插件的步骤&#xff1a; 打开 VS Code&#xff0c;点击左侧的插件图标&#xff08;或者按下 CtrlShiftX 快捷键&#xff09;&#xff0c;搜索并安装 Code Metrics 插件。 安装完成后…

【GStreamer】GstElement详解:GStreamer 中最重要的对象

1、什么是元素GstElement? 每个解码器、编码器、解复用器、视频或音频输出实际上都是一个GstElement。GstElement可以视为一个黑盒子:例如,对于解码器元素,输入为已编码数据,输出为解码后的数据,解码过程已由GstElement封装好。 2、都有哪些元素GstElement? 2.1 源点…

喜报,喜报!MO 荣获六个年度大奖!

我们很高兴地宣布一件事儿&#xff01; 今年&#xff0c;我们荣获了六个年度大奖&#xff0c;分别是&#xff1a; 中国信通院 “星河” 案例 InfoQ 2023 年度技术内容贡献奖 2023 大数据产业年度国产化优秀代表厂商 ITPUB 2023年度技术卓越奖 CSDN 中国开发者影响力年度榜单—…

用结构减法比较平面上4点结构的顺序

( A, B )---6*30*2---( 1, 0 )( 0, 1 ) 让网络的输入只有6个节点&#xff0c;AB训练集各由6张二值化的图片组成&#xff0c;A有4个点&#xff0c;B全是0.收敛误差7e-4&#xff0c;收敛199次&#xff0c;统计迭代次数平均值并排序。 如果行和列自由变换&#xff0c;迭代次数不…

python3字符串内建方法join()心得

python3字符串内建方法join()心得 概念 将序列&#xff08;sequence&#xff09;中的元素&#xff08;元素需要是字符串对象&#xff09;用指定字符连接后生成一个新的字符串。 语法 str.join(sequence) 参数1.join(参数2&#xff09; 参数1&#xff1a;用来连接序列中字符…

基于SpringBoot的CSGO赛事管理系统源码和论文

CSGO赛事管理系统是针对CSGO赛事管理方面必不可少的一个部分。在CSGO赛事管理的整个过程中&#xff0c;CSGO赛事管理系统担负着最重要的角色。为满足如今日益复杂的管理需求&#xff0c;各类的管理系统也在不断改进。本课题所设计的CSGO赛事管理系统&#xff0c;使用java进行开…

SCI一区 | Matlab实现GAF-PCNN-MSA格拉姆角场和双通道PCNN融合注意力机制的多特征分类预测

SCI一区 | Matlab实现GAF-PCNN-MSA格拉姆角场和双通道PCNN融合注意力机制的多特征分类预测 目录 SCI一区 | Matlab实现GAF-PCNN-MSA格拉姆角场和双通道PCNN融合注意力机制的多特征分类预测效果一览基本介绍模型描述程序设计参考资料 效果一览 基本介绍 1.【SCI一区级】Matlab实…

人工智能_CPU安装运行ChatGLM大模型_ChatGlm-6B_启动命令行对话_安装API调用接口_005---人工智能工作笔记0100

然后我们再进入 /data/module/ChatGLM-6B-main文件夹 然后我们去启动,命令行工具 python3 cli_demo.py 可以看到也是可以用了. 正常可以用了. 然后主要来看,如何使用api来调用呢,这样才可以,做自己的界面 可以看到就非常简单了只需要: 走到 /data/module/

Python自动化UI测试之Selenium基础实操

1. Selenium简介 Selenium 是一个用于 Web 应用程序测试的工具。最初是为网站自动化测试而开发的&#xff0c;可以直接运行在浏览器上&#xff0c;支持的浏览器包括 IE&#xff08;7, 8, 9, 10, 11&#xff09;&#xff0c;Mozilla Firefox&#xff0c;Safari&#xff0c;Googl…

操作系统虚拟内存(下)

操作系统虚拟内存&#xff08;上&#xff09;-CSDN博客 TLB 多级页表虽然解决了空间上的问题&#xff0c;但是虚拟地址到物理地址的转换就多了几道转换的工序&#xff0c;这显然就降低了这俩地址转换的速度&#xff0c;也就是带来了时间上的开销。 程序是有局部性的&#xff…

猫头虎分享已解决Bug || KeyError: ‘The truth value of a Series is ambiguous‘

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

数据结构D3作业

1. 2. 按位插入 void insert_pos(seq_p L,datatype num,int pos) { if(LNULL) { printf("入参为空&#xff0c;请检查\n"); return; } if(seq_full(L)1) { printf("表已满&#xff0c;不能插入\n"); …

【教3妹学编程-算法题】按距离统计房屋对数目 II

3妹&#xff1a;2哥2哥&#xff0c;国家又降息啦&#xff0c;贷款市场报价利率&#xff08;LPR&#xff09;为&#xff1a;1年期LPR为3.45%&#xff0c;与前值持平&#xff1b;5年期以上LPR为3.95%&#xff0c;较前值下调25个基点。 你的房贷是不是可以又少了&#xff1f; 2哥 …