You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Tkinter药品提醒程序问题:闹钟响后Snooze按钮不显示

解决Tkinter用药提醒程序中Snooze按钮不显示的问题

问题根源

你的代码里有两个核心问题导致Snooze按钮无法正常显示:

  • sd.wait()是阻塞式调用,会直接卡住Tkinter的主事件循环,必须等音频完全播放完毕才会执行create_snooze_button(),而且阻塞期间界面根本无法更新渲染按钮。
  • 每次触发闹钟都会创建新的Snooze按钮,不仅冗余,还会导致界面控件混乱。

修正方案

下面是修复后的完整代码,关键修改点已标注:

import tkinter as tk
import sounddevice as sd
import soundfile as sf

stop = False
interval = 0  # 初始化全局间隔变量
original_interval = 0  # 保存用户初始设定的间隔,用于Stop按钮重置

def start_alarm():
    global interval, original_interval, stop
    stop = False
    original_interval = int(entry.get())
    interval = original_interval
    time_left.config(text=f"{interval} seconds left")
    # 隐藏Snooze按钮(如果之前显示的话)
    snooze_button.pack_forget()
    countdown()

def stop_alarm():
    global stop
    stop = True
    sd.stop()
    # 隐藏Snooze按钮
    snooze_button.pack_forget()
    start_alarm()

def snooze_alarm():
    global stop, interval
    stop = True
    sd.stop()
    interval = 600  # 直接设置为10分钟(600秒),符合需求逻辑
    time_left.config(text=f"{interval} seconds left")
    # 隐藏Snooze按钮
    snooze_button.pack_forget()
    countdown()
    
def countdown():
    global interval, stop
    if interval > 0 and not stop:
        interval -= 1
        time_left.config(text=f"{interval} seconds left")
        time_left.after(1000, countdown)
    elif not stop:
        play_alarm()

def play_alarm():
    data, fs = sf.read('alarm.wav', dtype='float32')
    sd.play(data, fs)
    # 用Tkinter的after循环检查音频状态,替代阻塞的sd.wait()
    root.after(100, check_alarm_status)

def check_alarm_status():
    if sd.get_stream().active:
        # 音频还在播放,继续定时检查
        root.after(100, check_alarm_status)
    else:
        # 音频播放完毕,显示Snooze按钮
        snooze_button.pack()

root = tk.Tk()
root.title("Medicine Reminder")

label = tk.Label(root, text="Enter time interval (in seconds):")
label.pack()

entry = tk.Entry(root)
entry.pack()

start_button = tk.Button(root, text="Start", command=start_alarm)
start_button.pack()

stop_button = tk.Button(root, text="Stop", command=stop_alarm)
stop_button.pack()

# 提前创建Snooze按钮,默认隐藏,避免重复创建
snooze_button = tk.Button(root, text="Snooze", command=snooze_alarm)
snooze_button.pack_forget()

time_left = tk.Label(root, text="")
time_left.pack()

root.mainloop()

关键修改说明

  1. 替换阻塞的sd.wait():改用root.after()循环检查音频播放状态,彻底避免卡住Tkinter主事件循环,保证界面能实时更新。
  2. 提前创建并控制Snooze按钮:一开始就完成按钮创建,用pack()/pack_forget()控制显示和隐藏,不会重复生成控件。
  3. 修正Snooze逻辑:把interval +=600改成interval =600,因为闹钟触发时interval已经归零,直接设置为10分钟才符合需求。
  4. 新增初始间隔保存:用original_interval存储用户最初设置的时长,Stop按钮触发时能准确重置回初始值,避免原代码中重新读取输入框的潜在问题。
  5. 全局变量初始化:提前初始化核心全局变量,避免未定义报错。

内容的提问来源于stack exchange,提问作者Legend_recalls

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 00:05:25