Skip to content

Commit 7f3a88f

Browse files
šŸ› Improve cleanup process in closeEvent to ensure proper resource release and thread management (#106)
Fix regression introduced in #104
1 parent fa0fcd1 commit 7f3a88f

File tree

1 file changed

+38
-8
lines changed

1 file changed

+38
-8
lines changed

ā€Žrobot_log_visualizer/ui/gui.pyā€Ž

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@
5858
import pyqtconsole.highlighter as hl
5959

6060

61-
6261
class SetRobotModelDialog(QtWidgets.QDialog):
6362
def __init__(self, meshcat_provider, parent=None, dataset_loaded=False):
6463
# call QMainWindow constructor
@@ -599,22 +598,53 @@ def update_index(self):
599598
)
600599

601600
def closeEvent(self, event):
602-
# close the window
603-
self.pyconsole.close()
604-
for video_item in self.video_items:
605-
del video_item.media_player
601+
# ensure update callbacks are not triggered while tearing down the UI
602+
if self.signal_provider is not None:
603+
try:
604+
self.signal_provider.update_index_signal.disconnect(self.update_index)
605+
except (TypeError, RuntimeError):
606+
# ignore if already disconnected
607+
pass
608+
609+
# stop timers/animations before widgets disappear
610+
for plot_item in self.plot_items:
611+
plot_item.canvas.quit_animation()
606612

607-
self.meshcat_provider.state = PeriodicThreadState.closed
608-
self.meshcat_provider.wait()
613+
# stop the embedded Python console (it owns a QThread)
614+
self.pyconsole.close()
609615

616+
# gracefully stop worker threads before deleting widgets they use
610617
if self.signal_provider is not None:
611618
self.signal_provider.state = PeriodicThreadState.closed
612619
self.signal_provider.wait()
620+
self.signal_provider = None
613621

614-
event.accept()
622+
# Stop the meshcat_provider if exists
623+
if self.meshcat_provider is not None:
624+
self.meshcat_provider.state = PeriodicThreadState.closed
625+
self.meshcat_provider.wait()
626+
627+
# release multimedia resources explicitly to avoid late callbacks
628+
# while closing
629+
for video_item in self.video_items:
630+
media_player = getattr(video_item, "media_player", None)
631+
if media_player is not None:
632+
if video_item.media_loaded:
633+
media_player.stop()
634+
try:
635+
media_player.setVideoOutput(None)
636+
except Exception:
637+
pass
638+
media_player.deleteLater()
639+
video_item.deleteLater()
640+
self.video_items.clear()
641+
642+
# Disable realtime connection
615643
if self.realtime_connection_enabled:
616644
self.realtime_connection_enabled = False
617645

646+
event.accept()
647+
618648
def __populate_variable_tree_widget(self, obj, parent) -> QTreeWidgetItem:
619649
if not isinstance(obj, dict):
620650
return parent

0 commit comments

Comments
Ā (0)