JavaFX: Creating custom controls – the right way
Is is quite difficult to create custom controls in JavaFX that perform like they should. This is the result of lack of documentation, unavailability of source code and a not-so-good API…
I struggled with that issue for two days. And finally I think I understood the hole concept. I wrote about that process in this blog some days ago.
If you are just looking for a template, continue here.
Here is a small drawing that visualizes the relevant methods/fields related to custom controls:

width/height
The width and height are set by the container. The container calculates the width/height based on the values returned by getPrefWidth/Height and getMaxWidth/Height.
layoutBounds
The layoutBounds are calculated automatically based on the values of width/height of the control.
Attention: The layoutBounds do not depend on the layoutBounds of the node created by the Skin!
This might be counter-intuitive. But it is necessary since the Control is resizable. And therefore the layoutBounds have to depend on the width/size (which are set by the container).
boundsInLocal
The boundsInLocal are bound to the boundsInLocal of the node created by the skin. Just as you might have expected.
getMin/Pref/MaxWidth/height
The control delegates those method calls to the currently active Skin. At least it is necessary to implement the getPrefWidth/Height methods. The default implementation just returns hard coded values (100/50). If you don’t have implemented those methods, the layoutBounds of the control will be wrong. And this will result in odd layout behaviour of your custom node!
Which methods to extend? Which fields to bind?
There are two things you have to do:
Step 1: Override getPrefWidth/Height in Skin
This is *really* necessary. Those methods should have been made abstract. I can’t imagine any case where those methods don’t have to be overridden… So just override them. Returning hard coded values is ok for most cases.
Step 2: Bind the size of the node to Control#width/height
Whenever the layoutBounds of the control change, the size of the node must be adjusted. It depends on your implementation how the relationship might be. For simple nodes without any effects a simple bind should be enough:
[cc lang="c" escaped="true" tab_size="2" lines="20"]
class MySkin extends Skin {
init {
node = Rectangle {
width: bind control.width
height: bind control.height
}
}
…
[/cc]
Now you have created a custom Control that behaves as expected – and is resizable…
I have created a template to create custom a control and skin.




