I am attempting to make a simple button with pre-implemented navigation code in a module I am creating. But I cannot figure out how to get this scripting into the Java Module.
Basically, the component has 2x String Properties - Window Path and Tag Path. And will use these to open the popup at the vision location of Window Path and feed in the Tag Path as a parameter to the window. For example, a Jython Script for the same task on a button with 2 parameters "WindowPath" and "TagPath":
I tried looking at documentation but just could not wrap my head around how to do it in Java. If anyone can offer and help I would be very appreciative.
Me and a colleague have been looking at this for a hour or two and have found that we can get this to work using:
NavUtilitiesDispatcher navUtilsDisp = new NavUtilitiesDispatcher(FPMIApp.getInstance());
PyDictionary parameters= new PyDictionary();
parameters.put("TagRoot", tagRoot);
navUtilsDisp.openWindowInstance(windowPath, parameters);
navUtilsDisp.centerWindow(this.windowPath);
And it seems to work perfectly well. However, are you saying that this has the change to break general parts of the vision module? Do Note: I am aware that the FPMIApp.getInstance() is depreciated but I currently see no alternatives.
Let me know what we are all thinking and if it has the potential to cause major issues I will just go with the trusty internal Jython Scripting on the component, but for the application an internal method would be perfect.
It's less about access to internals (though that does have some fundamental risks on its own) and more about a fundamental design paradigm. Throughout Vision and Perspective, components provide hooks, and the developer working in the Designer chooses to implement (or not) whatever desired functionality they want in those hooks. By "pre-scripting" functionality in your components, you're taking that flexibility away from your end users.
You could probably achieve something close to the desired result without any "unsafe" edges by creating a custom component with some scripts automatically placed on it - the default behavior on drop is to do what you want, but end users are still able to change or disable this behavior if they want to.
This is also not to say that it's not potentially okay to offer a "magic button" via a custom module - it's your module, and of course you're free to do whatever you want with it, and you know your intended audience better than us. But if it's intended for wider distribution than "people you can directly explain this to", I'd highly recommend sticking to exposing hooks over exposing functionality if you're creating something as fundamental as a button.
This was a bit of a voyage of discovery for me, so bear with me if any of these explanations are a bit half-baked.
So, it looks like you want your component class to implement com.inductiveautomation.vision.api.client.components.model.SelfBinder - as the name/Javadoc suggest, it's used for components that set up their own event scripts (like the Paintable Canvas).
The first thing you want to do in your implementation of installBindings is check that no bindings already exist on the component - by definition, since your component is a SelfBinder, that will only be true on brand new components:
public void installBindings(InteractionController controller) {
Adapter[] adapters = controller.getAllAdaptersForTarget(this);
if (adapters.length == 0) {
Then, you will need to construct the event script wrapping object, an ActionAdapter and set it up with all the required elements.
Again, taking from the Paintable Canvas:
EventSetDescriptor and MethodDescriptor are standard Java "beans" introspection classes, not Ignition/Vision specific.
As far as I can tell, that's basically it. Whenever your component is constructed by Vision, if it happens to be a SelfBinder we'll automatically run that initialization code to allow you to configure it.
May I ask, is the jython code kept in the writer object and if so how is this initialized? Is there any code available with the constructor used for this application?
Currently, in my code I have as instructed implemented SelfBinder in my component:
public class ButtonComponentTest extends AbstractVisionComponent implements SelfBinder
and before my setter and getter methods, I have implemented the installBindings method:
The module builds and installs, and I can place the custom component also the vision project browser indicates that I do in-fact have some form of script on the component. But, whenever I try to CTRL+J or right-click and select "Scripting...", absolutely nothing happens no IDE, nothing... See screenshot below of the component in the project browser:
So after finally a colleague reminded me that the Console exists in Designer, I have determined that when placing the component I am getting a NoSuchMethod Exception and if I try to get onto the Scripting menu I get a java.lang.NullPointerException.
and the error exists on the line adapter.setMethodDescriptor(new MethodDescriptor(MeterButtonComponent2.class.getMethod("actionPerformed", ActionEvent.class)));, in the second try-statement.
Anyone able to point me in the direction to getting this resolved?
Resolved: in the line mentioned above I should have been using adapter.setMethodDescriptor(new MethodDescriptor(ActionListener.class.getMethod("actionPerformed", ActionEvent.class)));