今天做一個本機鬧鐘:加入多個 HH:MM 時間,到點就跳出提醒並嗶一聲。
全程使用 Python 標準庫(Tkinter、datetime),零安裝、跨 Windows/macOS/Linux 可跑。
今天要解決的痛點
功能清單
程式碼(存成 alarm_basic.py)
import tkinter as tk
from tkinter import ttk, messagebox
from datetime import datetime
import re
ALARMS = set() # "HH:MM"
MUTED = False
FIRED_TODAY = set() # 記錄今日已觸發(避免同分鐘重複)
HHMM_RE = re.compile(r"^(?:[01]\d|2[0-3]):[0-5]\d$")
def now_hhmm(): return datetime.now().strftime("%H:%M")
def add_alarm():
s = entry.get().strip()
if not HHMM_RE.match(s):
messagebox.showerror("格式錯誤","請輸入 24 小時制時間,如 08:30、19:05"); return
if s in ALARMS:
messagebox.showinfo("提示", f"{s} 已存在"); return
ALARMS.add(s); refresh_list(); entry.delete(0, tk.END)
def delete_selected():
sel = listbox.curselection()
if not sel: return
hhmm = listbox.get(sel[0]).split()[0]
ALARMS.discard(hhmm); refresh_list()
def refresh_list():
listbox.delete(0, tk.END)
for t in sorted(ALARMS): listbox.insert(tk.END, f"{t} (每日)")
def toggle_mute():
global MUTED
MUTED = not MUTED
mute_btn.config(text=("解除靜音" if MUTED else "靜音"))
def tick_clock():
clock_var.set(f"現在時間:{now_hhmm()}"); root.after(1000, tick_clock)
def check_loop():
# 每秒檢查鬧鐘;跨日 00:00 會自動清空 FIRED_TODAY
now = datetime.now()
hhmm = now.strftime("%H:%M")
if hhmm == "00:00" and now.second == 0:
FIRED_TODAY.clear()
if hhmm in ALARMS and hhmm not in FIRED_TODAY:
FIRED_TODAY.add(hhmm); notify(hhmm)
root.after(1000, check_loop)
def notify(hhmm):
if not MUTED:
try: root.bell()
except Exception: pass
messagebox.showinfo("時間到!", f"{hhmm} 到點囉!")
# ----- GUI -----
root = tk.Tk(); root.title("多鬧鐘(基礎版)")
main = ttk.Frame(root, padding=16); main.grid(sticky="nsew")
root.columnconfigure(0, weight=1); root.rowconfigure(0, weight=1)
main.columnconfigure(0, weight=1); main.rowconfigure(2, weight=1)
row = ttk.Frame(main); row.grid(row=0, column=0, sticky="we")
ttk.Label(row, text="新增鬧鐘(HH:MM)").grid(row=0, column=0, padx=(0,8))
entry = ttk.Entry(row, width=8, justify="center"); entry.grid(row=0, column=1)
ttk.Button(row, text="加入", command=add_alarm).grid(row=0, column=2, padx=6)
mute_btn = ttk.Button(row, text="靜音", command=toggle_mute); mute_btn.grid(row=0, column=3)
clock_var = tk.StringVar(value=f"現在時間:{now_hhmm()}")
ttk.Label(main, textvariable=clock_var).grid(row=1, column=0, sticky="w", pady=(8,4))
listbox = tk.Listbox(main, height=10); listbox.grid(row=2, column=0, sticky="nsew")
scroll = ttk.Scrollbar(main, orient="vertical", command=listbox.yview)
scroll.grid(row=2, column=1, sticky="ns"); listbox.configure(yscrollcommand=scroll.set)
ops = ttk.Frame(main); ops.grid(row=3, column=0, sticky="we", pady=(8,0))
ttk.Button(ops, text="刪除選取", command=delete_selected).grid(row=0, column=0, padx=4)
ttk.Button(ops, text="離開", command=root.destroy).grid(row=0, column=1, padx=4)
root.bind("<Return>", lambda e: add_alarm())
root.bind("<Delete>", lambda e: delete_selected())
tick_clock(); check_loop(); entry.focus()
root.mainloop()
使用方式
python alarm_basic.py
實作:
常見問題(FAQ)
今日小結