Using a simple test graph:
Anyone else having this issue?
I have installed only PythonNet3 Engine (no IronPython, or Python version 2.x)…
Data-Shape 2026.4.2
here is a code fix for TreeView input node
# Copyright (c) Data Shapes, 2025
# Data-Shapes www.data-shapes.io, elayoubi.mostafa@data-shapes.io @data_shapes
import clr
import unicodedata
try:
clr.AddReference("System.Windows.Forms")
clr.AddReference("System.Drawing")
clr.AddReference("PresentationCore")
clr.AddReference("WindowsBase")
from System.Windows.Forms import TreeView, TreeNode, MouseButtons
from System.Drawing import Point
from System.Windows.Input import Key, Keyboard
except Exception:
TreeView = None
TreeNode = None
MouseButtons = None
Point = None
Key = None
Keyboard = None
class uitreeview(object):
def __init__(self, inputname="", datalist=None, hastitles=False, height=200):
self.inputname = inputname if inputname is not None else ""
self.datalist = datalist if datalist is not None else []
self._hastitles = bool(hastitles)
self._height = height if isinstance(height, (int, float)) else 0
self._input_type = "uitreeview"
def __repr__(self):
return "UI.TreeView input"
def build_treeview(self, formbody, xlabel, xinput, y, xRatio, yRatio):
if TreeView is None:
return None, y
tv = TreeView()
tv.CheckBoxes = True
# Size and placement
if self.inputname != "":
tv.Width = int(formbody.Width - 25 * xRatio - xinput)
tv.Location = Point(int(xinput), int(y))
else:
tv.Width = int(formbody.Width - 25 * xRatio - xlabel)
tv.Location = Point(int(xlabel), int(y))
tv.Height = int(self._height * yRatio)
# Populate nodes
root = TreeNode("List1")
tv.Nodes.Add(root)
def _build_nodes():
data_list = self._ensure_list(self.datalist)
if self._hastitles:
for dl in data_list:
self._tree_iteration_title(root, dl)
else:
for dl in data_list:
self._tree_iteration(root, dl)
try:
_build_nodes()
except Exception:
# simple fallback: add each item as a leaf
try:
for item in self._ensure_list(self.datalist):
leaf = TreeNode(self._remove_accents(self._stringify(item)))
leaf.Tag = item
root.Nodes.Add(leaf)
except Exception:
pass
root.Expand()
try:
tv.ExpandAll()
except Exception:
pass
# Attach handlers
start_node = {"node": None}
def _tree_node_mouse_down(sender, event):
try:
if (
Keyboard is not None
and Key is not None
and event.Button == MouseButtons.Left
and Keyboard.IsKeyDown(Key.LeftShift)
):
tv_local = sender
end_node = tv_local.GetNodeAt(0, event.Y)
if (
start_node["node"] is not None
and end_node is not None
and start_node["node"].Parent == end_node.Parent
):
start_idx = start_node["node"].Index
end_idx = end_node.Index
if start_idx > end_idx:
start_idx, end_idx = end_idx, start_idx
for i in range(start_idx, end_idx + 1):
current = start_node["node"].Parent.Nodes[i]
current.Checked = not current.Checked
return
start_node["node"] = sender.GetNodeAt(0, event.Y)
except Exception:
start_node["node"] = None
def _check_children(sender, event):
try:
ev_node = event.Node
check_state = ev_node.Checked
for n in ev_node.Nodes:
n.Checked = check_state
except Exception:
pass
if Keyboard is not None and MouseButtons is not None:
tv.MouseDown += _tree_node_mouse_down
tv.AfterCheck += _check_children
def _gather_checked(node, acc):
try:
if node.Nodes is not None and node.Nodes.Count > 0:
for child in node.Nodes:
_gather_checked(child, acc)
else:
if getattr(node, "Checked", False):
acc.append(getattr(node, "Tag", None))
except Exception:
pass
def _get_checked_values():
checked = []
try:
if tv.Nodes.Count > 0:
_gather_checked(tv.Nodes[0], checked)
except Exception:
pass
return checked
# Store getter for the form to consume on close
tv.Tag = _get_checked_values
formbody.Controls.Add(tv) # BUG FIX HERE
next_y = tv.Bottom + int(25 * yRatio)
return tv, next_y
def _tree_iteration_title(self, control, input_val):
if isinstance(input_val, list):
data_copy = list(input_val)
try:
title = data_copy.pop(0)
except Exception:
title = None
node_text = self._stringify(title) if title is not None else "{0}.{1}".format(
control.Text, len(control.Nodes) + 1
)
node_text = self._remove_accents(node_text)
current_node = TreeNode(node_text)
current_node.Tag = ""
control.Nodes.Add(current_node)
for item in data_copy:
self._tree_iteration_title(current_node, item)
else:
item_node = TreeNode(self._remove_accents(self._stringify(input_val)))
item_node.Tag = input_val
control.Nodes.Add(item_node)
def _tree_iteration(self, control, input_val):
if isinstance(input_val, list):
current_node = TreeNode("{0}.{1}".format(control.Text, len(control.Nodes) + 1))
current_node.Tag = input_val
control.Nodes.Add(current_node)
for item in input_val:
self._tree_iteration(current_node, item)
else:
item_node = TreeNode(self._remove_accents(self._stringify(input_val)))
item_node.Tag = input_val
control.Nodes.Add(item_node)
def _stringify(self, obj):
try:
return str(obj)
except Exception:
try:
return obj.encode("utf-8").decode("utf-8")
except Exception:
return ""
def _remove_accents(self, input_str):
nfkd_form = unicodedata.normalize("NFKD", str(input_str))
only_ascii = nfkd_form.encode("ASCII", "ignore")
return only_ascii.decode("ASCII")
def _ensure_list(self, obj):
if obj is None:
return []
if isinstance(obj, list):
return obj
try:
return list(obj)
except Exception:
return [obj]
inputname = IN[0] if len(IN) > 0 else ""
datalist = IN[1] if len(IN) > 1 else []
hastitles = IN[2] if len(IN) > 2 else False
height = IN[3] if len(IN) > 3 else 150
OUT = uitreeview(inputname, datalist, hastitles, height)
Thank you, this worked!