I’m having issues with the DataModel. Anything I set and get using model.get() and model.set() is only stored in the specific node.
My URCap is structures as 1 parent node and 4 child nodes, and if I set() something in the parent node, the get() will return the default value in the child node. My question is then:
Is my DataModel only available to the node it is get() and set() in? Meaning there’s 5 DataModels in my structure, or did I do something wrong?
Afterwards I tried to add an installation node, but if I use the model.set() in the installation node, it is still not available for any of the other nodes. I believe it should be, so I’m guessing something’s wrong.
Each URCap node has its own DataModel, which is not shared with any other node.
Thank you for the reply. So I can’t access the datamodel from a different node? Can I share variables between node in any way then?
Do you really need the DataModel?
You can create a singleton object that stores the information that you need, with a public static getter that you can use anywhere in your code.
You can check a sample implementation here: Java Singleton Design Pattern Best Practices with Examples | DigitalOcean. Then, you can add getters and setters for the information you need to share.
Anything that should be accessible by the user should preferable be stored in the DataModel.
The DataModel is part of the program and installation files, so if you do not store your data here, the data will only be stored locally, and the user will have to reconfigure this again on a new robot.
If you are a parent-node, you can read and modify your child-nodes.
Either by them being built-in nodes such as Wait, or by using the URCap Custom API on your child nodes.
How do I use the URCap Custom API?
Check out the section “URCap Program Node proprietary API” in the “program node configuration” document in the SDK.
Thank you, I’ve read the pdf, but does still have a few questions:
So basically by implementing a Custom API on the child node, it is possible to access methods from the parent node?
To implement this I have to define this interface with the lines:
interface CustomAPI {
Setting getSetting ();
void setSetting ( Setting setting );
boolean isOptionEnabled ();
void reset ();
}
What are the functions of what’s inside the interface? Can I find that in any documentation? When I declare the interface with these it says that the type Setting is unresolved, so that is my main problem right now. I’ve declared the interface right before ProgramNodeContribution();.
I’m still learning Java, so I’ll apologise if it is obvious.
i would also recommend using a singleton object to handle the datamodel object between your Contributions as @jubeira said.
Just initialize the datamodel by the parent/master node and save the datamodel object reference to the singleton object.
I found the CustomAPI solution awkward and didn’t found a reasonable sample code for this.
I thought I would just share what I found out, after I got it to work:
So you have to declare an interface the so called “CustomAPI” and in here you will have to declare what methods you want to use. What confused me was the things defined inside “interface CustomAPI { … }” in line 3-7 of the attached example. However in the case you only want to set the DataModel you’ll only need a method called something like “setChildDataModel( … );” or whatever.
When you’ve done this, you will have to implement this interface to the child node like line 13 in the attached example, and then override the “setChildDataModel( … );” with the functionality you want like the other picture I’ve uploaded, which is my method.
Now you can, with the help of the CustomAPI, access this method in the parent node with childAs.setChildDataModel(…); like it is done in the example from line 20. Here they are accessing the method childAs.setSetting( … );
I hope this is clear if anyone needs it, and i apologize if my terminology is wrong as I’m not an experienced Java programmer.
![image](https://global.discourse-cdn.com/business7/uploads/universal_robots/original/1X/58e7800edcbf9f8e4231d61a5d1054d5b6f6f865.png)
Thanks a lot for sharing your gained knowledge, from working with this interface.
You may also want to check out this sample, demonstrating the custom API functionality:
And the DataModel is shared between 2 nodes which are of the same kind?? I’m having the trouble to save a value with model.set and model.get, 2 nodes of the same kind get the same value but I need every node save its own data, how can I achieve this?? thanks for the help
Each individual node has its own DataModel.
This is not shared with any other instance.
In the Program Node Service class, the DataModel provided in the createNode()
method is a separate instance for each node inserted.
The DataModel is empty, if this is a new instance of the node. If the node is copied or a program is loaded, this will give the DataModel containing previously configured values.
Yes, that what I been reading every where but I don’t know why mi node keep doing this…
I hope this gif help me explain what it’s happening to me, I been checking the hello world example and the tutorial My First URCap, the hello world don’t make this but the URCap created in the tutorials do this too, I hope someone know the reason of this. Thanks for the reply
Have you some code samples to help demonstrate this? what you should be doing to achieve the desired effect is:
- make sure the code that defines the drop down box is in buildUI or a method called from buildUI.
- Add an
ActionListener
to your drop down box. - in the
actionPerformed
method of thatActionListener
, use something likeContributionProvider.get().itemSelected(Object selectedItem)
to call the methoditemSelected
from your contribution class. - In your
itemSelected
method in your contribution class, usemodel.set("selection", selectedItem)
- change your
getTitle
method to returnmodel.get("selection", defaultSelection)
. - Likewise, in
openView()
set the selected item of the drop down to bemodel.get("selection", delfaultSelection)
, this will change the drop downs selected item to what it was when you were last in the node.
This way your the title for each node depends on the selected item that you chose when you each node was selected.
Because there is only ever 1 instance of the view class, anything that depends solely on the state of different components in the view class can behave oddly (eg. the title of a node in the tree).
Hope this helps.
Yes I checked all the steps and everything is right, here a left the code I checked
public void buildUI(JPanel panel, ContributionProvider contribution) {
panel.add(createTextBox("Select the stage of the process.")); panel.add(createVerticalSpace(5)); panel.add(createComboBox(contribution));
}
My method createComboBox
Preformatted textprivate Box createComboBox(final ContributionProvider contribution) {
Box box = Box.createHorizontalBox(); box.setAlignmentX(Component.LEFT_ALIGNMENT); stages.setPreferredSize(new Dimension(150,25)); stages.setPreferredSize(stages.getPreferredSize()); stages.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { contribution.get().setStage((String)e.getItem()); } }); box.add(stages); return box;
}
Method in contribution to save the selection
public void setStage(final String stage) {
undoReduManager.recordChanges(new UndoableChanges() { @Override public void executeChanges() { model.set(nodeStage, stage); } });
}
getTitle method
public String getTitle() {
return model.get(nodeStage, "Not Stage Defined");
}
openView method
public void openView() {
view.setComboBoxData(installation.getStages()); view.setComboBoxSelection(model.get(nodeStage, "notDefined"));
}
Could it be a problem because of the installation node?? is the DataModel shared with the program nodes DataModel??
Is that everythiing your getTitle
method does, also, what does your isDefined
method do, does that set anything? If so you should avoid setting thingsin this method, in fact doing so is considered good practice.
Yes thats all my getTitle method, and neither use set in isDefined method
@Override
public boolean isDefined() {if(model.isSet(nodeStage)) { return true; } return false;
}
I found a workaround if someone have the same problem, I used addActionListener to the JComboBox instead of addItemListener. I don’t know why the addItemListener was causing this.