I have a simple "comments" button popup I want to get data back from, and I don't know the best way to do this.
I have a template repeater on the main window, and each template instance has a "edit comments" button on it. When I press that, it opens a new popup window for the user to put their comments in. I don't know what to put in the "actionPerformed" script for the "submit" button on the popup.
My first guess would be a message handler, but Vision components can't receive messages like Perspective components can. How should I go about this?
I have already thought of system.gui.inputBox, but the text is too small. A client tag dataset seems most logical to me, but it just feels like a messy way to do a simple thing.
I want the whole screen to be like a form where a "submit" button enters data from all the template instances. I don't want any database writing to happen until that button is pressed. That's what made sense to me. No undo-redo, just a hard submit with an "are you sure?" attached.
Okay, so that seems to solve the template to window gap, but what about communicating from the popup window to the main window? system.gui.getOpenedWindows()?
system.gui.getOpenedWindows() returns all of the currently opened windows. Since, presumably you already know the name of the window, and you know that it will be open, then there is no need to use that, just get a reference to the window.
I've used something like this as well when having a generic popup to do things.
Basically, you have a function on your window that you would pass to the popup, and the popup would call that function before closing to either pass data back, or provide a confirmation etc...
Here's the situation I have, in case I wasn't super clear about it before:
I'm hoping I can use closure to create a reference to a property in the template instance ("comment" property), put that in a callback function, use the suggested method to pass that function to the popup, then call it once the popup returns.
Not closures, no, but the script that opens that popup can use the returned window object's .putClientProperty() method to store an arbitrary object reference in the popup. The popup's save action would use the window's matching .getClientProperty() to retrieve the original component, to which it can then assign results to properties.
Unlike client tags, this approach scales to many popup windows, even those created with .openWindowInstance().
I got it! But I want to make sure I'm not doing anything dangerous (not thread-safe) or unnecessary. Do I need the invokeLater call?
Template Open Popup Button
from functools import partial
template = event.source.parent
def setNewComment(newComment):
template.comment = newComment
def updateComment(newComment):
'''Callback function to update the comment property on the template from the popup context'''
system.util.invokeLater(partial(setNewComment, newComment))
window = system.nav.openWindow('Path/To/MyPopup', {'comments': event.source.parent.comment})
window.putClientProperty('updateComment', updateComment)
system.nav.centerWindow(window)
While I'll admit first off that I haven't tested your code, but couldn't you just remove both the setNewComment function and from functools import partial and change the updateComment function as follows:
com.inductiveautomation.ignition.common.script.JythonExecException: Traceback (most recent call last):
File "<event:actionPerformed>", line 4, in <module>
AttributeError: 'com.inductiveautomation.factorypmi.application.com' object has no attribute 'comment'
Presumably because the property is now private in this context.