sistemata la visualizzazione dei campi details con form
This commit is contained in:
parent
fc52579330
commit
01936497a0
@ -47,7 +47,7 @@ class DetailsPane:
|
||||
self._details_canvas_frame.bind('<Configure>', _on_frame_configure)
|
||||
self._details_canvas.bind('<Configure>', _on_canvas_configure)
|
||||
|
||||
# details Treeview
|
||||
# details Treeview (kept for backwards compatibility but not packed)
|
||||
self.detail_tree = ttk.Treeview(self._details_canvas_frame, columns=("param", "value"), show="headings", height=18)
|
||||
self.detail_tree.heading("param", text="Parameter")
|
||||
self.detail_tree.heading("value", text="Value")
|
||||
@ -57,10 +57,16 @@ class DetailsPane:
|
||||
self.detail_tree.configure() # placeholder to satisfy possible callers
|
||||
except Exception:
|
||||
pass
|
||||
self.detail_tree.pack(side=tk.TOP, fill=tk.BOTH, expand=False, padx=2, pady=2)
|
||||
|
||||
# form container in the interior frame so it scrolls with canvas
|
||||
self.detail_form_container = tk.Frame(self._details_canvas_frame)
|
||||
# ensure the form container is visible by default (the form builder will
|
||||
# populate it). We do not pack the Treeview to avoid an empty tree
|
||||
# overlaying the form; the form is the primary details UI.
|
||||
try:
|
||||
self.detail_form_container.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=2, pady=2)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# assign attributes onto the app so existing MonitorApp code works
|
||||
setattr(app, 'detail_tree', self.detail_tree)
|
||||
|
||||
@ -65,6 +65,8 @@ class MonitorApp(tk.Frame):
|
||||
self.update_loop_running = False
|
||||
# cache tree item ids by message label for incremental updates
|
||||
self._tree_items = {}
|
||||
# parents we want to keep always expanded in detail tree
|
||||
self._always_open_parents = {}
|
||||
# No background bind or retry at startup; user must press Initialize.
|
||||
|
||||
def create_widgets(self):
|
||||
@ -306,18 +308,16 @@ class MonitorApp(tk.Frame):
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def show_message_form(self, label: str):
|
||||
def show_message_form(self, label: str, editable: bool = True):
|
||||
"""Build an editable form for message `label` (A messages).
|
||||
|
||||
The form is placed into `self.detail_form_container`. Existing form
|
||||
widgets are destroyed and rebuilt for the new message.
|
||||
"""
|
||||
try:
|
||||
# ensure tree is hidden
|
||||
try:
|
||||
self.detail_tree.pack_forget()
|
||||
except Exception:
|
||||
pass
|
||||
# Use the form container for showing message details; do not toggle the
|
||||
# tree visibility here. The DetailsPane places the form inside a
|
||||
# scrollable canvas so it remains visible while updating.
|
||||
# if same form is already shown, just refresh widget values
|
||||
if getattr(self, 'current_form_label', None) == label and self.form_widgets:
|
||||
try:
|
||||
@ -353,13 +353,17 @@ class MonitorApp(tk.Frame):
|
||||
hdr.pack(fill=tk.X, padx=6, pady=(6,0))
|
||||
lbl_hdr = tk.Label(hdr, text=f"Edit message {label}", anchor=tk.W)
|
||||
lbl_hdr.pack(side=tk.LEFT)
|
||||
apply_btn = tk.Button(hdr, text='Apply', command=lambda: self._apply_form_values(msg_wrapper))
|
||||
apply_btn.pack(side=tk.RIGHT, padx=6)
|
||||
# For editable forms show Apply button, otherwise present a label
|
||||
if editable:
|
||||
apply_btn = tk.Button(hdr, text='Apply', command=lambda: self._apply_form_values(msg_wrapper))
|
||||
apply_btn.pack(side=tk.RIGHT, padx=6)
|
||||
else:
|
||||
tk.Label(hdr, text='Read-only', anchor=tk.E).pack(side=tk.RIGHT, padx=6)
|
||||
|
||||
# recursive builder for fields
|
||||
frm = tk.Frame(self.detail_form_container)
|
||||
frm.pack(fill=tk.BOTH, expand=True, padx=6, pady=6)
|
||||
self._build_form_fields(frm, msg, prefix='')
|
||||
self._build_form_fields(frm, msg, prefix='', editable=editable)
|
||||
|
||||
# show form container
|
||||
try:
|
||||
@ -372,7 +376,7 @@ class MonitorApp(tk.Frame):
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _build_form_fields(self, parent, obj, prefix='', max_depth=3, _depth=0):
|
||||
def _build_form_fields(self, parent, obj, prefix='', max_depth=3, _depth=0, editable=True):
|
||||
"""Recursively create labeled widgets for public fields of obj."""
|
||||
if _depth > max_depth:
|
||||
return
|
||||
@ -436,7 +440,9 @@ class MonitorApp(tk.Frame):
|
||||
# show human-friendly label first, then numeric value
|
||||
choices = [f"{n} ({v})" for (n, v) in enum_items]
|
||||
var = tk.StringVar()
|
||||
cb = ttk.Combobox(row_fr, values=choices, textvariable=var, state='readonly')
|
||||
# combobox is selectable for editable forms, otherwise disabled
|
||||
cb_state = 'readonly' if editable else 'disabled'
|
||||
cb = ttk.Combobox(row_fr, values=choices, textvariable=var, state=cb_state)
|
||||
# set current value
|
||||
try:
|
||||
raw = int(getattr(val, 'raw', getattr(val, 'value', val)))
|
||||
@ -464,6 +470,12 @@ class MonitorApp(tk.Frame):
|
||||
except Exception:
|
||||
var.set('')
|
||||
ent = tk.Entry(row_fr, textvariable=var)
|
||||
# disable entry if not editable
|
||||
if not editable:
|
||||
try:
|
||||
ent.config(state='disabled')
|
||||
except Exception:
|
||||
pass
|
||||
ent.pack(side=tk.RIGHT, fill=tk.X, expand=True)
|
||||
widget = ('entry', ent)
|
||||
|
||||
@ -532,6 +544,12 @@ class MonitorApp(tk.Frame):
|
||||
# create parent node with empty value
|
||||
try:
|
||||
iid = self.detail_tree.insert(parent, tk.END, values=(p, ''))
|
||||
# ensure parent is expanded so nested fields remain visible
|
||||
try:
|
||||
self.detail_tree.item(iid, open=True)
|
||||
self._always_open_parents[key] = True
|
||||
except Exception:
|
||||
pass
|
||||
self.detail_rows[key] = iid
|
||||
parent = iid
|
||||
except Exception:
|
||||
@ -552,7 +570,20 @@ class MonitorApp(tk.Frame):
|
||||
try:
|
||||
# keep the param column stable; show only the leaf label
|
||||
leaf = name.split('.')[-1]
|
||||
self.detail_tree.item(iid, values=(leaf, value))
|
||||
parent_key = '.'.join(name.replace('/', '.').split('.')[:-1])
|
||||
if parent_key and parent_key in self.detail_rows:
|
||||
disp = f"-> {leaf}"
|
||||
else:
|
||||
disp = leaf
|
||||
self.detail_tree.item(iid, values=(disp, value))
|
||||
# if this row represents a parent that we marked to remain open,
|
||||
# ensure it's still expanded after value updates
|
||||
try:
|
||||
parent_key = name
|
||||
if parent_key in self._always_open_parents:
|
||||
self.detail_tree.item(iid, open=True)
|
||||
except Exception:
|
||||
pass
|
||||
if accessor is not None:
|
||||
self.detail_accessors[name] = accessor
|
||||
return iid
|
||||
@ -562,14 +593,24 @@ class MonitorApp(tk.Frame):
|
||||
# insert hierarchical node
|
||||
parent_iid, leaf_label = _ensure_hierarchy(name)
|
||||
try:
|
||||
iid = self.detail_tree.insert(parent_iid, tk.END, values=(leaf_label, value))
|
||||
leaf_parent_key = '.'.join(name.replace('/', '.').split('.')[:-1])
|
||||
if leaf_parent_key:
|
||||
disp_label = f"-> {leaf_label}"
|
||||
else:
|
||||
disp_label = leaf_label
|
||||
iid = self.detail_tree.insert(parent_iid, tk.END, values=(disp_label, value))
|
||||
self.detail_rows[name] = iid
|
||||
if accessor is not None:
|
||||
self.detail_accessors[name] = accessor
|
||||
return iid
|
||||
except Exception:
|
||||
try:
|
||||
iid = self.detail_tree.insert('', tk.END, values=(leaf_label, value))
|
||||
leaf_parent_key = '.'.join(name.replace('/', '.').split('.')[:-1])
|
||||
if leaf_parent_key:
|
||||
disp_label = f"-> {leaf_label}"
|
||||
else:
|
||||
disp_label = leaf_label
|
||||
iid = self.detail_tree.insert('', tk.END, values=(disp_label, value))
|
||||
self.detail_rows[name] = iid
|
||||
if accessor is not None:
|
||||
self.detail_accessors[name] = accessor
|
||||
@ -582,7 +623,12 @@ class MonitorApp(tk.Frame):
|
||||
# best-effort hierarchical insert
|
||||
parent_iid, leaf_label = (lambda n: ('' , n))(name)
|
||||
try:
|
||||
iid = self.detail_tree.insert(parent_iid, tk.END, values=(leaf_label, str(value)))
|
||||
leaf_parent_key = '.'.join(name.replace('/', '.').split('.')[:-1])
|
||||
if leaf_parent_key:
|
||||
disp_label = f"-> {leaf_label}"
|
||||
else:
|
||||
disp_label = leaf_label
|
||||
iid = self.detail_tree.insert(parent_iid, tk.END, values=(disp_label, str(value)))
|
||||
if accessor is not None:
|
||||
self.detail_accessors[name] = accessor
|
||||
return iid
|
||||
@ -591,7 +637,7 @@ class MonitorApp(tk.Frame):
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def _add_detail_rows_from_obj(self, prefix: str, obj, max_depth: int = 3, _depth: int = 0):
|
||||
def _add_detail_rows_from_obj(self, prefix: str, obj, max_depth: int = 4, _depth: int = 0):
|
||||
"""Recursively add detail rows for public fields of `obj`.
|
||||
|
||||
- `prefix` is a string prepended to field names (e.g. 'param1').
|
||||
@ -621,24 +667,42 @@ class MonitorApp(tk.Frame):
|
||||
return
|
||||
|
||||
# Enum-like or ctypes scalar handling
|
||||
def _is_struct_like_local(v):
|
||||
# heuristics similar to form builder: ctypes.Structure or many public attrs
|
||||
if v is None:
|
||||
return False
|
||||
if isinstance(v, (int, float, str, bytes)):
|
||||
return False
|
||||
if hasattr(v, '_fields_'):
|
||||
return True
|
||||
public = [n for n in dir(v) if not n.startswith('_')]
|
||||
if len(public) > 2:
|
||||
return True
|
||||
return False
|
||||
|
||||
if hasattr(obj, 'raw') or hasattr(obj, 'value'):
|
||||
try:
|
||||
s = None
|
||||
# If the object also looks like a struct (has nested fields), recurse
|
||||
if _is_struct_like_local(obj):
|
||||
# fall through to attribute iteration to expand nested fields
|
||||
pass
|
||||
else:
|
||||
try:
|
||||
raw = int(getattr(obj, 'raw')) if hasattr(obj, 'raw') else int(getattr(obj, 'value'))
|
||||
s = self._fmt_enum(raw, [obj.__class__.__name__])
|
||||
s = None
|
||||
try:
|
||||
raw = int(getattr(obj, 'raw')) if hasattr(obj, 'raw') else int(getattr(obj, 'value'))
|
||||
s = self._fmt_enum(raw, [obj.__class__.__name__])
|
||||
except Exception:
|
||||
try:
|
||||
s = str(getattr(obj, 'raw', getattr(obj, 'value', obj)))
|
||||
except Exception:
|
||||
s = repr(obj)
|
||||
self._add_detail_row(prefix or obj.__class__.__name__, s)
|
||||
except Exception:
|
||||
try:
|
||||
s = str(getattr(obj, 'raw', getattr(obj, 'value', obj)))
|
||||
self._add_detail_row(prefix or '<value>', repr(obj))
|
||||
except Exception:
|
||||
s = repr(obj)
|
||||
self._add_detail_row(prefix or obj.__class__.__name__, s)
|
||||
except Exception:
|
||||
try:
|
||||
self._add_detail_row(prefix or '<value>', repr(obj))
|
||||
except Exception:
|
||||
pass
|
||||
return
|
||||
pass
|
||||
return
|
||||
|
||||
# dict-like
|
||||
try:
|
||||
@ -661,22 +725,63 @@ class MonitorApp(tk.Frame):
|
||||
pass
|
||||
|
||||
# otherwise iterate public attributes
|
||||
import inspect
|
||||
names = [n for n in dir(obj) if not n.startswith('_')]
|
||||
for n in names:
|
||||
try:
|
||||
v = getattr(obj, n)
|
||||
except Exception:
|
||||
continue
|
||||
if callable(v):
|
||||
continue
|
||||
field_name = f"{prefix}.{n}" if prefix else n
|
||||
|
||||
# If attribute is a ctypes Union with a '.str' bitfield, expand it
|
||||
try:
|
||||
if hasattr(v, 'str') and (hasattr(getattr(v, 'str'), '__dict__') or hasattr(getattr(v, 'str'), '_fields_')):
|
||||
try:
|
||||
self._add_detail_rows_from_obj(field_name, getattr(v, 'str'), max_depth=max_depth, _depth=_depth+1)
|
||||
continue
|
||||
except Exception:
|
||||
pass
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# If callable, try to call zero-arg getters (get_*/is_*) to obtain a value
|
||||
if callable(v):
|
||||
called = False
|
||||
try:
|
||||
sig = inspect.signature(v)
|
||||
if len(sig.parameters) == 0:
|
||||
try:
|
||||
val = v()
|
||||
self._add_detail_row(field_name, self._format_value_for_table(val))
|
||||
called = True
|
||||
except Exception:
|
||||
called = False
|
||||
except Exception:
|
||||
# fallback: attempt to call and ignore errors
|
||||
try:
|
||||
val = v()
|
||||
self._add_detail_row(field_name, self._format_value_for_table(val))
|
||||
called = True
|
||||
except Exception:
|
||||
called = False
|
||||
if called:
|
||||
continue
|
||||
# otherwise skip arbitrary callables
|
||||
continue
|
||||
|
||||
# Primitive or scalar-like values
|
||||
if isinstance(v, (int, float, str)) or hasattr(v, 'raw') or hasattr(v, 'value'):
|
||||
try:
|
||||
self._add_detail_row(field_name, self._format_value_for_table(v))
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
self._add_detail_rows_from_obj(field_name, v, max_depth=max_depth, _depth=_depth+1)
|
||||
# Recurse into nested objects
|
||||
try:
|
||||
self._add_detail_rows_from_obj(field_name, v, max_depth=max_depth, _depth=_depth+1)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def on_init(self):
|
||||
# On-demand import/creation of the connection manager when the user requests initialization.
|
||||
@ -986,15 +1091,24 @@ class MonitorApp(tk.Frame):
|
||||
|
||||
def show_message_detail(self, label: str):
|
||||
# build table for this label; detail_tree will be populated and updated
|
||||
try:
|
||||
self.detail_tree.delete(*self.detail_tree.get_children())
|
||||
except Exception:
|
||||
pass
|
||||
# Do not clear the form here — only clear when we know we'll show
|
||||
# an error message or rebuild the details. Clearing before the
|
||||
# MessageDB lookup causes the UI to briefly show then disappear
|
||||
# if the lookup fails during a refresh.
|
||||
self.detail_rows = {}
|
||||
self.detail_selected_label = label
|
||||
try:
|
||||
mdb = self._get_message_db()
|
||||
if mdb is None:
|
||||
# clear any previous form/tree content before showing diagnostic
|
||||
try:
|
||||
for w in getattr(self, 'detail_form_container', []).winfo_children():
|
||||
try:
|
||||
w.destroy()
|
||||
except Exception:
|
||||
pass
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
self.detail_tree.insert('', tk.END, values=("Message DB not available", "Open Diagnostics for details."))
|
||||
except Exception:
|
||||
@ -1004,7 +1118,6 @@ class MonitorApp(tk.Frame):
|
||||
except Exception:
|
||||
pass
|
||||
return
|
||||
return
|
||||
# Try direct lookup first
|
||||
try:
|
||||
msg_wrapper = mdb.getMessage(label)
|
||||
@ -1035,6 +1148,15 @@ class MonitorApp(tk.Frame):
|
||||
return
|
||||
|
||||
if not msg_wrapper:
|
||||
# clear any existing form before showing 'No data'
|
||||
try:
|
||||
for w in getattr(self, 'detail_form_container', []).winfo_children():
|
||||
try:
|
||||
w.destroy()
|
||||
except Exception:
|
||||
pass
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
self.detail_tree.insert('', tk.END, values=("No data", f"{label}"))
|
||||
except Exception:
|
||||
@ -1074,6 +1196,15 @@ class MonitorApp(tk.Frame):
|
||||
except Exception:
|
||||
self.current_msg_wrapper = None
|
||||
if msg is None:
|
||||
# Clear any existing form before showing 'No message'
|
||||
try:
|
||||
for w in getattr(self, 'detail_form_container', []).winfo_children():
|
||||
try:
|
||||
w.destroy()
|
||||
except Exception:
|
||||
pass
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
self.detail_tree.insert('', tk.END, values=("No message", "<empty>"))
|
||||
except Exception:
|
||||
@ -1084,156 +1215,17 @@ class MonitorApp(tk.Frame):
|
||||
pass
|
||||
return
|
||||
|
||||
# Handle known tellbacks
|
||||
# Use the same form renderer for B messages (read-only) to avoid toggling
|
||||
# between tree and form and to keep the UI stable. This will build a
|
||||
# non-editable form for the message so values can be observed live.
|
||||
try:
|
||||
if hasattr(msg, 'rdr_mode_tellback') or hasattr(msg, 'settings_tellback'):
|
||||
# B7 - status tellback
|
||||
if hasattr(msg, 'rdr_mode_tellback'):
|
||||
rb = msg.rdr_mode_tellback
|
||||
# master mode and flags
|
||||
try:
|
||||
mm = rb.get_master_mode()
|
||||
except Exception:
|
||||
mm = getattr(rb, 'raw', rb)
|
||||
try:
|
||||
mm_str = self._fmt_enum(mm, ['RdrModes', 'RdrModes'])
|
||||
except Exception:
|
||||
mm_str = str(mm)
|
||||
# store accessor to refresh live value
|
||||
try:
|
||||
self._add_detail_row('master_mode', mm_str, accessor=(lambda rb=rb: self._fmt_enum(rb.get_master_mode(), ['RdrModes'])))
|
||||
except Exception:
|
||||
self._add_detail_row('master_mode', mm_str)
|
||||
try:
|
||||
des = rb.get_des_ctrl()
|
||||
des_str = self._fmt_enum(des, ['DesControl', 'DesignationStatus'])
|
||||
try:
|
||||
self._add_detail_row('designation_ctrl', des_str, accessor=(lambda rb=rb: self._fmt_enum(rb.get_des_ctrl(), ['DesControl', 'DesignationStatus'])))
|
||||
except Exception:
|
||||
self._add_detail_row('designation_ctrl', des_str)
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
ib = rb.get_ibit()
|
||||
ib_str = self._fmt_enum(ib, ['IbitRequest', 'BITReportAvailable'])
|
||||
try:
|
||||
self._add_detail_row('ibit', ib_str, accessor=(lambda rb=rb: self._fmt_enum(rb.get_ibit(), ['IbitRequest', 'BITReportAvailable'])))
|
||||
except Exception:
|
||||
self._add_detail_row('ibit', ib_str)
|
||||
except Exception:
|
||||
pass
|
||||
# also expand nested fields for richer detail
|
||||
try:
|
||||
self._add_detail_rows_from_obj('rdr_mode_tellback', rb, max_depth=3)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# B6 - settings tellback
|
||||
if hasattr(msg, 'settings_tellback'):
|
||||
st = msg.settings_tellback
|
||||
try:
|
||||
hist = st.get_history_level()
|
||||
except Exception:
|
||||
hist = getattr(st, 'raw', '')
|
||||
try:
|
||||
sym = st.get_sym_intensity()
|
||||
except Exception:
|
||||
sym = ''
|
||||
try:
|
||||
self._add_detail_row('history_level', self._fmt_enum(hist, ['TargetHistory']), accessor=(lambda st=st: self._fmt_enum(st.get_history_level(), ['TargetHistory'])))
|
||||
except Exception:
|
||||
self._add_detail_row('history_level', self._fmt_enum(hist, ['TargetHistory']))
|
||||
try:
|
||||
self._add_detail_row('symbology_intensity', str(sym), accessor=(lambda st=st: str(st.get_sym_intensity())))
|
||||
except Exception:
|
||||
self._add_detail_row('symbology_intensity', str(sym))
|
||||
try:
|
||||
self._add_detail_rows_from_obj('settings_tellback', st, max_depth=3)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# param1/param2 fields (if present)
|
||||
try:
|
||||
if hasattr(msg, 'param1_tellback'):
|
||||
p1 = msg.param1_tellback
|
||||
for fn, enum_names in (
|
||||
('get_rws_submode', ['RwsSubmode']),
|
||||
('get_spot', ['SpotSelection','SpotSelection']),
|
||||
('get_acm_submode', ['AcmSubmode']),
|
||||
('get_gm_submode', ['GmSubmode','GmSubmode']),
|
||||
('get_expand', ['Expand']),
|
||||
('get_range_scale', ['RangeScale']),
|
||||
('get_bars_num', ['BarsNum']),
|
||||
('get_scan_width', ['ScanWidth','AzimuthScanWidth']),
|
||||
):
|
||||
if hasattr(p1, fn):
|
||||
try:
|
||||
v = getattr(p1, fn)()
|
||||
v_str = self._fmt_enum(v, enum_names)
|
||||
try:
|
||||
self._add_detail_row(fn, v_str, accessor=(lambda p1=p1, fn=fn, enum_names=enum_names: self._fmt_enum(getattr(p1, fn)(), enum_names)))
|
||||
except Exception:
|
||||
self._add_detail_row(fn, v_str)
|
||||
except Exception:
|
||||
pass
|
||||
# after common getters, also walk the p1 struct for other fields
|
||||
try:
|
||||
self._add_detail_rows_from_obj('param1_tellback', p1, max_depth=3)
|
||||
except Exception:
|
||||
pass
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
try:
|
||||
if hasattr(msg, 'param2_tellback'):
|
||||
p2 = msg.param2_tellback
|
||||
self._add_detail_row('param2_raw', str(getattr(p2,'raw', '')))
|
||||
try:
|
||||
self._add_detail_rows_from_obj('param2_tellback', p2, max_depth=3)
|
||||
except Exception:
|
||||
pass
|
||||
except Exception:
|
||||
pass
|
||||
return
|
||||
|
||||
# Default: dump raw fields of ctypes message
|
||||
self.detail_tree.insert('', tk.END, values=(f"# {label}", ""))
|
||||
# default: show top-level public attributes as rows
|
||||
self.show_message_form(label, editable=False)
|
||||
except Exception:
|
||||
try:
|
||||
for name in dir(msg):
|
||||
if name.startswith('_'):
|
||||
continue
|
||||
try:
|
||||
val = getattr(msg, name)
|
||||
except Exception:
|
||||
continue
|
||||
if callable(val):
|
||||
continue
|
||||
# add row and remember item id
|
||||
vstr = self._format_value_for_table(val)
|
||||
try:
|
||||
self._add_detail_row(name, vstr, accessor=(lambda v=val: v))
|
||||
except Exception:
|
||||
try:
|
||||
iid = self.detail_tree.insert('', tk.END, values=(name, vstr))
|
||||
self.detail_rows[name] = iid
|
||||
except Exception:
|
||||
pass
|
||||
except Exception as e:
|
||||
# fallback: ensure at least one row
|
||||
try:
|
||||
self.detail_tree.insert('', tk.END, values=("<error>", str(e)))
|
||||
except Exception:
|
||||
pass
|
||||
except Exception as e:
|
||||
try:
|
||||
self.detail_tree.insert('', tk.END, values=("<error>", str(e)))
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
self.log.insert(tk.END, f"Error while decoding: {e}\n")
|
||||
self.log.insert(tk.END, f"Failed to render form for {label}\n")
|
||||
except Exception:
|
||||
pass
|
||||
return
|
||||
|
||||
def periodic_update(self):
|
||||
while self.manager.is_running():
|
||||
@ -1369,8 +1361,17 @@ class MonitorApp(tk.Frame):
|
||||
pass
|
||||
if new_str != cur_val:
|
||||
try:
|
||||
# update display value
|
||||
self.detail_tree.item(iid, values=(name, new_str))
|
||||
# update display value keeping only the leaf name in the param column
|
||||
try:
|
||||
leaf_label = name.split('.')[-1]
|
||||
except Exception:
|
||||
leaf_label = name
|
||||
parent_key = '.'.join(name.replace('/', '.').split('.')[:-1])
|
||||
if parent_key and parent_key in self.detail_rows:
|
||||
disp = f"-> {leaf_label}"
|
||||
else:
|
||||
disp = leaf_label
|
||||
self.detail_tree.item(iid, values=(disp, new_str))
|
||||
# flash the changed row
|
||||
self._flash_item(iid)
|
||||
if DEBUG_DETAIL_UPDATES:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user