modificato gestione messaggi in simulazione su status bar

This commit is contained in:
VALLONGOL 2025-11-04 08:36:22 +01:00
parent b03777ae13
commit b3db92e101

View File

@ -619,30 +619,41 @@ class MainView(tk.Tk):
# Id used by show_status_message scheduling # Id used by show_status_message scheduling
self._status_after_id = None self._status_after_id = None
def show_status_message(self, text: str, timeout_ms: int = 3000): def show_status_message(self, text: str, timeout_ms: int | None = 3000):
"""Show a transient status message in the main status bar. """Show a status message in the main status bar.
If another message is scheduled to clear, cancel it and schedule the If timeout_ms is None the message is persistent until explicitly
new message to be cleared after timeout_ms. cleared or replaced. Otherwise the message will be cleared back to
"Ready" after timeout_ms milliseconds.
""" """
try: try:
# Cancel previous scheduled clear if any # Cancel previous scheduled clear if any
try: try:
if self._status_after_id is not None: if self._status_after_id is not None:
self.after_cancel(self._status_after_id) self.after_cancel(self._status_after_id)
self._status_after_id = None
except Exception: except Exception:
pass pass
# Set message # Set message
self.status_var.set(text) self.status_var.set(text)
# Schedule clear back to Ready # Schedule clear back to Ready if timeout provided
def _clear(): if timeout_ms is not None:
try: def _clear():
self.status_var.set("Ready") try:
except Exception: self.status_var.set("Ready")
pass except Exception:
pass
self._status_after_id = self.after(timeout_ms, _clear) try:
self._status_after_id = self.after(timeout_ms, _clear)
except Exception:
# If scheduling fails, log and leave message as-is
try:
self.logger.exception("Failed to schedule status clear")
except Exception:
pass
except Exception: except Exception:
# As a fallback, log the status # As a fallback, log the status
try: try:
@ -650,6 +661,28 @@ class MainView(tk.Tk):
except Exception: except Exception:
pass pass
def clear_status_message(self):
"""Clear status to the default 'Ready' and cancel any pending clears."""
try:
try:
if self._status_after_id is not None:
self.after_cancel(self._status_after_id)
except Exception:
pass
try:
self._status_after_id = None
except Exception:
pass
try:
self.status_var.set("Ready")
except Exception:
pass
except Exception:
try:
self.logger.exception("Failed to clear status message")
except Exception:
pass
def _draw_status_indicator(self, canvas, color): def _draw_status_indicator(self, canvas, color):
canvas.delete("all") canvas.delete("all")
canvas.create_oval(2, 2, 14, 14, fill=color, outline="black") canvas.create_oval(2, 2, 14, 14, fill=color, outline="black")
@ -934,9 +967,14 @@ class MainView(tk.Tk):
except Exception: except Exception:
pass pass
return return
self._start_in_progress_main = True self._start_in_progress_main = True
try: try:
# Show a persistent 'starting' message while the controller/engine prepares
try:
self.show_status_message("Starting simulation...", timeout_ms=None)
except Exception:
pass
# Delegate to SimulationController if available # Delegate to SimulationController if available
try: try:
if hasattr(self, "simulation_controller") and self.simulation_controller: if hasattr(self, "simulation_controller") and self.simulation_controller:
@ -950,6 +988,11 @@ class MainView(tk.Tk):
# If controller is not present or failed, attempt no-op fallback # If controller is not present or failed, attempt no-op fallback
try: try:
messagebox.showerror("Start Error", "Unable to start simulation (controller unavailable).") messagebox.showerror("Start Error", "Unable to start simulation (controller unavailable).")
# If start failed, clear the starting message so the status bar isn't stuck
try:
self.clear_status_message()
except Exception:
pass
except Exception: except Exception:
pass pass
finally: finally:
@ -978,25 +1021,65 @@ class MainView(tk.Tk):
def _on_simulation_finished(self): def _on_simulation_finished(self):
try: try:
if hasattr(self, "simulation_controller") and self.simulation_controller: if hasattr(self, "simulation_controller") and self.simulation_controller:
return self.simulation_controller.on_simulation_finished(self) try:
result = self.simulation_controller.on_simulation_finished(self)
except Exception:
result = None
else:
result = None
except Exception: except Exception:
try: try:
self.logger.exception("SimulationController on_finished failed; falling back to inline finished handler.") self.logger.exception("SimulationController on_finished failed; falling back to inline finished handler.")
except Exception: except Exception:
pass pass
result = None
# Ensure UI reflects finished state regardless of controller handling
try: try:
self.logger.error("Unable to handle simulation finished (controller unavailable).") # Mark simulation as not running
try:
self.is_simulation_running.set(False)
except Exception:
pass
# Show a short transient message informing the user
try:
self.show_status_message("Simulation finished", timeout_ms=5000)
except Exception:
pass
except Exception: except Exception:
pass try:
self.logger.error("Unable to handle simulation finished (controller unavailable).")
except Exception:
pass
return result
def _on_reset_simulation(self): def _on_reset_simulation(self):
self.logger.info("Resetting scenario to initial state.") self.logger.info("Resetting scenario to initial state.")
# Show a brief 'starting' message during the reset phase so users
# see that a reset/action is in progress (matches requested UX).
try:
self.show_status_message("Starting simulation...", timeout_ms=1500)
except Exception:
pass
if self.is_simulation_running.get(): if self.is_simulation_running.get():
self._on_stop_simulation() self._on_stop_simulation()
self.scenario.reset_simulation() self.scenario.reset_simulation()
self._update_all_views() self._update_all_views()
# After reset complete, clear or set Ready so the status bar does not
# remain stuck on 'Starting simulation...'
try:
self.show_status_message("Ready", timeout_ms=1500)
except Exception:
try:
self.clear_status_message()
except Exception:
pass
def _process_gui_queue(self): def _process_gui_queue(self):
""" """
Processes a batch of updates from the GUI queue to keep the UI responsive Processes a batch of updates from the GUI queue to keep the UI responsive
@ -1668,6 +1751,22 @@ class MainView(tk.Tk):
self.simulation_engine is not None and self.simulation_engine.is_running() self.simulation_engine is not None and self.simulation_engine.is_running()
) )
# Transition: started -> set running status
if (not sim_was_running) and sim_is_running_now:
try:
# Mark internal flag and show persistent running message
try:
self.is_simulation_running.set(True)
except Exception:
pass
try:
self.show_status_message("Simulation running", timeout_ms=None)
except Exception:
pass
except Exception:
pass
# Transition: stopped
if sim_was_running and not sim_is_running_now: if sim_was_running and not sim_is_running_now:
self._on_simulation_finished() self._on_simulation_finished()