基于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. 设置持久化
使用QSettings实现配置的自动保存和加载:
# 保存设置
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_start_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_app_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.KEY_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.settings.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屏幕控制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
