55from loguru import logger
66from PySide6 .QtWidgets import QApplication , QLabel , QWidget , QScroller , QSizePolicy
77from PySide6 .QtGui import QIcon
8- from PySide6 .QtCore import QTimer , QEvent , Signal , QSize , Qt
8+ from PySide6 .QtCore import QTimer , QEvent , Signal , QSize , Qt , QThread , QObject
99from PySide6 .QtWidgets import QVBoxLayout
1010from qfluentwidgets import (
1111 FluentWindow ,
@@ -1153,6 +1153,7 @@ def _unload_settings_page(self, page_name: str):
11531153
11541154 try :
11551155 real_page = self ._created_pages .pop (page_name )
1156+ self ._cleanup_page_threads (real_page )
11561157 container = getattr (self , page_name , None )
11571158 if container and container .layout ():
11581159 container .layout ().removeWidget (real_page )
@@ -1167,6 +1168,96 @@ def _unload_settings_page(self, page_name: str):
11671168 except Exception as e :
11681169 logger .exception (f"卸载设置页面 { page_name } 失败: { e } " )
11691170
1171+ def _cleanup_page_threads (self , widget : QWidget ) -> None :
1172+ visited : set [int ] = set ()
1173+ self ._cleanup_threads_in_object (widget , visited )
1174+
1175+ def _cleanup_threads_in_object (self , obj , visited : set [int ]) -> None :
1176+ if obj is None :
1177+ return
1178+
1179+ obj_id = id (obj )
1180+ if obj_id in visited :
1181+ return
1182+ visited .add (obj_id )
1183+
1184+ if isinstance (obj , QThread ):
1185+ self ._stop_qthread (obj )
1186+ return
1187+
1188+ try :
1189+ obj_dict = vars (obj )
1190+ except Exception :
1191+ obj_dict = {}
1192+
1193+ for value in obj_dict .values ():
1194+ self ._cleanup_threads_in_value (value , visited )
1195+
1196+ if isinstance (obj , QObject ):
1197+ try :
1198+ for child in obj .children ():
1199+ self ._cleanup_threads_in_object (child , visited )
1200+ except Exception :
1201+ pass
1202+
1203+ def _cleanup_threads_in_value (self , value , visited : set [int ]) -> None :
1204+ if value is None :
1205+ return
1206+
1207+ if isinstance (value , (str , bytes , int , float , bool )):
1208+ return
1209+
1210+ if isinstance (value , QThread ):
1211+ self ._stop_qthread (value )
1212+ return
1213+
1214+ if isinstance (value , dict ):
1215+ for item in value .values ():
1216+ self ._cleanup_threads_in_value (item , visited )
1217+ return
1218+
1219+ if isinstance (value , (list , tuple , set )):
1220+ for item in value :
1221+ self ._cleanup_threads_in_value (item , visited )
1222+ return
1223+
1224+ self ._cleanup_threads_in_object (value , visited )
1225+
1226+ def _stop_qthread (self , thread : QThread ) -> None :
1227+ try :
1228+ if not thread .isRunning ():
1229+ return
1230+ except RuntimeError :
1231+ return
1232+
1233+ try :
1234+ thread .requestInterruption ()
1235+ except Exception :
1236+ pass
1237+
1238+ try :
1239+ thread .quit ()
1240+ except Exception :
1241+ pass
1242+
1243+ try :
1244+ finished = thread .wait (500 )
1245+ except Exception :
1246+ finished = False
1247+
1248+ if finished :
1249+ return
1250+
1251+ try :
1252+ thread .terminate ()
1253+ except Exception :
1254+ return
1255+
1256+ try :
1257+ thread .wait (500 )
1258+ except Exception :
1259+ pass
1260+
11701261 def _restore_page_factory (self , page_name : str , container ):
11711262 """恢复页面工厂函数
11721263
0 commit comments