I decided to write it and it wasn’t that difficult. In case it helps anyone in the future here’s the code. All you need is a window with a Tree View component. There’s an internalFrameActivated event on the window to populate the root with all your devices:
[code]# Get the current dataset from the tree view object
tvItems = system.gui.getParentWindow(event).getComponentForPath(‘Root Container.Tree View’).data
Convert it to a PyDataSet so we can iterate through it
pyDS = system.dataset.toPyDataSet(tvItems)
Delete the existing rows
for node in pyDS:
tvItems = system.dataset.deleteRow(tvItems, 0)
Get top-level opc tag data by device (the propertyChange event of the Tree View will have the logic needed to drill deeper)
opcServer = “Ignition OPC-UA Server”
nodeId = “Devices”
devices = system.opc.browseServer(opcServer, nodeId)
for device in devices:
device_name = device.getDisplayName()
device_type = device.getElementType()
device_nodeId = device.getServerNodeId()
device_items = system.opc.browseServer(opcServer, str(device_nodeId).replace('[' + opcServer + ']', ''))
for device_item in device_items:
device_item_name = device_item.getDisplayName()
device_item_type = device_item.getElementType()
device_item_nodeId = device_item.getServerNodeId()
if str(device_item_type).upper() == "OBJECT":
# Create as folder with placeholder as item. This allows tree to quickly be built but parent folder must be double-clicked for items to be populated
icon = "Builtin/icons/16/about.png"
sep_char = system.gui.getParentWindow(event).getComponentForPath('Root Container.Tree View').separationCharacter
tvItems = system.dataset.addRow(tvItems, [device_name + sep_char + device_item_name, "Placeholder", icon, "", "", "(double-click parent folder to refresh)", "", "", icon, "", "", "", "", str(device_item_nodeId).replace('[' + opcServer + ']', ''), device_item_type])
else:
icon = "icon-tag.png"
tvItems = system.dataset.addRow(tvItems, [device_name, device_item_name, icon, "", "", "", "", "", icon, "", "", "", "", str(device_item_nodeId).replace('[' + opcServer + ']', ''), device_item_type])
#assign the new dataset to the component data property
system.gui.getParentWindow(event).getComponentForPath(‘Root Container.Tree View’).data = tvItems[/code]
Then there’s a propertyChange event on the Tree View:
[code]if event.propertyName == “selectedPath”:
selectedItem = event.newValue
# Get the current dataset from the tree view object
tvItems = event.source.parent.getComponent('Tree View').data
# Convert it to a PyDataSet so we can iterate through it
pyDS = system.dataset.toPyDataSet(tvItems)
i = 0
# Find selected item in Tree View's dataset
for row in pyDS:
# Get data for selected item
# - nodeId and elementType are custom columns added to the end of the Tree View's dataset
path = row["path"]
text = row["text"]
nodeId = row["nodeID"]
elementType = row["elementType"]
if path == selectedItem and text == "Placeholder":
if elementType.upper() == "OBJECT":
# It's a folder that was clicked on so drill into its items
opcServer = "Ignition OPC-UA Server"
device_items = system.opc.browseServer(opcServer, nodeId)
# Following loop will add items to Tree View dataset and then delete placeholder record
for device_item in device_items:
device_item_name = device_item.getDisplayName()
device_item_type = device_item.getElementType()
device_item_nodeId = device_item.getServerNodeId()
if str(device_item_type) == "OBJECT":
icon = "Builtin/icons/16/about.png"
sep_char = system.gui.getParentWindow(event).getComponentForPath('Root Container.Tree View').separationCharacter
tvItems = system.dataset.addRow(tvItems, [path + sep_char + device_item_name, "Placeholder", icon, "", "", "", "", "", icon, "", "", "", "", str(device_item_nodeId).replace('[' + opcServer + ']', ''), device_item_type])
else:
icon = "icon-tag.png"
tvItems = system.dataset.addRow(tvItems, [path, device_item_name, icon, "", "", "", "", "", icon, "", "", "", "", str(device_item_nodeId).replace('[' + opcServer + ']', ''), device_item_type])
tvItems = system.dataset.deleteRow(tvItems, i)
# Refresh Tree View with updated dataset
event.source.parent.getComponent('Tree View').data = tvItems
# For testing purposes, refresh table showing Tree View dataset
table = event.source.parent.getComponent('Power Table')
system.db.refresh(table, "data")
break
else:
i += 1[/code]
This only browses one level at a time so it doesn’t take long. The only thing I’m not pleased with is there’s no event on the Tree View I could find for expanding and collapsing nodes so you have to double-click to trigger the selectedPath propertyChange event to populate each level.