Ignition 8.1 / Vision / Component Alarm Status table.
My goal is to make a right click menu popup that allows for a couple of options based on some custom parameters in the alarm.
def createPopupMenu(self, selectedAlarmEvents):
names = []
funcs = []
InputNum = selectedAlarmEvents[0].get("Number")
PLC = selectedAlarmEvents[0].get("PLC")
Provider = selectedAlarmEvents[0].get("Provider")
path = "Popups/Inputs"
params = {"PLC":PLC, "Provider":Provider, "InputNum":InputNum }
def OpenDrill(event):
import system
system.nav.openWindow("Main Windows/Site/FAB1/Level 1/Sector 1")
names.append("Go to Page")
funcs.append(OpenDrill)
def OpenPopup(path, params):
import system
system.nav.openWindow(path, params)
names.append("Open Input Popup")
funcs.append(OpenPopup(path, params))
menu = system.gui.createPopupMenu(names, funcs)
return menu
what happens with this is that the OpenPopup portion fires and opens the correct popup when right click is done to bring up menu. Never really see the menu it just instantly navigates. So I guess I am missing something in function to wait for click... not sure what though.
Also,
With this it depends on a single alarm being "selected" on the table. Is there a way to make this work without the selection so that it is based on the alarm that is under the right click only?
That's the core problem.
You need to pass a callable reference to your function - what you're doing is calling your function, which is why it immediately opens the popup. A complication is that system.gui.createPopupMenu
expects your function to accept one argument (for an event object) and nothing else. So, one option you have is to use Python's builtin functools
module, specifically the partial
function: 9.8. functools — Higher-order functions and operations on callable objects — Python 2.7.18 documentation
The partial()
is used for partial function application which “freezes” some portion of a function’s arguments and/or keywords resulting in a new object with a simplified signature. For example, partial()
can be used to create a callable that behaves like the int()
function where the base argument defaults to two:
Which you could then use to wrap a simple function that calls openWindow. Putting it all together, it would look something like this:
def createPopupMenu(self, selectedAlarmEvents):
names = []
funcs = []
from functools import partial
def openWindow(event, path, params = None):
system.nav.openWindow(path, params or {})
names.append("Go to Page")
funcs.append(partial(openWindow, path="Main Windows/Site/FAB1/Level 1/Sector 1"))
params = {
"PLC": selectedAlarmEvents[0].get("PLC"),
"Provider": selectedAlarmEvents[0].get("Provider"),
"InputNum": selectedAlarmEvents[0].get("Number")
}
names.append("Open Input Popup")
funcs.append(partial(openWindow, path="Popups/Inputs", params=params))
return system.gui.createPopupMenu(names, funcs)
Yes, but it's not trivial. The event
object delivered to you in the createPopupMenu callback will have x and y coordinates on it. "Inside" the alarm status table are (technically, a couple) Java swing JTable components, which have a rowAtPoint()
method to convert an x/y coordinate to a selected row on the table. The AST itself, meanwhile, has a viewRowToAlarm
function to convert a row index to an actual selected alarm. With those things together, you should be able to take a click on the context menu, convert it into a row, convert that row into an alarm, and do something with that alarm. But it's not trivial.