fix: defensive attribute access in _sync_config_from_ui

_sync_config_from_ui() now uses hasattr() for _port_var, _erase_cb_var,
_xilinx_path_var, and _ip_string_var so it doesn't crash when called
during _build_config_panel() before those widgets are created.

This fixes the AttributeError: '_tkinter.tkapp' object has no attribute
'_port_var' that occurred on startup.
This commit is contained in:
2026-06-12 10:24:36 +08:00
parent e2e1fdd2a0
commit 941d7453bb
+12 -5
View File
@@ -218,16 +218,21 @@ class MainWindow(ctk.CTk):
object's perspective); the FileSelector stores both the object's perspective); the FileSelector stores both the
absolute path (for internal use) and the relative path absolute path (for internal use) and the relative path
(for saving to YAML). (for saving to YAML).
All attribute accesses are defensive — widgets may not exist
yet during construction (e.g. _port_var created in _build_serial).
""" """
if not self._config: if not self._config:
return return
# Sync IP address # Sync IP address (may not exist yet during _build_config_panel)
if self._ip_string_var: if self._ip_string_var:
self._config.zynq_ip = self._ip_string_var.get() self._config.zynq_ip = self._ip_string_var.get()
# Sync Xilinx Kit path # Sync Xilinx Kit path
self._config.xilinx_path = self._xilinx_path_var.get() if hasattr(self, '_xilinx_path_var'):
# Sync serial port self._config.xilinx_path = self._xilinx_path_var.get()
self._config.serial_port = self._port_var.get() # Sync serial port (may not exist yet during _build_config_panel)
if hasattr(self, '_port_var'):
self._config.serial_port = self._port_var.get()
# Sync file paths from FileSelectors # Sync file paths from FileSelectors
files = self._get_selected_files() files = self._get_selected_files()
for attr, selector in [ for attr, selector in [
@@ -245,7 +250,9 @@ class MainWindow(ctk.CTk):
if abs_path: if abs_path:
self._config._config_path # ensure _config_path is set self._config._config_path # ensure _config_path is set
setattr(self._config, attr, self._config._relative_path(abs_path)) setattr(self._config, attr, self._config._relative_path(abs_path))
self._config.erase_all = self._erase_cb_var.get() # Sync erase checkbox (may not exist yet)
if hasattr(self, '_erase_cb_var'):
self._config.erase_all = self._erase_cb_var.get()
def _auto_save_config(self) -> None: def _auto_save_config(self) -> None:
"""Auto-save config to disk after UI changes. """Auto-save config to disk after UI changes.