Compare commits

3 Commits

Author SHA1 Message Date
dbaff55d3a feat(焦点管理): 添加微缩模式时自动归还焦点功能
新增 return_focus_to_previous_window 方法,在切换到微缩模式时自动清除当前窗口焦点并将其置于其他窗口下方,同时尝试激活上一个窗口。更新README文档说明新增功能特性。
2026-01-22 14:17:09 +08:00
74b1de9b3a style: 调整计时器窗口的边距参数
将右侧边距从200改为40,顶部边距从50改为30,使窗口位置更紧凑
2026-01-22 13:49:51 +08:00
81fc433690 feat: 适配分支机构版本界面样式 2026-01-22 11:23:15 +08:00
3 changed files with 223 additions and 35 deletions

187
README(分支机构).md Normal file
View File

@@ -0,0 +1,187 @@
# 述职计时器(分支机构版)
一个使用 PySide6 构建的倒计时应用程序,专为述职演讲设计,美观大方,支持多种倒计时模式。
## 最新更新
- **界面优化**:采用浅蓝色调设计,更加清新美观
- **按钮调整**:将原来的"5分钟"和"6分钟"按钮合并为"4分钟"按钮
- **位置优化**微缩窗口默认距离右边缘40像素距离上边缘30像素
- **焦点管理**:切换到微缩模式时自动将焦点还给上一个进程
## 功能特点
### 界面设计
- **浅蓝色调**:采用清新的浅蓝色(#e8f4f8)作为主色调
- **圆角设计**15px圆角边框美观大方
- **无标题栏**:可通过拖动窗口任意位置移动窗口
- **两种状态**:正常状态和微缩状态
### 界面状态
程序有两种界面状态:
#### 1. 正常状态
- 显示倒计时时间和完整的按钮区域
- 可以通过拖动窗口的任何位置来移动窗口
- 显示按钮区域:"4分钟"和"其它"按钮
- 窗口大小500×300像素
#### 2. 微缩状态
- 点击"4分钟"按钮开始倒计时后延迟2秒自动切换到微缩状态
- 只显示倒计时时间
- 窗口大小120×50像素
- 位置距离屏幕上边缘30像素距离右边缘40像素可配置
- **焦点管理**:切换到微缩状态时自动将焦点还给上一个进程
- 双击界面后暂停倒计时,并切换回正常状态
### 快捷按钮
- **4分钟**开始4分钟240秒倒计时
- **其它**:打开配置对话框
### 配置功能
点击"其它"按钮可以打开配置对话框:
| 配置项 | 说明 | 默认值 |
|--------|------|--------|
| 自定义秒数 | 设置自定义倒计时时间1-3600秒 | 240秒 |
| 提前告警(秒) | 设置倒计时结束前多少秒播放告警提示音 | 30秒 |
| 窗口置顶 | 设置窗口是否置顶 | 开启 |
| 窗口透明度 | 设置窗口透明度10%-100% | 100% |
| 距离右边缘 | 微缩窗口距离屏幕右边缘的像素值 | 40像素 |
| 距离上边缘 | 微缩窗口距离屏幕上边缘的像素值 | 30像素 |
| 测试告警 | 测试告警提示音 | - |
| 退出程序 | 退出程序(唯一退出方式) | - |
### 告警功能
- **提前告警**:倒计时结束前设置的秒数时播放告警提示音
- **循环播放**告警音循环播放3次
- **音量控制**告警音音量设置为80%
- **倒计时结束效果**
- 微缩模式:文字红黄闪烁效果
- 正常模式:文字跳动 + 透明度闪烁效果
### 音频支持
- 支持自定义告警音效
- 优先从外部目录加载 `alarm.wav` 音频文件
- 若外部未找到,则使用内置音频文件
### 焦点管理
- **智能焦点归还**:切换到微缩模式时自动将焦点还给上一个进程
- **窗口层级管理**:微缩窗口自动置于其他窗口下方
- **无干扰设计**:不影响用户在其他应用程序中的操作
## 使用说明
### 快速开始
1. 运行程序(双击 `countdown.exe` 或运行 `python countdown.py`
2. 程序启动后显示正常状态界面
3. 点击"4分钟"按钮开始4分钟倒计时
4. 2秒后自动切换到微缩状态
5. 在微缩状态下双击可以暂停并回到正常状态
### 详细操作指南
#### 1. 启动程序
- 方法一:双击 `countdown.exe`(已打包版本)
- 方法二:运行 `python countdown.py`(源代码版本)
#### 2. 开始倒计时
- 点击"4分钟"按钮开始4分钟倒计时
- 点击"其它"按钮 → 设置自定义时间 → 点击"开始倒计时":使用自定义时间
#### 3. 窗口操作
- **移动窗口**:在正常状态下,拖动窗口任意位置可移动窗口
- **切换状态**开始倒计时后2秒自动切换到微缩状态
- **恢复状态**:在微缩状态下双击窗口可暂停倒计时并恢复为正常状态
#### 4. 配置设置
1. 点击"其它"按钮打开配置对话框
2. 根据需要调整各项配置:
- 设置自定义倒计时时间
- 调整提前告警时间
- 开启/关闭窗口置顶
- 调整窗口透明度
- 设置微缩窗口位置
3. 点击"确认并保存"应用设置
4. 点击"测试告警"测试告警音效
5. 点击"退出程序"退出应用程序
#### 5. 告警提示
- 倒计时结束前30秒默认会播放告警提示音
- 告警音循环播放3次
- 倒计时结束时显示"时间已到"并有视觉特效
### 音频配置
1. 准备一个 `alarm.wav` 音频文件
2. 将文件放置在以下位置之一:
-`countdown.exe` 同一目录
- 当前工作目录
3. 程序会优先加载外部音频文件
## 技术栈
- **编程语言**Python 3.11+
- **GUI框架**PySide6 (Qt 6)
- **音频支持**Qt Multimedia
- **打包工具**PyInstaller
## 打包命令
```bash
python -m PyInstaller --onefile --windowed --icon=Timer.ico --name=述职计时器 countdown.py
```
## 文件说明
| 文件 | 说明 |
|------|------|
| `countdown.py` | 主程序源代码 |
| `Timer.ico` | 程序图标文件 |
| `alarm.wav` | 默认告警音频文件 |
| `2alarm.wav` | 备用告警音频文件 |
| `README.md` | 原始说明文档 |
| `README分支机构.md` | 分支机构版说明文档(本文档) |
| `操作手册.md` | 详细操作手册 |
| `要求.txt` | 功能需求文档 |
| `clean.py` | 清理打包残留文件 |
| `SKILL.md` | 打包技巧说明 |
## 开发说明
### 代码结构
- `TimerApp` 类:主应用程序类
- `ConfigDialog` 类:配置对话框类
- 主要方法:
- `init_ui()`:初始化用户界面
- `start_countdown()`:开始倒计时
- `set_mini_state()`:切换到微缩状态
- `return_focus_to_previous_window()`:焦点归还功能
- `open_config()`:打开配置对话框
### 关键特性实现
1. **无标题栏窗口**:使用 `Qt.FramelessWindowHint`
2. **窗口拖动**:重写 `mousePressEvent``mouseMoveEvent`
3. **微缩状态**:定时器控制状态切换
4. **焦点管理**:使用 `clearFocus()``lower()``requestActivate()`
5. **音频播放**:使用 `QSoundEffect` 播放告警音
### 自定义修改
如需自定义程序,可修改以下部分:
- 界面颜色:修改 `setStyleSheet` 中的颜色值
- 按钮时间:修改 `start_countdown` 中的时间参数
- 窗口位置:修改 `config` 字典中的 `right_margin``top_margin`
- 音频文件:替换 `alarm.wav` 文件
## 注意事项
1. 首次运行请确保 `alarm.wav` 与可执行文件在同一目录
2. 微缩窗口位置可在配置中自定义调整
3. 程序退出必须通过配置对话框中的"退出程序"按钮
4. 焦点归还功能仅在切换到微缩状态时生效
5. 窗口置顶功能可能在某些系统上表现不同
## 版本历史
- **v1.0**基础版本支持5分钟和6分钟倒计时
- **v1.1**:界面优化,改为浅蓝色调
- **v1.2**按钮调整合并为4分钟按钮
- **v1.3**:位置优化,微缩窗口位置调整
- **v1.4**:焦点管理,自动归还焦点功能
## 支持与反馈
如有问题或建议,请参考源代码进行调试或联系开发人员。

View File

@@ -107,12 +107,12 @@ class TimerApp(QWidget):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.config = { self.config = {
'duration': 300, 'duration': 240,
'alarm_offset': 30, 'alarm_offset': 30,
'stay_on_top': True, 'stay_on_top': True,
'opacity': 1.0, 'opacity': 1.0,
'right_margin': 200, # 距离右边缘 'right_margin': 40, # 距离右边缘
'top_margin': 50 # 距离上边缘 'top_margin': 30 # 距离上边缘
} }
self.remaining_time = 0 self.remaining_time = 0
self.is_running = False self.is_running = False
@@ -129,19 +129,19 @@ class TimerApp(QWidget):
self.setAttribute(Qt.WA_TranslucentBackground) self.setAttribute(Qt.WA_TranslucentBackground)
self.setStyleSheet(""" self.setStyleSheet("""
QWidget#MainFrame { QWidget#MainFrame {
background-color: #2c3e50; background-color: #e8f4f8;
border-radius: 15px; border-radius: 15px;
border: 2px solid #34495e; border: 2px solid #b0d4e3;
} }
QLabel { color: #ecf0f1; font-family: 'Segoe UI', Arial; } QLabel { color: #2c3e50; font-family: 'Segoe UI', Arial; }
QPushButton { QPushButton {
background-color: #3498db; background-color: #5dade2;
color: white; color: white;
border-radius: 5px; border-radius: 5px;
padding: 8px; padding: 8px;
font-weight: bold; font-weight: bold;
} }
QPushButton:hover { background-color: #2980b9; } QPushButton:hover { background-color: #3498db; }
""") """)
self.main_layout = QVBoxLayout(self) self.main_layout = QVBoxLayout(self)
@@ -168,16 +168,13 @@ class TimerApp(QWidget):
# 按钮区域 # 按钮区域
self.btn_area = QWidget() self.btn_area = QWidget()
self.btn_layout = QHBoxLayout(self.btn_area) self.btn_layout = QHBoxLayout(self.btn_area)
self.btn_5m = QPushButton("5分钟") self.btn_4m = QPushButton("4分钟")
self.btn_6m = QPushButton("6分钟")
self.btn_other = QPushButton("其它") self.btn_other = QPushButton("其它")
self.btn_5m.clicked.connect(lambda: self.start_countdown(300)) self.btn_4m.clicked.connect(lambda: self.start_countdown(240))
self.btn_6m.clicked.connect(lambda: self.start_countdown(360))
self.btn_other.clicked.connect(self.open_config) self.btn_other.clicked.connect(self.open_config)
self.btn_layout.addWidget(self.btn_5m) self.btn_layout.addWidget(self.btn_4m)
self.btn_layout.addWidget(self.btn_6m)
self.btn_layout.addWidget(self.btn_other) self.btn_layout.addWidget(self.btn_other)
self.content_layout.addWidget(self.btn_area) self.content_layout.addWidget(self.btn_area)
@@ -268,6 +265,9 @@ class TimerApp(QWidget):
y = self.config['top_margin'] y = self.config['top_margin']
self.move(x, y) self.move(x, y)
# 将焦点还给上一个进程
self.return_focus_to_previous_window()
def center_on_screen(self): def center_on_screen(self):
screen = QApplication.primaryScreen() screen = QApplication.primaryScreen()
screen_geometry = screen.availableGeometry() screen_geometry = screen.availableGeometry()
@@ -301,7 +301,7 @@ class TimerApp(QWidget):
if hasattr(self, 'color_anim') and self.color_anim is not None: if hasattr(self, 'color_anim') and self.color_anim is not None:
self.color_anim.stop() self.color_anim.stop()
self.label_time.setStyleSheet("color: #ecf0f1;") self.label_time.setStyleSheet("color: #2c3e50;")
self.is_running = True self.is_running = True
@@ -385,6 +385,24 @@ class TimerApp(QWidget):
self.anim_group.addAnimation(self.flash_anim) self.anim_group.addAnimation(self.flash_anim)
self.anim_group.start() self.anim_group.start()
def return_focus_to_previous_window(self):
# 清除当前窗口的焦点
self.clearFocus()
# 将窗口置于其他窗口下方
self.lower()
# 尝试激活其他窗口
app = QApplication.instance()
windows = app.topLevelWindows()
# 找到不是当前窗口的其他窗口
for window in windows:
if window != self.windowHandle() and window.isVisible():
# 尝试激活其他窗口
window.requestActivate()
break
def open_config(self): def open_config(self):
dialog = ConfigDialog(self, self.config) dialog = ConfigDialog(self, self.config)
if dialog.exec() == QDialog.Accepted: if dialog.exec() == QDialog.Accepted:

View File

@@ -2,7 +2,7 @@
## 一、概述 ## 一、概述
述职计时器是一款专为述职演讲设计的倒计时工具,支持快捷计时、提前告警、微缩悬浮窗口等功能 述职计时器是一款专为述职演讲设计的倒计时工具。
## 二、快速开始 ## 二、快速开始
@@ -26,7 +26,7 @@
| 配置项 | 说明 | | 配置项 | 说明 |
|--------|------| |--------|------|
| 自定义秒数 | 设置自定义倒计时时长1-3600秒 | | 自定义秒数 | 设置自定义倒计时时长1-3600秒可用来测试 |
| 提前告警(秒) | 设置提前播放告警音的时间0-300秒 | | 提前告警(秒) | 设置提前播放告警音的时间0-300秒 |
| 窗口置顶 | 勾选后窗口始终保持在其他窗口上方 | | 窗口置顶 | 勾选后窗口始终保持在其他窗口上方 |
| 透明度 | 调节窗口透明度10%-100% | | 透明度 | 调节窗口透明度10%-100% |
@@ -54,24 +54,7 @@
-`alarm.wav` 音频文件放置在 **exe 同目录****当前工作目录** -`alarm.wav` 音频文件放置在 **exe 同目录****当前工作目录**
- 程序会优先从外部目录加载,若未找到则使用内置音频 - 程序会优先从外部目录加载,若未找到则使用内置音频
## 五、打包说明 ## 五、注意事项
### 5.1 打包命令
```bash
pyinstaller --onefile --windowed --noconsole --icon=Timer.ico countdown.py
```
参数说明:
- `--onefile`打包成单个exe文件
- `--windowed` / `--noconsole`:不显示控制台窗口
- `--icon`:指定程序图标
### 5.2 清理残留文件
运行 `clean.py` 可自动清理打包残留文件并重新生成exe。
## 六、注意事项
1. 首次运行请确保 `alarm.wav` 与 exe 在同一目录,否则告警功能不可用 1. 首次运行请确保 `alarm.wav` 与 exe 在同一目录,否则告警功能不可用
2. 微缩窗口位置可在配置中自定义 2. 微缩窗口位置可在配置中自定义