I think you're on the right track with the Skin
class being the controller for the loaded FXML file because it is the Skin
that is responsible for defining the nodes that comprise the 'look' of a particular control.
The Control
class itself should really only define properties that hold the state of the control and should not care how the Skin
actually creates the view hierarchy (that is, it should only care about it's state, not how it looks).
One difference I would make is to change fxmlloader.setController(control);
to fxmlloader.setController(this);
so that the Skin
class becomes the controller rather than the control itself.
Another thing you could do is to move the FXMLLoader
logic into a base class so that you don't have to duplicate it every time you want to create a Skin
, something like this:
public abstract class FXMLSkin<C extends Control> extends SkinBase<C>{
public FXMLSkin(C control) {
super(control);
this.load();
}
private void load() {
FXMLLoader loader = new FXMLLoader(getFXML());
loader.setController(this);
try {
Node root = loader.load();
this.getChildren().add(root);
} catch (IOException ex) {
Logger.getLogger(FXMLSkin.class.getName()).log(Level.SEVERE, null, ex);
}
}
protected abstract URL getFXML();
}
I have a JavaFX UserControl
on my Github page which does something very similar to the FXMLSkinBase
class above. It uses a convention to load an FXML file with the same name as the derived class so that the FXML file name does not need to be specified each time. I.E. if your derived skin is called FooControlSkin
, the control will automatically load an FXML file called FooControlSkin.fxml
.
The class is very simple and the code could very easily be refactored into a fully featured FXMLSkinBase
class that would meet your requirements.