本文主要是介绍基于Python开发Windows屏幕控制工具,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
《基于Python开发Windows屏幕控制工具》在数字化办公时代,屏幕管理已成为提升工作效率和保护眼睛健康的重要环节,本文将分享一个基于Python和PySide6开发的Windows屏幕控制工具,...
概述
在数字化办公时代,屏幕管理已成为提升工作效率和保护眼睛健康的重要环节。今天我将分享一个基于python和PySide6开发的Windows屏幕控制工具,它集成了一键息屏、亮度调节、自动息屏时间设置和全局快捷键等实用功能,并支持系统托盘运行和开机自启动。
本文将深入解析这个工具的实现原理、关键技术点和完整代码,适合有一定Python基础的开发者学习GUI开发、系统级操作和实用工具开发。
功能亮点
1.一键息屏功能
- 立即关闭显示器节省能源
- 支持全局快捷键触发(可自定义)
2.自动息屏时间设置
- 预设常用时间(1/5/10/15/30/60分钟)
- 支持自定义任意分钟数
- 永不息屏模式
3.屏幕亮度控制
- 0-100%无级调节
- 预设常用亮度档位
- 亮度调节快捷键支持
4.实用附加功能
- 系统托盘运行
- 开机自启动
- 启动时最小化
- 当前设置实时显示
界面展示
主界面设计
界面采用现代化设计,包含:
- 醒目的标题区
- 快速息屏大按钮
- 自动息屏时间预设区
- 亮度控制滑块
- 应用设置面板
- 当前设置显示区
系统托盘菜单
实现步骤详解
1. 环境准备
# 主要依赖库 import sys import ctypes import subprocess import winreg from PySide6.QtWidgets import (QApplication, QMainWindow, ...) from PySide6.QtCore import Qt, QTimer, QSettings
2. 亮度控制模块
亮度调节采用了三种备选方案,确保兼容性:
class BrightnessController: def set_brightness(self, level): # 方法1: WMI (Windows Management Instrumentation) try: import wmi w = wmi.WMI(namespace='wmi') methods = w.WmiMonitorBrightnessMethods()[0] methods.WmiSetBrightness(level, 0) # 方法2: PowerShell命令 except: script = f"$brightness = {level}; $myMonitor = Get-WmiObject..." subprocess.run(["powershell", "-Command", script]) # 方法3: DDC/CI控制 except: import screen_brightness_control as sbc sbc.set_brightness(level)
3. 息屏功能实现
使用Windows API发送消息关闭显示器:
def turn_off_screen(self): # 0x0112 = WM_SYSCOMMAND, 0xF170 = SC_MONITORPOWER, 2 = 关闭显示器 ctypes.windll.user32.SendMessageW(0xFFFF, 0x0112, 0xF170, 2)
4. 息屏时间设置
通过Windows powercfg命令修改电源设置:
def set_screen_timeout(self, minutes): if minutes == 0: # 永不息屏 subprocess.run(['powercfg', '/change', 'monitor-timeout-ac', '0']) else: # 设置指定时间 subprocess.run(['powercfg', '/change', 'monitor-timeout-ac', str(minutes)])
5. 全局快捷键实现
使用QShortcut捕获全局快捷键:
def setup_global_shortcut(self, key_sequence): self.global_shortcut = QShortcut(key_sequence, self) self.global_shortcut.activated.connect(self.turn_off_screen)
6. 开机自启动
通过修改Windows注册表实现:
def toggle_autostart(self, state): key_path = r"SOFTWARE\Microsoft\Windows\CurrentVersion\Run" if state == Qt.Checked: # 添加启动项 winreg.SetValueEx(key, "ScreenController", 0, winreg.REG_SZ, exe_path) else: # 删除启动项 winreg.DeleteValue(key, "ScreenController")
7. 系统托盘集成
创建托盘图标和右键菜单:
def setup_tray_icon(self): self.tray_icon = QSystemTrayIcon(self) tray_menu = QMenu() # 添加菜单项 show_action = QAction("显示主窗口", self) screen_off_action = QAction("立即息屏", self) # 亮度子菜单 brightness_menu = tray_menu.addMenu("屏幕亮度") for level in [0, 25, 50, 75, 100]: action = QAction(f"{level}%", self) action.triggered.connect(lambda l=level: self.set_brightness_level(l)) brightness_menu.addAction(action)
关键代码解析
1. 多方法亮度控制
亮度控制模块采用了策略模式,依次尝试三种不同的亮度调节方法:
- WMI方式:最原生的Windows管理接口
- PowerShell方式:兼容性更好的脚本方法
- DDC/CI方式:直接与显示器通信
这种设计确保了在各种Windows环境和硬件配置下都能正常工作。
2. 设置持久化
使用QpythonSettings实现配置的自动保存和加载:
# 保存设置 self.settings.setValue("shortcut", self.shortcut_edit.keySequence().toString()) # 加载设置 shortcut_string = self.settings.value("shortcut", "", type=str)
3. 管理员权限检测
关键系统操作需要管理员权限:
def is_admin(self): try: return ctypes.windll.shell32.IsUserAnAdmin() except: return False
源码下载
import sys import ctypes import subprocess import os import sys import winreg import argparse from pathlib import Path from PySide6.QtWidgets import ( QApplication, QMainWindow, QWidget, QvboxLayout, QHBoxLayout, QGridLayout, QPushButton, QLabel, QLineEdit, QFrame, QMessageBox, QGroupBox, QSpacerItem, QSizePolicy, QCheckBox, QKeySequenceEdit, QSystemTrayIcon, QMenu, QSlider ) from PySide6.QtCore import Qt, QTimer, QSettings, QStandardPaths from PySide6.QtGui import QFont, QPalette, QColor, QKeySequence, QShortcut, QIcon, QPixmap, QAction # 获取应用程序路径(支持打包后的可执行文件) def get_app_path(): """获取应用程序路径,支持打包后的可执行文件""" if getattr(sys, 'frozen', False): return Path(sys.executable).parent else: return Path(__file__).parent # 获取配置文件路径 def get_config_path(): """获取配置文件路径""" config_dir = QStandardPaths.writableLocation(QStandardPaths.AppConfigLocation) return Path(config_dir) / "ScreenController" class BrightnessController: """屏幕亮度控制类""" def __init__(self): self.physical_monitors = self._get_physical_monitors() def _get_physical_monitors(self): """获取物理显示器句柄""" try: from screeninfo import get_monitors return [monitor for monitor in get_monitors() if monitor.is_primary] except Exception as e: print(f"获取显示器信息失败: {e}") return [] def set_brightness(self, level): """设置屏幕亮度(0-100)""" try: if not (0 <= level <= 100): raise ValueError("亮度值必须在0-100之间") # 方法1: 使用WMI (Windows Management Instrumentation) try: import wmi w = wmi.WMI(namespace='wmi') methods = w.WmiMonitorBrightnessMethods()[0] methods.WmiSetBrightness(level, 0) return True except Exception as wmi_error: # 方法2: 使用PowerShell命令 (适用于更多系统) try: brightness = max(0, min(100, level)) script = f""" $brightness = {brightness} $delay = 0 $myMonitor = Get-WmiObject -Namespace root\\wmi -Class WmiMonitorBrightnessMethods $myMonitor.WmiSetBrightness($delay, $brightness) """ subprocess.run(["powershell", "-Command", script], check=True, creationflags=subprocess.CREATE_NO_WINDOW) return True except subprocess.CalledProcessError: # 方法3: 使用DDC/CI (需要显示器支持) try: if self.physical_monitors: import screen_brightness_control as sbc sbc.set_brightness(level) return True except Exception as sbc_error: raise Exception(f"所有亮度调节方法均失败: WMI错误: {wmi_error}, DDC/CI错误: {sbc_error}") except Exception as e: raise Exception(f"设置亮度失败: {str(e)}") class ScreenController(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("️ Windows屏幕控制") self.setFixedSize(1000, 800) # 增加窗口尺寸以容纳亮度控制 # 亮度控制器 self.brightness_controller = BrightnessController() # 设置存储 config_path = get_config_path() config_path.mkdir(parents=True, exist_ok=True) settings_file = config_path / "settings.ini" self.settings = QSettings(str(settings_file), QSettings.IniFormat) # 全局快捷键 self.global_shortcut = None self.brightness_shortcut = None # 系统托盘 self.tray_icon = None self.setup_tray_icon() self.setup_ui() self.setup_style() self.load_settings() # 定时器用于更新当前设置 self.update_timer = QTimer() self.update_timer.timeout.connect(self.update_current_setting) self.update_timer.start(5000) # 每5秒更新一次 # 初始更新 self.update_current_setting() def setup_ui(self): """设置用户界面""" central_widget = QWidget() self.setCentralWidget(central_widget) # 主布局 main_layout = QVBoxLayout(central_widget) main_layout.setSpacing(20) main_layout.setContentsMargins(25, 25, 25, 25) # 标题 - 添加emoji title_label = QLabel("️ Windows屏幕控制器") title_font = QFont("Microsoft YaHei", 20, QFont.Bold) title_label.setFont(title_font) title_label.setAlignment(Qt.AlignCenter) title_label.setStyleSheet(""" QLabel { padding: 15px; background: qlineargradient(x1:0, y1:0, x2:1, y2:0, stop:0 #3498db, stop:1 #2ecc71); border-radius: 12px; border: 2px solid #bdc3c7; color: white; } """) main_layout.addwidget(title_label) # 快速息屏按钮 self.screen_off_btn = QPushButton(" 立即息屏") self.screen_off_btn.clicked.connect(self.turn_off_screen) self.screen_off_btn.setFixedHeight(65) button_font = QFont("Microsoft YaHei", 14, QFont.Bold) self.screen_off_btn.setFont(button_font) self.screen_off_btn.setStyleSheet(""" QPushButton { background-color: #e74c3c; color: white; border: none; border-radius: 12px; padding: 15px; } QPushButton:hover { background-color: #ec7063; transform: scale(1.02); } QPushButton:pressed { background-color: #c0392b; } """) main_layout.addWidget(self.screen_off_btn) # 分隔线 separator = QFrame() separator.setFrameShape(QFrame.HLine) separator.setFrameShadow(QFrame.Sunken) separator.setStyleSheet(""" QFrame { color: #bdc3c7; margin: 10px 0; } """) main_layout.addWidget(separator) # 创建水平布局容器 horizontal_container = QWidget() horizontal_layout = QHBoxLayout(horizontal_container) horizontal_layout.setSpacing(20) horizontal_layout.setContentsMargins(0, 0, 0, 0) # 左侧:息屏时间设置组 settings_group = QGroupBox("⏱️ 自动息屏时间设置") settings_group.setFont(QFont("Microsoft YaHei", 12, QFont.Bold)) settings_group.setStyleSheet(""" QGroupBox { font-weight: bold; border: 2px solid #3498db; border-radius: 12px; margin-top: 10px; padding-top: 15px; background-color: #f8fafc; } QGroupBox::title { subcontrol-origin: margin; left: 20px; padding: 0 10px 0 10px; color: #2980b9; } """) settings_layout = QVBoxLayout(settings_group) settings_layout.setSpacing(15) # 预设时间按钮网格 preset_label = QLabel("⚡ 快速设置(分钟):") preset_label.setFont(QFont("Microsoft YaHei", 11, QFont.Bold)) preset_label.setStyleSheet("QLabel { color: #2c3e50; margin-bottom: 5px; }") settings_layout.addWidget(preset_label) # 第一行:1, 5, 10分钟 preset_row1 = QWidget() preset_layout1 = QHBoxLayout(preset_row1) preset_layout1.setSpacing(12) preset_layout1.setContentsMargins(0, 0, 0, 0) time_emojis = {1: "⏱️", 5: "⏳", 10: "⌛"} for time_val in [1, 5, 10]: btn = QPushButton(f"{time_emojis.get(time_val, '⏱️')} {time_val}分钟") btn.clicked.connect(lambda checked=None, t=time_val: self.set_screen_timeout(t)) btn.setFixedHeight(50) btn.setFont(QFont("Microsoft YaHei", 10, QFont.Bold)) btn.setStyleSheet(""" QPushButton { background-color: #3498db; color: white; border: none; border-radius: 10px; padding: 10px; min-width: 90px; } QPushButton:hover { background-color: #5dade2; } QPushButton:pressed { background-color: #2980b9; } """) preset_layout1.addWidget(btn) settings_layout.addWidget(preset_row1) # 第二行:15, 30, 60分钟 preset_row2 = QWidget() preset_layout2 = QHBoxLayout(preset_row2) preset_layout2.setSpacing(12) preset_layout2.setContentsMargins(0, 0, 0, 0) time_emojis = {15: "", 30: "", 60: ""} for time_val in [15, 30, 60]: btn = QPushButton(f"{time_emojis.get(time_val, '')} {time_val}分钟") btn.clicked.connect(lambda checked=None, t=time_val: self.set_screen_timeout(t)) btn.setFixedHeight(50) btn.setFont(QFont("Microsoft YaHei", 10, QFont.Bold)) btn.setStyleSheet(""" QPushButton { background-color: #16a085; color: white; border: none; border-radius: 10px; padding: 10px; min-width: 90px; } QPushButton:hover { background-color: #48c9b0; } QPushButton:pressed { background-color: #138d75; } """) preset_layout2.addWidget(btn) settings_layout.addWidget(preset_row2) # 添加间距 settings_layout.addItem(QSpacerItem(20, 15, QSizePolicy.Minimum, QSizePolicy.Fixed)) # 自定义时间设置 custom_label = QLabel(" 自定义时间:") custom_label.setFont(QFont("Microsoft YaHei", 11, QFont.Bold)) custom_label.setStyleSheet("QLabel { color: #2c3e50; margin-bottom: 5px; }") settings_layout.addWidget(custom_label) custom_widget = QWidget() custom_layout = QHBoxLayout(custom_widget) custom_layout.setSpacing(12) custom_layout.setContentsMargins(0, 0, 0, 0) self.custom_time_input = QLineEdit() self.custom_time_input.setPlaceholderText("输入分钟数...") self.custom_time_input.setFixedHeight(50) self.custom_time_input.setFont(QFont("Microsoft YaHei", 11)) self.custom_time_input.returnPressed.connect(self.set_custom_timeout) self.custom_time_input.setStyleSheet(""" QLineEdit { border: 2px solid #bdc3c7; border-radius: 10px; padding: 12px; background-color: white; font-size: 11pt; } QLineEdit:focus { border-color: #f39c12; background-color: #fffde7; } """) custom_layout.addWidget(self.custom_time_input, 2) minutes_label = QLabel("⏰ 分钟") minutes_label.setFont(QFont("Microsoft YaHei", 11)) minutes_label.setStyleSheet("QLabel { color: #7f8c8d; }") custom_layout.addWidget(minutes_label) custom_btn = QPushButton("✅ 设置") custom_btn.clicked.connect(self.set_custom_timeout) custom_btn.setFixedHeight(50) custom_btn.setFixedWidth(100) custom_btn.setFont(QFont("Microsoft YaHei", 10, QFont.Bold)) custom_btn.setStyleSheet(""" QPushButton { background-color: #f39c12; color: white; border: none; border-radius: 10px; padding: 10px; } QPushButton:hover { background-color: #f4d03f; } QPushButton:pressed { background-color: #d68910; } """) custom_layout.addWidget(custom_btn) settings_layout.addWidget(custom_widget) # 添加间距 settings_layout.addItem(QSpacerItem(20, 15, QSizePolicy.Minimum, QSizePolicy.Fixed)) # 永不息屏按钮 never_btn = QPushButton(" 永不息屏") never_btn.clicked.connect(lambda checked=None: self.set_screen_timeout(0)) never_btn.setFixedHeight(55) never_btn.setFont(QFont("Microsoft YaHei", 12, QFont.Bold)) never_btn.setStyleSheet(""" QPushButton { background-color: #e74c3c; color: white; border: none; border-radius: 12px; padding: 12px; font-weight: bold; } QPushButton:hover { background-color: #ec7063; transform: scale(1.02); } QPushButton:pressed { background-color: #c0392b; } """) settings_layout.addWidget(never_btn) # 将息屏时间设置组添加到左侧 horizontal_layout.addWidget(settings_group) # 中间:亮度控制组 brightness_group = QGroupBox("☀️ 屏幕亮度控制") brightness_group.setFont(QFont("Microsoft YaHei", 12, QFont.Bold)) brightness_group.setStyleSheet(""" QGroupBox { font-weight: bold; border: 2px solid #f39c12; border-radius: 12px; margin-top: 10px; padding-top: 15px; background-color: #fff9e6; } QGroupBox::title { subcontrol-origin: margin; left: 20px; padding: 0 10px 0 10px; color: #d35400; } """) brightness_layout = QVBoxLayout(brightness_group) brightness_layout.setSpacing(15) # 亮度滑块 brightness_slider_layout = QHBoxLayout() self.brightness_slider = QSlider(Qt.Horizontal) self.brightness_slider.setRange(0, 100) self.brightness_slider.setValue(80) self.brightness_slider.setTickInterval(10) self.brightness_slider.setTickPosition(QSlider.TicksBelow) self.brightness_slider.valueChanged.connect(self.adjust_brightness) self.brightness_slider.setStyleSheet(""" QSlider::groove:horizontal { height: 10px; background: #e0e0e0; border-radius: 5px; } QSlider::handle:horizontal { width: 20px; height: 20px; background: #f39c12; border-radius: 10px; margin: -5px 0; } QSlider::sub-page:horizontal { background: #f1c40f; border-radius: 5px; } """) brightness_slider_layout.addWidget(self.brightness_slider) self.brightness_label = QLabel("80%") self.brightness_label.setFont(QFont("Microsoft YaHei", 10, QFont.Bold)) self.brightness_label.setFixedWidth(40) self.brightness_label.setAlignment(Qt.AlignCenter) brightness_slider_layout.addWidget(self.brightness_label) brightness_layout.addLayout(brightness_slider_layout) # 亮度预设按钮 brightness_preset_layout = QHBoxLayout() brightness_preset_layout.setSpacing(10) for level in [0, 25, 50, 75, 100]: btn = QPushButton(f"{level}%") btn.setFixedHeight(35) btn.setFont(QFont("Microsoft YaHei", 9)) btn.clicked.connect(lambda checked=None, l=level: self.set_brightness_level(l)) btn.setStyleSheet(""" QPushButton { background-color: #f1c40f; color: #34495e; border: none; border-radius: 8px; padding: 5px; } QPushButton:hover { background-color: #f39c12; color: white; } QPushButton:pressed { background-color: #e67e22; } """) brightness_preset_layout.addWidget(btn) brightness_layout.addLayout(brightness_preset_layout) # 亮度快捷键设置 brightness_shortcut_layout = QHBoxLayout() brightness_shortcut_label = QLabel(" 亮度调节快捷键:") brightness_shortcut_label.setFont(QFont("Microsoft YaHei", 10)) brightness_shortcut_layout.addWidget(brightness_shortcut_label) self.brightness_shortcut_edit = QKeySequenceEdit() self.brightness_shortcut_edit.setFixedHeight(35) self.brightness_shortcut_edit.keySequenceChanged.connect(self.on_brightness_shortcut_changed) brightness_shortcut_layout.addWidget(self.brightness_shortcut_edit) brightness_layout.addLayout(brightness_shortcut_layout) horizontal_layout.addWidget(brightness_group) # 右侧:应用设置组 app_settings_group = QGroupBox("⚙️ 应用设置") app_settings_group.setFont(QFont("Microsoft YaHei", 12, QFont.Bold)) app_settings_group.setStyleSheet(""" QGroupBox { font-weight: bold; border: 2px solid #9b59b6; border-radius: 12px; margin-top: 15px; padding-top: 15px; background-color: #faf5ff; } QGroupBox::title { subcontrol-origin: margin; left: 20px; padding: 0 15px 0 15px; color: #8e44ad; } """) app_settings_layout = QVBoxLayout(app_settings_group) app_settings_layout.setSpacing(20) # 开机自启动复选框 autostart_widget = QWidget() autostart_layout = QHBoxLayout(autostart_widget) autostart_layout.setContentsMargins(10, 5, 10, 5) self.autostart_checkbox = QCheckBox(" 开机自启动") self.autostart_checkbox.setFont(QFont("Microsoft YaHei", 11)) self.autostart_checkbox.stateChanged.connect(self.toggle_autostart) self.autostart_checkbox.setStyleSheet(""" QCheckBox { color: #2c3e50; padding: 8px; font-weight: 500; } QCheckBox::indicator { width: 22px; height: 22px; } QCheckBox::indicator:unchecked { border: 2px solid #bdc3c7; border-radius: 5px; background-color: white; } QCheckBox::indicator:checked { border: 2px solid #9b59b6; border-radius: 5px; background-color: #9b59b6; image: url(data:image/svg+XML;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTEzIDRMNiAxMkwzIDgiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZwpvaW49InJvdW5kIi8+Cjwvc3ZnPgo=); } QCheckBox::indicator:hover { border-color: #9b59b6; } """) autostart_layout.addWidget(self.autostart_checkbox) autostart_layout.addStretch() app_settings_layout.addWidget(autostart_widget) # 启动时最小化复选框 minimize_widget = QWidget() minimize_layout = QHBoxLayout(minimize_widget) minimize_layout.setContentsMargins(10, 5, 10, 5) self.minimize_on_start_checkbox = QCheckBox(" 启动时最小化到系统托盘") self.minimize_on_starandroidt_checkbox.setFont(QFont("Microsoft YaHei", 11)) self.minimize_on_start_checkbox.stateChanged.connect(self.save_settings) self.minimize_on_start_checkbox.setStyleSheet(self.autostart_checkbox.styleSheet()) minimize_layout.addWidget(self.minimize_on_start_checkbox) minimize_layout.addStretch() app_settings_layout.addWidget(minimize_widget) # 快捷键设置 shortcut_container = QWidget() shortcut_container_layout = QVBoxLayout(shortcut_container) shortcut_container_layout.setContentsMargins(10, 5, 10, 5) shortcut_container_layout.setSpacing(8) shortcut_header = QWidget() shortcut_header_layout = QHBoxLayout(shortcut_header) shortcut_header_layout.setContentsMargins(0, 0, 0, 0) shortcut_label = QLabel("⌨️ 立即息屏快捷键:") shortcut_label.setFont(QFont("Microsoft YaHei", 11, QFont.Bold)) shortcut_label.setStyleSheet("QLabel { color: #2c3e50; font-weight: 500; }") shortcut_header_layout.addWidget(shortcut_label) shortcut_header_layout.addStretch() shortcut_container_layout.addWidget(shortcut_header) shortcut_widget = QWidget() shortcut_layout = QHBoxLayout(shortcut_widget) shortcut_layout.setSpacing(12) shortcut_layout.setContentsMargins(0, 0, 0, 0) self.shortcut_edit = QKeySequenceEdit() self.shortcut_edit.setFixedHeight(45) self.shortcut_edit.setFont(QFont("Microsoft YaHei", 10)) self.shortcut_edit.keySequenceChanged.connect(self.on_shortcut_changed) self.shortcut_edit.setStyleSheet(""" QKeySequenceEdit { border: 2px solid #bdc3c7; border-radius: 10px; padding: 10px; background-color: white; font-size: 10pt; } QKeySequenceEdit:focus { border-color: #9b59b6; background-color: #fffde7; } """) shortcut_layout.addWidget(self.shortcut_edit, 2) clear_shortcut_btn = QPushButton("️ 清除") clear_shortcut_btn.clicked.connect(self.clear_shortcut) clear_shortcut_btn.setFixedHeight(45) clear_shortcut_btn.setFixedWidth(80) clear_shortcut_btn.setFont(QFont("Microsoft YaHei", 9, QFont.Bold)) clear_shortcut_btn.setStyleSheet(""" QPushButton { background-color: #95a5a6; color: white; border: none; border-radius: 10px; padding: 8px; } QPushButton:hover { background-color: #b2bec3; } QPushButton:pressed { background-color: #7f8c8d; } """) shortcut_layout.addWidget(clear_shortcut_btn) shortcut_container_layout.addWidget(shortcut_widget) app_settings_layout.addWidget(shortcut_container) # 将应用设置组添加到右侧 horizontal_layout.addWidget(app_settings_group) # 将水平布局容器添加到主布局 main_layout.addWidget(horizontal_container) # 当前设置显示 self.current_setting_label = QLabel(" 当前设置:获取中...") self.current_setting_label.setFont(QFont("Microsoft YaHei", 10)) self.current_setting_label.setAlignment(Qt.AlignCenter) self.current_setting_label.setStyleSheet(""" QLabel { color: #7f8c8d; padding: 15px; background-color: #f8f9fa; border-radius: 8px; border: 1px solid #dee2e6; } """) main_layout.addWidget(self.current_setting_label) # 添加弹性空间 main_layout.addItem(QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)) # 底部信息栏 footer_label = QLabel("️ 由创客白泽开发 | ️ Windows屏幕控制工具 ") footer_label.setFont(QFont("Microsoft YaHei", 8)) footer_label.setAlignment(Qt.AlignCenter) footer_label.setStyleSheet("QLabel { color: #7f8c8d; margin-top: 10px; }") main_layout.addWidget(footer_label) def setup_style(self): """设置整体样式""" self.setStyleSheet(""" QMainWindow { background-color: #ffffff; } QWidget { background-color: #ffffff; } """) def setup_tray_icon(self): """设置系统托盘图标""" if not QSystemTrayIcon.isSystemTrayAvailable(): QMessageBox.critical(self, "系统托盘", "系统托盘不可用") return # 创建托盘图标 self.tray_icon = QSystemTrayIcon(self) # 尝试加载favicon.ico图标 app_path = get_apandroidp_path() icon_path = app_path / "icon.ico" if icon_path.exists(): icon = QIcon(str(icon_path)) else: # 如果找不到favicon.ico,创建一个简单的图标 pixmap = QPixmap(16, 16) pixmap.fill(Qt.blue) icon = QIcon(pixmap) self.tray_icon.setIcon(icon) # 创建托盘菜单 tray_menu = QMenu() # 显示主窗口 show_action = QAction("️ 显示主窗口", self) show_action.triggered.connect(self.show_main_window) tray_menu.addAction(show_action) # 立即息屏 screen_off_action = QAction(" 立即息屏", self) screen_off_action.triggered.connect(self.turn_off_screen) tray_menu.addAction(screen_off_action) # 亮度调节菜单 brightness_menu = tray_menu.addMenu("☀️ 屏幕亮度") brightness_levels = [ (" 0%", 0), (" 25%", 25), (" 50%", 50), (" 75%", 75), (" 100%", 100) ] for text, level in brightness_levels: action = QAction(text, self) action.triggered.connect(lambda checked=None, l=level: self.set_brightness_level(l)) brightness_menu.addAction(action) tray_menu.addSeparator() # 退出程序 quit_action = QAction(" 退出", self) quit_action.triggered.connect(QApplication.instance().quit) tray_menu.addAction(quit_action) self.tray_icon.setContextMenu(tray_menu) self.tray_icon.activated.connect(self.tray_icon_activated) # 设置托盘提示 self.tray_icon.setToolTip("Windows屏幕控制器") # 显示托盘图标 self.tray_icon.show() def tray_icon_activated(self, reason): """托盘图标被激活时的处理""" if reason == QSystemTrayIcon.DoubleClick: self.show_main_window() def show_main_window(self): """显示主窗口""" self.show() self.raise_() self.activateWindow() def turn_off_screen(self): """立即关闭屏幕""" try: # 发送消息关闭显示器 ctypes.windll.user32.SendMessageW(0xFFFF, 0x0112, 0xF170, 2) except Exception as e: if self.isVisible(): QMessageBox.warning(self, "错误", f"关闭屏幕失败: {str(e)}") else: # 如果窗口不可见,通过托盘显示消息 if self.tray_icon: self.tray_icon.showMessage("错误", f"关闭屏幕失败: {str(e)}", QSystemTrayIcon.Warning, 3000) def set_screen_timeout(self, minutes): """设置屏幕超时时间""" try: if minutes == 0: message = "已设置为永不息屏" # 永不关闭屏幕 result1 = subprocess.run(['powercfg', '/change', 'monitor-timeout-ac', '0'], capture_output=True, text=True, check=True, creationflags=subprocess.CREATE_NO_WINDOW) result2 = subprocess.run(['powercfg', '/change', 'monitor-timeout-dc', '0'], capture_output=True, text=True, check=True, creationflags=subprocess.CREATE_NO_WINDOW) else: message = f"已设置息屏时间为 {minutes} 分钟" # 设置指定的超时时间 result1 = subprocess.run(['powercfg', '/change', 'monitor-timeout-ac', str(minutes)], capture_output=True, text=True, check=True, creationflags=subprocess.CREATE_NO_WINDOW) result2 = subprocess.run(['powercfg', '/change', 'monitor-timeout-dc', str(minutes)], capture_output=True, text=True, check=True, creationflags=subprocess.CREATE_NO_WINDOW) if self.isVisible(): QMessageBox.information(self, "成功", message) else: # 如果窗口不可见,通过托盘显示消息 if self.tray_icon: self.tray_icon.showMessage("设置成功", message, QSystemTrayIcon.Information, 3000) self.update_current_setting() except subprocess.CalledProcessError as e: error_msg = f"设置失败: {e.stderr if e.stderr else str(e)}" if self.isVisible(): QMessageBox.warning(self, "错误", error_msg) else: if self.tray_icon: self.tray_icon.showMessage("错误", error_msg, QSystemTrayIcon.Warning, 3000) except FileNotFoundError: error_msg = "找不到powercfg命令,请确保在Windows系统上运行" if self.isVisible(): QMessageBox.warning(self, "错误", error_msg) else: if self.tray_icon: self.tray_icon.showMessage("错误", error_msg, QSystemTrayIcon.Warning, 3000) except Exception as e: error_msg = f"未知错误: {str(e)}" if self.isVisible(): QMessageBox.warning(self, "错误", error_msg) else: if self.tray_icon: self.tray_icon.showMessage("错误", error_msg, QSystemTrayIcon.Warning, 3000) def set_custom_timeout(self): """设置自定义超时时间""" try: time_str = self.custom_time_input.text().strip() if not time_str: QMessageBox.warning(self, "警告", "请输入时间") return minutes = int(time_str) if minutes < 0: QMessageBox.warning(self, "警告", "时间不能为负数") return self.set_screen_timeout(minutes) self.custom_time_input.clear() # 清空输入框 except ValueError: QMessageBox.critical(self, "错误", "请输入有效的数字") def update_current_setting(self): """更新当前设置显示""" try: # 获取当前屏幕超时设置 result = subprocess.run(["powercfg", "/query", "SCHEME_CURRENT", "SUB_VIDEO", "VIDEOIDLE"], capture_output=True, text=True, check=True, creationflags=subprocess.CREATE_NO_WINDOW) # 解析输出获取当前设置 lines = result.stdout.split('\n') ac_timeout = None for line in lines: # 支持中英文输出 if "Current AC Power Setting Index:" in line or "当前交流电源设置索引:" in line: try: ac_timeout = int(line.split(':')[1].strip(), 16) break except (ValueError, IndexError): continue if ac_timeout is not None: if ac_timeout == 0: setting_text = " 当前设置:永不息屏" else: minutes = ac_timeout // 60 setting_text = f" 当前设置:{minutes} 分钟后息屏" else: setting_text = "⚠️ 当前设置:解析失败" self.current_setting_label.setText(setting_text) except subprocess.CalledProcessError as e: error_detail = f"命令执行失败: {e.stderr if e.stderr else '未知错误'}" self.current_setting_label.setText(f"⚠️ 当前设置:获取失败 ({error_detail})") except FileNotFoundError: self.current_setting_label.setText("⚠️ 当前设置:找不到powercfg命令") except Exception as e: self.current_setting_label.setText(f"⚠️ 当前设置:异常错误 ({str(e)})") def adjust_brightness(self, value): """调整屏幕亮度""" try: self.brightness_label.setText(f"{value}%") self.brightness_controller.set_brightness(value) except Exception as e: QMessageBox.warning(self, "亮度调节失败", f"无法调整亮度: {str(e)}") def set_brightness_level(self, level): """设置特定亮度级别""" self.brightness_slider.setValue(level) self.adjust_brightness(level) def on_brightness_shortcut_changed(self, key_sequence): """亮度快捷键改变时的处理""" if key_sequence.isEmpty(): return # 检查快捷键冲突 if self.check_shortcut_conflict(key_sequence): reply = QMessageBox.question( self, "快捷键冲突", f"⚠️ 快捷键 {key_sequence.toString()} 可能与其他程序冲突。\n是否仍要使用此快捷键?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No ) if reply == QMessageBox.No: self.brightness_shortcut_edit.clear() return # 设置新的快捷键 self.setup_brightness_shortcut(key_sequence) self.save_settings() QMessageBox.information(self, "成功", f"✅ 已设置亮度调节快捷键:{key_sequence.toString()}") def setup_brightness_shortcut(self, key_sequence): """设置亮度调节全局快捷键""" # 清除旧的快捷键 if self.brightness_shortcut: self.brightness_shortcut.setEnabled(False) self.brightness_shortcut = None # 设置新的快捷键 if not key_sequence.isEmpty(): self.brightness_shortcut = QShortcut(key_sequence, self) self.brightness_shortcut.activated.connect(self.toggle_brightness) def toggle_brightness(self): """切换亮度预设""" current = self.brightness_slider.value() if current >= 75: self.set_brightness_level(25) elif current >= 25: self.set_brightness_level(0) else: self.set_brightness_level(75) def is_admin(self): """检查是否以管理员权限运行""" try: return ctypes.windll.shell32.IsUserAnAdmin() except: return False def toggle_autostart(self, state): """切换开机自启动""" try: key_path = r"SOFTWARE\Microsoft\Windows\CurrentVersion\Run" app_name = "WindowsScreenController" if state == Qt.Checked: # 添加到注册表 with winreg.OpenKey(winreg.HKEY_CURRENT_USER, key_path, 0, winreg.KE编程Y_SET_VALUE) as key: if getattr(sys, 'frozen', False): # 打包后的可执行文件,添加启动时最小化参数 exe_path = f'"{sys.executable}" --minimized' else: # Python脚本 exe_path = sys.executable script_path = os.path.abspath(__file__) exe_path = f'"{exe_path}" "{script_path}" --minimized' winreg.SetValueEx(key, app_name, 0, winreg.REG_SZ, exe_path) QMessageBox.information(self, "成功", "✅ 已启用开机自启动") else: # 从注册表删除 try: with winreg.OpenKey(winreg.HKEY_CURRENT_USER, key_path, 0, winreg.KEY_SET_VALUE) as key: winreg.DeleteValue(key, app_name) QMessageBox.information(self, "成功", "❌ 已禁用开机自启动") except FileNotFoundError: pass # 键不存在,无需删除 self.save_settings() except PermissionError: QMessageBox.warning(self, "错误", "⛔ 权限不足,无法修改注册表启动项") # 恢复复选框状态 self.autostart_checkbox.setChecked(not state) except Exception as e: QMessageBox.critical(self, "错误", f"⚠️ 设置开机自启动失败:{str(e)}") # 恢复复选框状态 self.autostart_checkbox.setChecked(not state) def check_autostart_status(self): """检查开机自启动状态""" try: key_path = r"SOFTWARE\Microsoft\Windows\CurrentVersion\Run" app_name = "WindowsScreenController" with winreg.OpenKey(winreg.HKEY_CURRENT_USER, key_path, 0, winreg.KEY_READ) as key: try: winreg.QueryValueEx(key, app_name) return True except FileNotFoundError: return False except Exception: return False def on_shortcut_changed(self, key_sequence): """快捷键改变时的处理""" if key_sequence.isEmpty(): return # 检查快捷键冲突 if self.check_shortcut_conflict(key_sequence): reply = QMessageBox.question( self, "快捷键冲突", f"⚠️ 快捷键 {key_sequence.toString()} 可能与其他程序冲突。\n是否仍要使用此快捷键?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No ) if reply == QMessageBox.No: self.shortcut_edit.clear() return # 设置新的快捷键 self.setup_global_shortcut(key_sequence) self.save_settings() QMessageBox.information(self, "成功", f"✅ 已设置快捷键:{key_sequence.toString()}") def check_shortcut_conflict(self, key_sequence): """检查快捷键冲突(简单检查常见系统快捷键)""" key_string = key_sequence.toString().lower() # 常见的系统快捷键 system_shortcuts = [ "ctrl+c", "ctrl+v", "ctrl+x", "ctrl+z", "ctrl+y", "ctrl+a", "ctrl+s", "ctrl+alt+del", "ctrl+shift+esc", "alt+tab", "alt+f4", "win+l", "win+d", "win+r", "win+e", "win+i", "win+x", "ctrl+alt+t", "print screen", "alt+print screen", "ctrl+print screen" ] return key_string in system_shortcuts def setup_global_shortcut(self, key_sequence): """设置全局快捷键""" # 清除旧的快捷键 if self.global_shortcut: self.global_shortcut.setEnabled(False) self.global_shortcut = None # 设置新的快捷键 if not key_sequence.isEmpty(): self.global_shortcut = QShortcut(key_sequence, self) self.global_shortcut.activated.connect(self.turn_off_screen) def clear_shortcut(self): """清除快捷键""" self.shortcut_edit.clear() if self.global_shortcut: self.global_shortcut.setEnabled(False) self.global_shortcut = None self.save_settings() QMessageBox.information(self, "成功", "️ 已清除快捷键") def save_settings(self): """保存设置""" self.settings.setValue("autostart", self.autostart_checkbox.isChecked()) self.settings.setValue("minimize_on_start", self.minimize_on_start_checkbox.isChecked()) self.setandroidtings.setValue("shortcut", self.shortcut_edit.keySequence().toString()) self.settings.setValue("brightness_shortcut", self.brightness_shortcut_edit.keySequence().toString()) self.settings.setValue("brightness_level", self.brightness_slider.value()) def load_settings(self): """加载设置""" # 加载开机自启动状态 autostart_status = self.check_autostart_status() self.autostart_checkbox.setChecked(autostart_status) # 加载其他设置 minimize_on_start = self.settings.value("minimize_on_start", False, type=bool) self.minimize_on_start_checkbox.setChecked(minimize_on_start) shortcut_string = self.settings.value("shortcut", "", type=str) if shortcut_string: key_sequence = QKeySequence(shortcut_string) self.shortcut_edit.setKeySequence(key_sequence) self.setup_global_shortcut(key_sequence) brightness_shortcut_string = self.settings.value("brightness_shortcut", "", type=str) if brightness_shortcut_string: key_sequence = QKeySequence(brightness_shortcut_string) self.brightness_shortcut_edit.setKeySequence(key_sequence) self.setup_brightness_shortcut(key_sequence) brightness_level = self.settings.value("brightness_level", 80, type=int) self.brightness_slider.setValue(brightness_level) self.brightness_label.setText(f"{brightness_level}%") # 如果设置了启动时最小化,则隐藏到托盘 if minimize_on_start: self.hide() def showEvent(self, event): """窗口显示时检查权限""" super().showEvent(event) if not self.is_admin(): QMessageBox.warning(self, "权限提示", "⚠️ 建议以管理员权限运行此程序以确保所有功能正常工作") def closeEvent(self, event): """关闭事件处理""" if self.tray_icon and self.tray_icon.isVisible(): # 如果托盘图标可见,隐藏到托盘而不是退出 self.hide() event.ignore() if not hasattr(self, '_tray_message_shown'): self.tray_icon.showMessage( "程序已最小化到托盘", " 程序仍在后台运行,双击托盘图标可重新打开", QSystemTrayIcon.Information, 3000 ) self._tray_message_shown = True else: self.save_settings() event.accept() def main(): """主函数""" # 解析命令行参数 parser = argparse.ArgumentParser(description='Windows屏幕控制器') parser.add_argument('--minimized', action='store_true', help='启动时最小化到系统托盘') args = parser.parse_args() app = QApplication(sys.argv) # 设置应用程序样式 app.setStyle('Fusion') # 设置应用程序信息 app.setApplicationName("Windows屏幕控制器") app.setApplicationVersion("2.0") app.setOrganizationName("ScreenController") # 设置应用程序图标 app_path = get_app_path() icon_path = app_path / "favicon.ico" if icon_path.exists(): app.setWindowIcon(QIcon(str(icon_path))) window = ScreenController() # 如果指定了--minimized参数或设置了启动时最小化,则不显示主窗口 if args.minimized or window.minimize_on_start_checkbox.isChecked(): # 不显示主窗口,直接最小化到托盘 pass else: window.show() sys.exit(app.exec()) if __name__ == "__main__": # 检查并安装必要的依赖 try: import wmi import screeninfo import screen_brightness_control except ImportError: print("正在安装必要的依赖库...") try: import pip pip.main(['install', 'wmi', 'screeninfo', 'screen-brightness-control']) except: subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'wmi', 'screeninfo', 'screen-brightness-control']) main()
项目总结
这个Windows屏幕控制工具通过精心设计的UI和稳健的后台实现,解决了日常使用中的多个痛点:
- 一键操作:告别繁琐的系统设置路径
- 全局快捷键:随时随地快速息屏
- 亮度精细控制:保护眼睛健康
- 无感运行:系统托盘常驻不打扰
技术亮点:
- 多方法兼容的亮度控制
- 完善的异常处理机制
- 符合Windows应用规范的设置存储
- 优雅的系统托盘集成
扩展方向:
- 添加多显示器独立控制
- 实现根据时间自动调整亮度
- 增加使用统计和提醒功能
使用建议
- 建议以管理员权限运行以获得完整功能
- 设置开机自启动+最小化,实现无感运行
- 为息屏功能设置顺手的全局快捷键(如Ctrl+Alt+L)
到此这篇关于基于Python开发Windows屏幕控制工具的文章就介绍到这了,更多相关Python Windows屏幕控制内容请搜索China编程(www.chinasem.cn)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程China编程(www.chinasem.cn)!
这篇关于基于Python开发Windows屏幕控制工具的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!