2121
2222# 全局变量,用于跟踪当前的悬浮窗口
2323float_window = None
24+ timer_job = None
25+ timer_active = False
26+ current_phase = None
2427root = None
2528entry = None
29+ start_button = None
2630tray_icon = None
2731tray_thread = None
2832tray_visible = False
2933action_queue = queue .SimpleQueue ()
3034
3135
3236if sys .platform == "win32" :
37+
3338 class TrayIcon (pystray .Icon ):
3439 def _on_notify (self , wparam , lparam ):
3540 if lparam == pystray_win32 .win32 .WM_LBUTTONUP :
@@ -43,7 +48,8 @@ def _on_notify(self, wparam, lparam):
4348 hmenu , descriptors = self ._menu_handle
4449 index = pystray_win32 .win32 .TrackPopupMenuEx (
4550 hmenu ,
46- pystray_win32 .win32 .TPM_LEFTALIGN | pystray_win32 .win32 .TPM_BOTTOMALIGN
51+ pystray_win32 .win32 .TPM_LEFTALIGN
52+ | pystray_win32 .win32 .TPM_BOTTOMALIGN
4753 | pystray_win32 .win32 .TPM_RETURNCMD ,
4854 point .x ,
4955 point .y ,
@@ -128,12 +134,48 @@ def start_break_session():
128134 start_timer (work_time = get_focus_minutes () * 60 , break_time = DEFAULT_BREAK_TIME , is_work_time = False )
129135
130136
137+ def update_timer_controls ():
138+ if start_button is not None and root is not None and root .winfo_exists ():
139+ if timer_active :
140+ start_button .config (text = "停止" , command = stop_current_timer )
141+ else :
142+ start_button .config (text = "开始" , command = start_focus_session )
143+ refresh_tray_menu ()
144+
145+
146+ def clear_timer_state (cancel_job = True , destroy_window = True ):
147+ global float_window , timer_job , timer_active , current_phase
148+
149+ timer_active = False
150+ current_phase = None
151+
152+ if cancel_job and timer_job is not None and root is not None and root .winfo_exists ():
153+ try :
154+ root .after_cancel (timer_job )
155+ except tk .TclError :
156+ pass
157+ timer_job = None
158+
159+ if destroy_window and float_window is not None :
160+ try :
161+ if float_window .winfo_exists ():
162+ float_window .destroy ()
163+ except tk .TclError :
164+ pass
165+ float_window = None
166+ update_timer_controls ()
167+
168+
169+ def stop_current_timer ():
170+ clear_timer_state ()
171+
172+
131173def start_timer (work_time = DEFAULT_WORK_TIME , break_time = DEFAULT_BREAK_TIME , is_work_time = True ):
132- global float_window
174+ global float_window , timer_job , timer_active , current_phase
133175
134- # 如果已经存在一个悬浮窗口,先销毁它
135- if float_window is not None :
136- float_window . destroy ()
176+ clear_timer_state ()
177+ timer_active = True
178+ current_phase = "work" if is_work_time else "break"
137179
138180 # 创建新的悬浮窗口
139181 float_window = tk .Toplevel (root )
@@ -167,16 +209,22 @@ def do_move(event):
167209
168210 float_window .bind ("<Button-1>" , start_move )
169211 float_window .bind ("<B1-Motion>" , do_move )
212+ update_timer_controls ()
170213
171214 # 倒计时功能
172215 def countdown (count ):
216+ global timer_job
217+
218+ if not timer_active or float_window is None or not float_window .winfo_exists ():
219+ return
220+
173221 mins , secs = divmod (count , 60 )
174222 time_format = '{:02d}:{:02d}' .format (mins , secs )
175223 label .config (text = time_format )
176224 if count > 0 :
177- float_window .after (1000 , countdown , count - 1 )
225+ timer_job = float_window .after (1000 , countdown , count - 1 )
178226 else :
179- float_window . destroy ( )
227+ clear_timer_state ( cancel_job = False )
180228 if is_work_time :
181229 messagebox .showinfo ("时间到" , "工作时间结束!休息一下吧~" )
182230 start_timer (work_time = work_time , break_time = break_time , is_work_time = False ) # 开始休息时间
@@ -202,6 +250,10 @@ def get_window_toggle_text(item=None):
202250 return "最小化窗口" if is_root_visible () else "显示窗口"
203251
204252
253+ def is_timer_active (item = None ):
254+ return timer_active
255+
256+
205257def refresh_tray_menu ():
206258 if tray_icon is not None :
207259 tray_icon .update_menu ()
@@ -217,6 +269,7 @@ def create_tray_menu():
217269 pystray .MenuItem (get_window_toggle_text , enqueue_tray_action ("toggle_window" )),
218270 pystray .MenuItem ("开始专注" , enqueue_tray_action ("start_focus" )),
219271 pystray .MenuItem ("开始休息" , enqueue_tray_action ("start_break" )),
272+ pystray .MenuItem ("停止计时" , enqueue_tray_action ("stop_timer" ), visible = is_timer_active ),
220273 pystray .MenuItem ("退出" , enqueue_tray_action ("quit" )),
221274 )
222275
@@ -356,11 +409,8 @@ def on_leave(event):
356409
357410
358411def quit_application ():
359- global float_window
360-
412+ stop_current_timer ()
361413 hide_tray_icon ()
362- if float_window is not None and float_window .winfo_exists ():
363- float_window .destroy ()
364414 root .destroy ()
365415
366416
@@ -380,6 +430,8 @@ def process_tray_actions():
380430 start_focus_session ()
381431 elif action == "start_break" :
382432 start_break_session ()
433+ elif action == "stop_timer" :
434+ stop_current_timer ()
383435 elif action == "quit" :
384436 quit_application ()
385437 return
@@ -494,6 +546,7 @@ def on_leave(event):
494546 about_button .place (relx = 0.9 , rely = 0.1 , anchor = 'center' )
495547
496548 root .update_idletasks ()
549+ update_timer_controls ()
497550 show_tray_icon ()
498551 root .deiconify ()
499552 root .after (200 , process_tray_actions )
0 commit comments