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方法等待优化!
相关推荐
房开民1 天前
PyQt 翻译(国际化)极简讲解
pyqt
u0103055271 天前
AI驱动的安卓UI自动生成功能实现
人工智能·1024程序员节
u0103055272 天前
长株潭智能体赋能腾讯元器链接共享
1024程序员节
云贝贝贝3 天前
OceanBase认证体系介绍与备考指南
运维·服务器·oceanbase·1024程序员节
u0103055273 天前
Java图像处理实战指南
人工智能·1024程序员节
u0103055274 天前
Java AWT鼠标事件全解析
人工智能·1024程序员节
房开民5 天前
PyQt5 常用模块(对应Qt五大模块)
数据库·pyqt
u0103055276 天前
Java实用类应用精讲
人工智能·1024程序员节
u0103055277 天前
Java I/O核心操作实战
人工智能·1024程序员节
u0103055278 天前
ArrayList操作详解与实战应用
人工智能·1024程序员节