@@ -261,10 +261,38 @@ def __init__(self, master: Any, settings: Settings) -> None:
261261 self ._stop_event = threading .Event ()
262262 self ._bot_app = None
263263 self ._bot_handler = None
264+ self ._alive = True
264265
265266 self ._build ()
266267 self ._start_status_poll ()
267268
269+ def _safe_after (self , delay : int , func , * args , ** kwargs ) -> str | None :
270+ if not self ._alive :
271+ return None
272+ try :
273+ if not self .winfo_exists ():
274+ return None
275+ except Exception :
276+ return None
277+ def wrapper ():
278+ if not self ._alive :
279+ return
280+ try :
281+ if not self .winfo_exists ():
282+ return
283+ except Exception :
284+ return
285+ func (* args , ** kwargs )
286+ return self .after (delay , wrapper )
287+
288+ def destroy (self ) -> None :
289+ self ._alive = False
290+ if self .bot_running :
291+ self ._stop_bot ()
292+ import time
293+ time .sleep (0.5 )
294+ super ().destroy ()
295+
268296 def _build (self ) -> None :
269297 self .grid_columnconfigure (0 , weight = 1 )
270298 self .grid_columnconfigure (1 , weight = 1 )
@@ -357,11 +385,15 @@ def _build(self) -> None:
357385 _CTkButtonSecondary (btn_logs_frame , text = "Export Logs" , command = self ._export_logs , height = 36 , width = 120 ).pack (side = "left" )
358386
359387 def _log_callback (self , msg : str ) -> None :
360- self .after (0 , lambda : self ._append_log ( msg ) )
388+ self ._safe_after (0 , self ._append_log , msg )
361389
362390 def _append_log (self , msg : str ) -> None :
363- self .log_text .insert ("end" , msg + "\n " )
364- self .log_text .see ("end" )
391+ try :
392+ if self .winfo_exists ():
393+ self .log_text .insert ("end" , msg + "\n " )
394+ self .log_text .see ("end" )
395+ except Exception :
396+ pass
365397
366398 def _clear_logs (self ) -> None :
367399 self .log_text .delete ("1.0" , "end" )
@@ -382,8 +414,8 @@ def _start_status_poll(self) -> None:
382414 self ._poll_status ()
383415
384416 def _poll_status (self ) -> None :
385- self .after (0 , self ._do_poll )
386- self .after (5000 , self ._poll_status )
417+ self ._safe_after (0 , self ._do_poll )
418+ self ._safe_after (5000 , self ._poll_status )
387419
388420 def _do_poll (self ) -> None :
389421 def check ():
@@ -393,9 +425,9 @@ def check():
393425 health = loop .run_until_complete (self .client .health ())
394426 loop .close ()
395427 status_val = health .get ("healthy" , health .get ("status" , "unknown" ))
396- self .after (0 , lambda : self .server_label .configure (text = f"Server: { status_val } " , text_color = COLORS ["success" ]))
428+ self ._safe_after (0 , lambda : self .server_label .configure (text = f"Server: { status_val } " , text_color = COLORS ["success" ]))
397429 except Exception :
398- self .after (0 , lambda : self .server_label .configure (text = "Server: Offline" , text_color = COLORS ["error" ]))
430+ self ._safe_after (0 , lambda : self .server_label .configure (text = "Server: Offline" , text_color = COLORS ["error" ]))
399431
400432 threading .Thread (target = check , daemon = True ).start ()
401433
@@ -500,14 +532,14 @@ async def run():
500532 await app .initialize ()
501533 await app .start ()
502534 await app .updater .start_polling (drop_pending_updates = True )
503- self .after (0 , lambda : self .bot_label .configure (text = "Bot: Running" , text_color = COLORS ["success" ]))
504- self .after (0 , lambda : self ._append_log ( "Bot polling started." ) )
535+ self ._safe_after (0 , lambda : self .bot_label .configure (text = "Bot: Running" , text_color = COLORS ["success" ]))
536+ self ._safe_after (0 , self ._append_log , "Bot polling started." )
505537 while not self ._stop_event .is_set ():
506538 await asyncio .sleep (0.5 )
507539 except Exception as exc :
508540 err_msg = f"Bot error: { exc } "
509- self .after (0 , lambda m = err_msg : self ._append_log ( m ) )
510- self .after (0 , lambda : self .bot_label .configure (text = "Bot: Error" , text_color = COLORS ["error" ]))
541+ self ._safe_after (0 , self ._append_log , err_msg )
542+ self ._safe_after (0 , lambda : self .bot_label .configure (text = "Bot: Error" , text_color = COLORS ["error" ]))
511543 finally :
512544 try :
513545 if app .updater .running :
@@ -521,19 +553,19 @@ async def run():
521553 except Exception :
522554 pass
523555 scheduler .stop ()
524- self .after (0 , lambda : self .bot_label .configure (text = "Bot: Stopped" , text_color = COLORS ["text_secondary" ]))
525- self .after (0 , lambda : self ._append_log ( "Bot stopped." ) )
556+ self ._safe_after (0 , lambda : self .bot_label .configure (text = "Bot: Stopped" , text_color = COLORS ["text_secondary" ]))
557+ self ._safe_after (0 , self ._append_log , "Bot stopped." )
526558 self .bot_running = False
527- self .after (0 , lambda : self .start_bot_btn .configure (text = "Start Bot" , fg_color = COLORS ["accent" ], text_color = "#FFFFFF" ))
559+ self ._safe_after (0 , lambda : self .start_bot_btn .configure (text = "Start Bot" , fg_color = COLORS ["accent" ], text_color = "#FFFFFF" ))
528560
529561 loop = asyncio .new_event_loop ()
530562 asyncio .set_event_loop (loop )
531563 try :
532564 loop .run_until_complete (run ())
533565 except Exception as exc :
534566 err_msg = f"Bot loop error: { exc } "
535- self .after (0 , lambda m = err_msg : self ._append_log ( m ) )
536- self .after (0 , lambda : self .bot_label .configure (text = "Bot: Error" , text_color = COLORS ["error" ]))
567+ self ._safe_after (0 , self ._append_log , err_msg )
568+ self ._safe_after (0 , lambda : self .bot_label .configure (text = "Bot: Error" , text_color = COLORS ["error" ]))
537569 finally :
538570 loop .close ()
539571
@@ -556,9 +588,10 @@ def fetch():
556588 asyncio .set_event_loop (loop )
557589 providers = loop .run_until_complete (self .client .get_config_providers ())
558590 loop .close ()
559- self .after (0 , lambda p = providers : self ._render_models ( p ) )
591+ self ._safe_after (0 , self ._render_models , providers )
560592 except Exception as exc :
561- self .after (0 , lambda e = str (exc ): self ._append_log (f"Failed to load models: { e } " ))
593+ err_msg = f"Failed to load models: { exc } "
594+ self ._safe_after (0 , self ._append_log , err_msg )
562595
563596 threading .Thread (target = fetch , daemon = True ).start ()
564597
0 commit comments