It's already some time ago when I released my last blog post but I was busy with presentation preparation, trainings, preparing stuff for my upcoming JavaFX related podcast etc.
I was playing around with validation using css styles and so far that is an easy way to do some validation. But I in the Java Swing days I used the GlasPane to draw validation icons on top of invalid or valid controls. This approach was not always useful but I liked it because I could use one set of validation icons and validate all kinds of controls. So I was asking myself how I could implement this behavior in JavaFX.
I decided to go with the Canvas node because it has a translucent background by default and enables me to draw whatever I like by only using one node on the scene graph. The only disadvantage was that the Canvas node is like an image means it won't resize automatically but you have to take care about size by yourself.
Well the solution to this problem could be extending Canvas and implement the autosizing behavior or encapsulate the Canvas node into another node which could be resized automatically and react on the new size by using an InvalidationListener to the resizable control. I decided to encapsulate the Canvas node in a Region because it's lightweight and supports resizing.
The implementation is more a proof of concept than a ready to go solution but it should be good enough to play around with it. It only takes two classes, the
- ValidationPane
- Validator
The ValidationPane is simply a Region which encapsulates a Canvas node. To use the ValidationPane one simply has to add the nodes that should get the validation overlays by using one of the following methods
- add(Node node)
- add(Pos position, Node node)
- addAll(Node... nodes)
- addAll(Pos position, Node... nodes)
Here is a short example that shows you how to add a TextField to the ValidationPane
TextField textField = new TextField();
ValidationPane validationPane = new ValidationPane();
validationPane.add(Pos.TOP_LEFT, textField);
As you could see it is possible to configure the position of the validation icon (the default position is Pos.TOP_LEFT).
There are five different states that one could use for validation
- Validator.State.VALID
- Validator.State.INVALID
- Validator.State.INFO
- Validator.State.OPTIONAL
- Validator.State.CLEAR
To set the validation state of a node you simply have to call the setState() method on the validation pane, for the example above this would look like follows
validationPane.setState(textField, Validator.State.INVALID);
If you set the validation state to Validator.State.VALID the validation icon will fade out after 1500 ms to keep the interface clean.
If the node is invalid the validation icon will stay visible as long as it is in the invalid state.
On the following screenshot you could see three different states (Validator.State.CLEAR has no indicator).
You could see all three available indicators on the image above (invalid, valid and info).
The idea was to use the validation not only for textfields (which is most of the times the standard use case) but for example also for complete layout containers like a HBox, GridPane etc.
Therefor it works on the JavaFX Node instead of Control. I did not make very indeep tests with it and cannot guarantee that it works in any case but like I said it's more a proof of concept than a ready to go solution.
To use it you simply have to wrap your existing root pane in an additional StackPane and put the ValidationPane on top by adding it at the last node to the StackPane. Because the ValidationPane is transparent to mouse events it won't catch events and should be "invisible" to your application. The following image should try to give you an idea...
It was fun to create and very similar to the Swing GlasPane approach and proofed that even if JavaFX is based on a SceneGraph using nodes for visualization one could easy adopt a bitmap based approach by using the Canvas node.
If you are interested in the source code, please find it here.
The idea was to use the validation not only for textfields (which is most of the times the standard use case) but for example also for complete layout containers like a HBox, GridPane etc.
Therefor it works on the JavaFX Node instead of Control. I did not make very indeep tests with it and cannot guarantee that it works in any case but like I said it's more a proof of concept than a ready to go solution.
To use it you simply have to wrap your existing root pane in an additional StackPane and put the ValidationPane on top by adding it at the last node to the StackPane. Because the ValidationPane is transparent to mouse events it won't catch events and should be "invisible" to your application. The following image should try to give you an idea...
It was fun to create and very similar to the Swing GlasPane approach and proofed that even if JavaFX is based on a SceneGraph using nodes for visualization one could easy adopt a bitmap based approach by using the Canvas node.
If you are interested in the source code, please find it here.
ATTENTION: I'm using lambdas in the code which might not work in every IDE !!!
UPDATE:
During the last JavaFX training course at Canoo in Basel one of the attendees pointed me to a useful feature for the validation pane. If you think about nodes that are invalid and are not visible. These nodes should not show their validation icon right...so I've added this behavior to the ValidationPane. So if you would like to take a look, feel free to get the code from BitBucket. I've also updated the demo to show the new behavior.
That's it for today so keep coding...
Nice approach. Adding the ValidationPane to a StackPane is something that has to be done manually or is there a utility method on ValidationPane?
ReplyDeleteAnd, ah, awfully perfectly suited for JFXtras...
At the moment you have to add it manually like you described it but I like your idea with the utility method :)
DeleteCheers,
Gerrit
Cool, great job as always!
ReplyDeleteI will soon play around with it
This looks very nice.
ReplyDeleteI need to start experimenting with JavaFX
nice one,
Jim