modificato gestione messaggi in simulazione su status bar
This commit is contained in:
parent
b03777ae13
commit
b3db92e101
@ -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()
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user