PySide6 实现win10 手动与自动切换主题 借助系统托盘

文章目录

实现win10 手动与自动切换主题

为什么写这篇文章?

笔者以前使用代码实现过win10自动与手动切换主题,但是没有实现过带界面的,这次是弥补以前的不足。

常见的后台应用(如:搜狗输入法 )都会设置有托盘(QSystemTrayIcon)这里就借助托盘,让程序更像在后台一直运行一样!

一些需要知道的知识

  1. 怎么通过代码修改win10的主题?
    答:其实是借用winregPython内置库)来修改注册表文件
  2. 怎么实现自动切换主题?
    答: 获取当地的日出日落时间,在日出之后日落之前亮色 ;其他暗色
  3. 怎么实现系统托盘?下面详解

系统托盘的实现

见相关代码:

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方法等待优化!
相关推荐
Boilermaker199214 小时前
【Redis】集群与分布式缓存
java·数据库·redis·1024程序员节
花果山~~程序猿15 小时前
rtp组播乱序三种策略模式选择(AI)
1024程序员节
hazy1k15 小时前
51单片机基础-LCD1602液晶显示
stm32·单片机·嵌入式硬件·51单片机·1024程序员节
南方的狮子先生16 小时前
【深度学习】60 分钟 PyTorch 极速入门:从 Tensor 到 CIFAR-10 分类
人工智能·pytorch·python·深度学习·算法·分类·1024程序员节
瑞禧生物ruixibio17 小时前
iFluor 594 Styramide,水溶性荧光探针
1024程序员节
金融小师妹17 小时前
OpenAI拟借AI估值重构浪潮冲击1.1万亿美元IPO——基于市场情绪因子与估值量化模型的深度分析
大数据·人工智能·深度学习·1024程序员节
jamesge201017 小时前
zookeeper学习笔记
笔记·学习·zookeeper·1024程序员节
Yupureki18 小时前
从零开始的C++学习生活 19:C++复习课(5.4w字全解析)
c语言·数据结构·c++·学习·1024程序员节
门外的兔子20 小时前
【FPGA】Quartus Prime Lite 23.1 最新版 安装教程 ModelSim_18.1 下载安装 + 联调仿真教程 + 详细安装教程 2025最新
嵌入式硬件·fpga开发·1024程序员节