[Part 5] Custom Node Content
UPDATE [23.05.2014]: This tutorial need features that are no longer part of the JFXtras library. If you have problems building it, you might want to try the JavaOne2013 project that also makes use of the Custom Node feature.
First of all, sorry for the delay. Many of you asked me how to add custom node content to VNodes. This tutorial will finally lift this secret 😉
If you haven’t done so already please read the previous parts of the tutorial: Part 1, Part 2, Part 3 and Part 4.
Short Demo on Custom Node Content:
Adding Content
The latest snaphot release (vworkflows-fx:0-1-r1-SNAPSHOT
) contains a new skin factory that allows to register node skins for specific value types. Instead of FXValueSkinFactory
one has to use FXValueSkinFactory
instead:
// create skin factory for flow visualization
FXValueSkinFactory fXSkinFactory = new FXValueSkinFactory(canvas.getContentPane());
Registering custom node skins is very easy:
// register visualizations for Integer, String and Image
fXSkinFactory.addSkinClassForValueType(Integer.class, IntegerFlowNodeSkin.class);
fXSkinFactory.addSkinClassForValueType(String.class, StringFlowNodeSkin.class);
fXSkinFactory.addSkinClassForValueType(Image.class, ImageFlowNodeSkin.class);
// generate the ui for the flow
flow.addSkinFactories(fXSkinFactory);
It is also possible to register multiple factories at the same time that use a different set of node skins!
Anatomy of a Custom Flow Node Skin
A custom node skin usually inherits from FXFlowNodeSkinBase
and provides a custom version of the updateView()
method:
public class CustomFlowNodeSkin extends FXFlowNodeSkinBase {
@Override
public void updateView() {
// ...
}
}
The version we provide in the tutorial project looks like this:
public abstract class CustomFlowNodeSkin extends FXFlowNodeSkinBase {
public CustomFlowNodeSkin(FXSkinFactory skinFactory,
VNode model, VFlow controller) {
super(skinFactory, model, controller);
}
protected abstract Node createView();
/**
* Will be called once for each value change.
*/
@Override
public void updateView() {
super.updateView();
// we don't create custom view for flows
if (getModel() instanceof VFlowModel) {
return;
}
// we don't create a custom view if no value has been defined
if (getModel().getValueObject().getValue() == null) {
return;
}
// create the view
Node view = createView();
// add the view to scalable content pane
if (view != null) {
ScalableContentPane scalableContentPane = new ScalableContentPane();
scalableContentPane.setPadding(new Insets(10));
GridPane nodePane = new GridPane();
nodePane.setAlignment(Pos.CENTER);
scalableContentPane.setContentPane(nodePane);
scalableContentPane.getContentPane().getChildren().add(view);
getNode().setContentPane(scalableContentPane);
}
}
}
In the updateView()
method we define a scalable container for the actual value view. If the node the skin visualizes does contain child nodes we don’t provide a custom view.
Example Skins:
The tutorial project provides the following skins:
The LCD gauge and the segment display are part of the JFXtras library (http://jfxtras.org). See Gerrit Grunwalds Enzo library for other very nice and lightweight gauges (depends on JDK 8).
Feedback
If you’d like to contribute or if you want to ask questions about VRL, VWorkflows and other related projects join the Developer & User groups:
- Developer Group: https://groups.google.com/forum/#!forum/vrl-developers
- User Group: https://groups.google.com/forum/#!forum/vrl-studio-users
Demo Application
Download the tutorial code from GitHub.
Requirements:
- Java 7 or a recent Java 8 preview build (>=b98)
- Optional: Netbeans >=7.3 with Gradle Plugin
Building & Running:
To run the application from the command line just type ./gradlew run
.
Stay tuned and follow me on Twitter
To be continued…
Leave a Reply