Features of JavaFX such as declarative UI scripting, and binding, make it very natural to use a model-view-controller pattern. I typically have at least one class that comprises the model, and usually put model classes in a package whose ending node is "model".
Often it is necessary to share a model instance with more than one view class. In these cases I leverage the Singleton pattern with a factory function to ensure that there is at most one instance of a model class. The screenshot below is the UI of a very simple program that I developed to demonstrate this technique. The screenshot on the right is of the quintessential model Betty Boop :-)
Here's the code behind the example, beginning with the model class:
/*
* SingletonExampleModel.fx
*
* Example of using the Singleton pattern to have share a model class
* by more than one view class in JavaFX.
*
* Developed 2009 by James L. Weaver as a JavaFX example to be freely used
*/
package com.javafxpert.model;
/**
* Singleton instance of model
*/
var modelInstance:SingletonExampleModel;
/**
* Get or create the singleton instance of model
*/
public function getInstance():SingletonExampleModel {
if (modelInstance == null) {
modelInstance = SingletonExampleModel {};
}
return modelInstance;
}
public class SingletonExampleModel {
/**
* String that comprises this very simple model
*/
public var myString:String = "Change me!";
}
The model class above uses a module-level variable to store the singleton instance, and a module-level function that retrieves it (creating one if necessary). This model instance is accessed by the simple, contrived, view classes (CustomNodeA and CustomNodeB) shown in the listings below:
CustomNodeA.fx:
package com.javafxpert.ui;
import javafx.scene.*;
import javafx.scene.control.TextBox;
import com.javafxpert.model.SingletonExampleModel;
public class CustomNodeA extends CustomNode {
/**
* Reference to the model class
*/
var model:SingletonExampleModel = SingletonExampleModel.getInstance();
/**
* Define the scene graph for this custom node
*/
public override function create() {
var tbRef:TextBox = TextBox {
text: "Change me!"
columns: 15
action: function():Void {
model.myString = tbRef.text;
}
}
}
}
CustomNodeB.fx:
package com.javafxpert.ui;
import javafx.scene.*;
import javafx.scene.text.*;
import com.javafxpert.model.SingletonExampleModel;
public class CustomNodeB extends CustomNode {
/**
* Reference to the model class
*/
var model:SingletonExampleModel = SingletonExampleModel.getInstance();
/**
* Define the scene graph for this custom node
*/
public override function create() {
Text {
content: bind model.myString
font: Font.font("default", FontWeight.BOLD, 24)
}
}
}
Finally, here is the main script that puts the custom nodes shown above in a scene on the stage:
SingletonExampleMain.fx
package com.javafxpert.ui;
import javafx.stage.Stage;
import javafx.scene.*;
import javafx.scene.layout.VBox;
Stage {
title: "Singleton Model Example"
scene: Scene {
width: 300
height: 200
content: VBox {
translateX: 50
translateY: 50
spacing: 30
content: [
CustomNodeA {},
CustomNodeB {}
]
}
}
}
Using this technique, any number of view classes can access a single, shared, model instance.
Regards, and please leave a comment if you have any questions,
Jim Weaver
JavaFXpert.com
Recent Comments