文章目录
- [实现win10 手动与自动切换主题](#实现win10 手动与自动切换主题)
实现win10 手动与自动切换主题
为什么写这篇文章?
笔者以前使用代码实现过win10自动与手动切换主题,但是没有实现过带界面的,这次是弥补以前的不足。
常见的后台应用(如:搜狗输入法 )都会设置有托盘(QSystemTrayIcon)这里就借助托盘,让程序更像在后台一直运行一样!
一些需要知道的知识
- 怎么通过代码修改
win10的主题?
答:其实是借用winreg(Python内置库)来修改注册表文件 - 怎么实现自动切换主题?
答: 获取当地的日出日落时间,在日出之后日落之前亮色 ;其他暗色 - 怎么实现系统托盘?下面详解
系统托盘的实现
见相关代码:
py
def setup_system_tray(self):
"""设置系统托盘
"""
#
system_tray = QSystemTrayIcon(self)
system_tray.setIcon(QIcon("./images/dicos.ico"))
system_tray.setToolTip("自动切换主题")
tray_menu = QMenu()
self.__change = tray_menu.addAction("切换主题")
self.__exit = tray_menu.addAction("退出")
system_tray.setContextMenu(tray_menu)
system_tray.show()
注意 :
win10图标没有正确配置则不会显示托盘,linux 会显示三个点的图标,macOS条件有限待更新
按照如上代码就可以实现一个系统托盘。
小知识 :在 Windows 上,系统托盘图标大小为
16x16;在 X11 上,首选尺寸为22x22。
效果演示
PySide6 win10 手动与自动切换主题 借助系统托盘
整体代码
│- auto_choose_them.py PySide6窗口QWidget与系统托盘QSystemTrayIcon
│ - one_day.py 一天的时间相关,当前时间、日出日落时间
│ - windows_regedit.py 用于操作windows注册表
└─images
dicos.ico 托盘图标
auto_choose_them.py
py
# 这是一个 win10的自动切换 主题的工具
# 根据当地 日升 日落 时间来设置 对应的主题
# 需要主界面与应用窗口
from PySide6.QtWidgets import (QWidget,QVBoxLayout,QCheckBox,QSystemTrayIcon,QMenu,QApplication)
from PySide6.QtGui import QIcon
import sys
from windows_regedit import WinSystemThem
from one_day import OneDay
class AutoThem(QWidget):
"""自动切换主题
"""
def __init__(self):
"""初始化
"""
super().__init__()
self.setup_ui()
self.setup_system_tray()
self.set_event_bind()
def setup_ui(self):
"""设置界面
"""
# 窗口使用垂直布局
vbox = QVBoxLayout(self)
# 创建勾选框
self.__enable_checkbox = QCheckBox("开机自启动")
self.__auto_checkbox = QCheckBox("自动选择")
# 添加到垂直布局中
vbox.addWidget(self.__enable_checkbox)
vbox.addWidget(self.__auto_checkbox)
def setup_system_tray(self):
"""设置系统托盘
"""
#
system_tray = QSystemTrayIcon(self)
system_tray.setIcon(QIcon("./images/dicos.ico"))
system_tray.setToolTip("自动切换主题")
tray_menu = QMenu()
self.__change = tray_menu.addAction("切换主题")
self.__exit = tray_menu.addAction("退出")
system_tray.setContextMenu(tray_menu)
system_tray.show()
def set_event_bind(self):
"""设置事件绑定
"""
# 主界面
self.__auto_checkbox.checkStateChanged.connect(self.auto_choose_theme)
# 托盘 上下文菜单
self.__change.triggered.connect(lambda: WinSystemThem().reset_windows_theme())
self.__exit.triggered.connect(self.close)
def auto_choose_theme(self):
"""自动选择主题
"""
one_day = OneDay()
hours,minutes = one_day.get_current_time()
sunrise_hour,sunrise_minute = one_day.get_sunrise()
sunset_hour,sunset_minute = one_day.get_sunset()
# 日升之后 落入之前 亮色 二分法 先比小时 再比分钟
if hours >= sunrise_hour and hours <= sunset_hour:
if sunrise_minute >= minutes or minutes <= sunset_minute:
WinSystemThem().set_system_theme(1)
else:
WinSystemThem().set_system_theme(0)
if __name__ == "__main__":
app = QApplication(sys.argv)
auto_them = AutoThem()
auto_them.show()
sys.exit(app.exec())
one_day.py
py
import time
import requests
from datetime import datetime
class OneDay:
def __init__(self):
self.lat,self.lon,self.city = None,None,None
self.sunrise_hour,self.sunrise_minute = None,None
self.sunset_hour,self.sunset_minute = None,None
def __get_location_by_ip(self) -> tuple[float,float,str]:
"""获取当前位置
"""
try:
response = requests.get("http://ip-api.com/json/", timeout=5)
data = response.json()
if data["status"] == "success":
self.lat,self.lon,self.city = data["lat"], data["lon"], data["city"]
return (data["lat"], data["lon"], data["city"])
else:
return None, None, None
except:
return None, None, None
def __get_sunrise_sunset(self):
if self.lat:
lat,lon = self.lat,self.lon
else:
lat,lon,city = self.__get_location_by_ip()
url = f"https://api.sunrise-sunset.org/json?lat={lat}&lng={lon}&date=today&formatted=0"
response = requests.get(url, timeout=5)
data = response.json()
if data["status"] == "OK":
sunrise_str = data["results"]["sunrise"] # ISO 8601 UTC
sunset_str = data["results"]["sunset"]
# 解析 ISO 时间字符串
sunrise_utc = datetime.fromisoformat(sunrise_str.replace("Z", "+00:00"))
sunset_utc = datetime.fromisoformat(sunset_str.replace("Z", "+00:00"))
# 转换为本地时区
sunrise_local = sunrise_utc.astimezone()
sunset_local = sunset_utc.astimezone()
# 提取小时和分钟为整数
sunrise_hour = sunrise_local.hour
sunrise_minute = sunrise_local.minute
sunset_hour = sunset_local.hour
sunset_minute = sunset_local.minute
self.sunrise_hour,self.sunrise_minute,self.sunset_hour,self.sunset_minute = sunrise_hour, sunrise_minute, sunset_hour, sunset_minute
return sunrise_hour, sunrise_minute, sunset_hour, sunset_minute
return None, None,None,None
def get_sunrise(self):
"""获取日出事件
"""
if self.sunrise_hour:
return (self.sunrise_hour,self.sunrise_minute)
else:
return (self.__get_sunrise_sunset()[0],self.__get_sunrise_sunset()[1])
def get_sunset(self):
"""获取日落事件
"""
if self.sunrise_hour:
return (self.sunset_hour,self.sunset_minute)
else:
return (self.__get_sunrise_sunset()[2],self.__get_sunrise_sunset()[3])
def get_current_time(self) -> tuple[int,int] :
"""获取当前时间
"""
# 获取当前时间结构
local_time = time.localtime()
# 获取当前小时和分钟
current_hour = local_time.tm_hour
current_minute = local_time.tm_min
return (current_hour,current_minute)
windows_regedit.py
py
import winreg
class WinSystemThem:
def __init__(self):
self.__key = winreg.OpenKey(
winreg.HKEY_CURRENT_USER,
r"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize",
0,
winreg.KEY_READ | winreg.KEY_WRITE
)
def __del__(self):
"""对象销毁时关闭注册表键
"""
if hasattr(self, '__key') and self.__key:
winreg.CloseKey(self.__key)
def get_system_theme(self):
"""获取系统主题
:return: 0 dark ; 1 light
"""
apps_use_light_theme = winreg.QueryValueEx(self.__key , "AppsUseLightTheme")[0]
system_use_light_theme = winreg.QueryValueEx(self.__key , "SystemUsesLightTheme")[0]
# 如果两个值都是0,表示暗色模式
if apps_use_light_theme == 0 and system_use_light_theme == 0:
return 0
else:
return 1
def set_system_theme(self,module:bool):
"""设置系统主题
:param module: 0 dark; 1 light
"""
winreg.SetValueEx(self.__key, "AppsUseLightTheme", 0, winreg.REG_DWORD, module)
winreg.SetValueEx(self.__key, "SystemUsesLightTheme", 0, winreg.REG_DWORD, module)
def reset_windows_theme(self):
"""
重新设置主题为亮色或者按钮
"""
module = not self.get_system_theme()
self.set_system_theme(module)
winreg.CloseKey(self.__key)
展望
- 开机自启动待实现
auto_choose_theme方法等待优化!