windows定时闹钟

特点:会播报当前时间、距离ddl还剩多少时间,避免赖床

import tkinter as tk
from tkinter import ttk, messagebox
import datetime, time, threading, json, os, pyttsx3


class AlarmClock:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("定时闹钟")
        self.root.geometry("500x400")
        
        self.init_voice_engine()
        self.config_file = "alarm_config.json"
        self.custom_message = self.load_custom_message()
        self.target_event = "上班"  # 默认事件名称
        
        self.setup_ui()
        self.alarm_thread = None
        self.voice_thread = None
        self.is_running = False
        self.is_alarming = False
    
    def init_voice_engine(self):
        self.engine = pyttsx3.init()
        self.engine.setProperty('rate', 150)
        self.engine.setProperty('volume', 1.0)
        
        voices = self.engine.getProperty('voices')
        for voice in voices:
            if "chinese" in voice.id.lower():
                self.engine.setProperty('voice', voice.id)
                break
    
    def num_to_chinese(self, num):
        """将数字转换为中文"""
        chinese_numbers = {
            '0': '零', '1': '一', '2': '二', '3': '三', '4': '四',
            '5': '五', '6': '六', '7': '七', '8': '八', '9': '九', '10': '十'
        }
        if num <= 10:
            return chinese_numbers.get(str(num), str(num))
        elif num < 20:
            return f"十{chinese_numbers.get(str(num-10), '')}"
        elif num < 100:
            tens = num // 10
            ones = num % 10
            if ones == 0:
                return f"{chinese_numbers.get(str(tens), '')}十"
            return f"{chinese_numbers.get(str(tens), '')}{chinese_numbers.get(str(ones), '')}"
        return str(num)

    def generate_reminder_text(self, target_time):
        """生成动态提醒文本"""
        now = datetime.datetime.now()
        current_hour = now.hour
        current_minute = now.minute
        
        # 计算剩余时间(分钟)
        time_diff = target_time - now
        remaining_minutes = int(time_diff.total_seconds() / 60)

        final_time = "2024-11-10 13:30:00"
        final_time = datetime.datetime.strptime(final_time, "%Y-%m-%d %H:%M:%S")

        time_diff = final_time - now
        remaining_minutes = int(time_diff.total_seconds() / 60)
        
        # 生成提醒文本
        text = f"现在已经{self.num_to_chinese(current_hour)}{self.num_to_chinese(current_minute)}分,"
        text += f"距离{self.num_to_chinese(final_time.hour)}{self.num_to_chinese(final_time.minute)}{self.target_event}还剩{self.num_to_chinese(remaining_minutes)}分钟"
        
        return text
    
    def speak_loop(self, target_time):
        """循环播放动态语音"""
        while self.is_alarming:
            try:
                # 生成动态提醒文本
                reminder_text = self.generate_reminder_text(target_time)
                # 更新状态显示
                self.root.after(0, lambda: self.status_var.set(reminder_text))
                # 播放语音
                self.engine.say(reminder_text)
                self.engine.runAndWait()
                # 等待一段时间再播放下一次
                time.sleep(2)
            except Exception as e:
                print(f"语音播放出错:{str(e)}")
                time.sleep(1)
    
    def start_alarm_sound(self, target_time):
        """开始循环播放警报声"""
        self.is_alarming = True
        self.voice_thread = threading.Thread(target=self.speak_loop, 
                                          args=(target_time,),
                                          daemon=True)
        self.voice_thread.start()
    
    def stop_alarm_sound(self):
        """停止警报声"""
        self.is_alarming = False
        if self.voice_thread:
            self.voice_thread.join(timeout=2)
    
    def load_custom_message(self):
        if os.path.exists(self.config_file):
            try:
                with open(self.config_file, 'r', encoding='utf-8') as f:
                    config = json.load(f)
                    return config.get('target_event', '上班')
            except:
                return '上班'
        return '上班'
    
    def save_custom_message(self):
        with open(self.config_file, 'w', encoding='utf-8') as f:
            json.dump({'target_event': self.target_event}, f, ensure_ascii=False)
    
    def setup_ui(self):
        # 时间设置框架
        time_frame = ttk.LabelFrame(self.root, text="目标时间设置", padding="10")
        time_frame.pack(fill="x", padx=10, pady=5)
        
        # 小时选择
        ttk.Label(time_frame, text="小时:").grid(row=0, column=0, padx=5)
        self.hour_var = tk.StringVar(value="9")
        self.hour_spinbox = ttk.Spinbox(time_frame, from_=0, to=23, width=5, 
                                      textvariable=self.hour_var)
        self.hour_spinbox.grid(row=0, column=1, padx=5)
        
        # 分钟选择
        ttk.Label(time_frame, text="分钟:").grid(row=0, column=2, padx=5)
        self.minute_var = tk.StringVar(value="0")
        self.minute_spinbox = ttk.Spinbox(time_frame, from_=0, to=59, width=5,
                                        textvariable=self.minute_var)
        self.minute_spinbox.grid(row=0, column=3, padx=5)
        
        # 事件名称设置
        event_frame = ttk.LabelFrame(self.root, text="事件设置", padding="10")
        event_frame.pack(fill="x", padx=10, pady=5)
        
        ttk.Label(event_frame, text="事件名称:").pack(side="left", padx=5)
        self.event_var = tk.StringVar(value=self.target_event)
        self.event_entry = ttk.Entry(event_frame, textvariable=self.event_var)
        self.event_entry.pack(side="left", fill="x", expand=True, padx=5)
        
        # 测试按钮
        self.test_button = ttk.Button(self.root, text="测试提示音", 
                                    command=self.test_voice)
        self.test_button.pack(pady=5)
        
        # 控制按钮
        button_frame = ttk.Frame(self.root)
        button_frame.pack(pady=10)
        
        self.start_button = ttk.Button(button_frame, text="开始", 
                                     command=self.start_alarm)
        self.start_button.pack(side="left", padx=5)
        
        self.stop_button = ttk.Button(button_frame, text="停止", 
                                    command=self.stop_alarm,
                                    state="disabled")
        self.stop_button.pack(side="left", padx=5)
        
        # 状态显示
        self.status_var = tk.StringVar(value="未启动")
        self.status_label = ttk.Label(self.root, textvariable=self.status_var,
                                    wraplength=400)  # 允许文本换行
        self.status_label.pack(pady=10)
        
        # 置顶按钮
        self.topmost_var = tk.BooleanVar(value=False)
        self.topmost_check = ttk.Checkbutton(self.root, text="窗口置顶", 
                                           variable=self.topmost_var,
                                           command=self.toggle_topmost)
        self.topmost_check.pack(pady=5)
    
    def toggle_topmost(self):
        self.root.attributes('-topmost', self.topmost_var.get())
    
    def test_voice(self):
        """测试语音按钮的回调函数"""
        try:
            hours = int(self.hour_var.get())
            minutes = int(self.minute_var.get())
            target_time = datetime.datetime.now().replace(hour=hours, minute=minutes)
            test_text = self.generate_reminder_text(target_time)
            
            # 在新线程中播放测试语音
            threading.Thread(target=lambda: self.engine.say(test_text) or 
                           self.engine.runAndWait(),
                           daemon=True).start()
        except ValueError:
            messagebox.showerror("错误", "请输入有效的时间!")
    
    def start_alarm(self):
        try:
            hours = int(self.hour_var.get())
            minutes = int(self.minute_var.get())
            
            if hours < 0 or hours > 23 or minutes < 0 or minutes > 59:
                messagebox.showerror("错误", "请输入有效的时间!")
                return
            
            # 保存事件名称
            self.target_event = self.event_var.get()
            self.save_custom_message()
            
            # 计算目标时间
            target_time = datetime.datetime.now().replace(hour=hours, 
                                                        minute=minutes,
                                                        second=0, 
                                                        microsecond=0)
            
            # 如果目标时间已过,设置为明天
            if target_time <= datetime.datetime.now():
                target_time += datetime.timedelta(days=1)
            
            self.is_running = True
            self.alarm_thread = threading.Thread(target=self.run_alarm, 
                                              args=(target_time,))
            self.alarm_thread.daemon = True
            self.alarm_thread.start()
            
            self.start_button.config(state="disabled")
            self.stop_button.config(state="normal")
            self.status_var.set(f"闹钟将在 {target_time.strftime('%H:%M')} 响起")
            
        except ValueError:
            messagebox.showerror("错误", "请输入有效的数字!")
    
    def stop_alarm(self):
        self.is_running = False
        self.stop_alarm_sound()
        self.start_button.config(state="normal")
        self.stop_button.config(state="disabled")
        self.status_var.set("已停止")
    
    def run_alarm(self, target_time):
        while self.is_running:
            now = datetime.datetime.now()
            if now >= target_time:
                # 开始循环播放动态警报声
                self.start_alarm_sound(target_time)
                break
            time.sleep(1)
    
    def run(self):
        self.root.mainloop()

if __name__ == "__main__":
    alarm = AlarmClock()
    alarm.run()
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值