Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 38 additions & 8 deletions robot_log_visualizer/ui/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@
import pyqtconsole.highlighter as hl



class SetRobotModelDialog(QtWidgets.QDialog):
def __init__(self, meshcat_provider, parent=None, dataset_loaded=False):
# call QMainWindow constructor
Expand Down Expand Up @@ -599,22 +598,53 @@ def update_index(self):
)

def closeEvent(self, event):
# close the window
self.pyconsole.close()
for video_item in self.video_items:
del video_item.media_player
# ensure update callbacks are not triggered while tearing down the UI
if self.signal_provider is not None:
try:
self.signal_provider.update_index_signal.disconnect(self.update_index)
except (TypeError, RuntimeError):
# ignore if already disconnected
pass

# stop timers/animations before widgets disappear
for plot_item in self.plot_items:
plot_item.canvas.quit_animation()

self.meshcat_provider.state = PeriodicThreadState.closed
self.meshcat_provider.wait()
# stop the embedded Python console (it owns a QThread)
self.pyconsole.close()

# gracefully stop worker threads before deleting widgets they use
if self.signal_provider is not None:
self.signal_provider.state = PeriodicThreadState.closed
self.signal_provider.wait()
self.signal_provider = None

event.accept()
# Stop the meshcat_provider if exists
if self.meshcat_provider is not None:
self.meshcat_provider.state = PeriodicThreadState.closed
self.meshcat_provider.wait()

# release multimedia resources explicitly to avoid late callbacks
# while closing
for video_item in self.video_items:
media_player = getattr(video_item, "media_player", None)
if media_player is not None:
if video_item.media_loaded:
media_player.stop()
Comment on lines +632 to +633
Copy link

Copilot AI Oct 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The check for video_item.media_loaded before calling media_player.stop() may not be necessary during cleanup. Consider calling stop() unconditionally as it should be safe to call on a stopped player.

Suggested change
if video_item.media_loaded:
media_player.stop()
media_player.stop()

Copilot uses AI. Check for mistakes.
try:
media_player.setVideoOutput(None)
except Exception:
Copy link

Copilot AI Oct 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Catching Exception is too broad and can mask unexpected errors. Consider catching specific exceptions like RuntimeError or AttributeError that are expected during cleanup operations.

Suggested change
except Exception:
except (RuntimeError, AttributeError):

Copilot uses AI. Check for mistakes.
pass
media_player.deleteLater()
video_item.deleteLater()
self.video_items.clear()

# Disable realtime connection
if self.realtime_connection_enabled:
self.realtime_connection_enabled = False

event.accept()

def __populate_variable_tree_widget(self, obj, parent) -> QTreeWidgetItem:
if not isinstance(obj, dict):
return parent
Expand Down