Hello Today after long days I’ve came here to share my experience of FXML in JavaFX. After working with FXML I found it’s really easy for every developer.
Requirements:
- XML knowledge
- CSS knowledge
FXML and Binding Stuff
Ok First lets start with a FXML Template.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<?import java.lang.*?> <?import javafx.scene.*?> <?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <?import javafx.scene.shape.*?> <?import fxmlstuff.fxml.*?> <GUITemplate id="main" prefHeight="200" prefWidth="320" xmlns:fx="http://javafx.com/fxml" fx:controller="fxmlstuff.fxml.GUITemplate"> <children> <Rectangle fx:id="back" /> <Rectangle fx:id="front" /> <Button fx:id="button" text="Click Me" onAction="#handleButton"/> <Button fx:id="clear" text="Clear Me" onAction="#handleClearButton"/> <TextArea fx:id="textArea"/> </children> </GUITemplate> |
In above FXML I’ve not added Rectangle,Button,TextArea controls.
As per the FXML specification you can call the function from the FXML attribute using ‘#’ just before the function name. Here I’ve added #handleButton()
and #handleClearButton()
functions to handle the event of Buttons. Here First we are going to load them in JavaFX Application moreover we are going to make the Rectangle
flexible to the Stage
‘s width and height. To make any shapes or controls width and height relative to the Stage
‘s width, height we can use bind feature plus a the control or the shape which we are going to make bind must static
. Ok now we are going to need one Controller for the FXML which helps to control the FXML GUI components. I’ve already added fx:controller = "fxmlstuff.fxml.GUITemplate"
in above FXML. So to map the controller we ought to make one conroller class inside fxmlstuff.fxml
package with classname GUITemplate.java
GUITemplate.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
" ]public class GUITemplate extends StackPane implements Initializable { //Main GUI Components @FXML private Button button,clear; @FXML private Rectangle back,front; @FXML private TextArea textArea; //Helper Properties @FXML private static DoubleProperty widthX = new SimpleDoubleProperty(500); @FXML private static DoubleProperty heightX = new SimpleDoubleProperty(500); //static access to the Helper Properties public static DoubleProperty heightXProperty() { return heightX; } public static DoubleProperty widthXProperty() { return widthX; } //Button Action Handling public void handleButton(ActionEvent ac){ textArea.appendText("\n Yes you clicked"); } public void handleClearButton(ActionEvent ac){ textArea.setText("==============================\n" + " Welcome to the Console of JavaFX\n" + "==============================\n"); } //Main Initialization @Override public void initialize(URL url, ResourceBundle rb) { } } |
In above Java controller I’ve not done anything. Just made the instances. We’ll need to customize our controller class to make things working greatly.You can see there are eventHandler for the buttons also. I just want you to know that I’ve made some variables static which is useful for binding with Stage width and height. Here one more Java class we need to add i.e. FXMLStuff.java a.k.a main executor class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
" ]public class FXMLStuff extends Application{ /** * @param args the command line arguments */ public static void main(String[] args) { // TODO code application logic here launch(args); } @Override public void start(Stage stage) throws Exception { GUITemplate tpl = (GUITemplate) FXMLLoader.load(getClass().getResource("fxml/GUITemplate.fxml")); Scene scene = new Scene(tpl,500,500); scene.getStylesheets().add(getClass().getResource("fxml/gui.css").toExternalForm()); GUITemplate.heightXProperty().bind(stage.heightProperty()); GUITemplate.widthXProperty().bind(stage.widthProperty()); GUITemplate.loadOnStart(); stage.setScene(scene); stage.show(); } } |
As you can see on the main executor class there we’ve bind the property with respect to the Stage’s width and height. Currently If you compile them you won’t be able to see any thing magic. So to make thing work let’s touch with CSS. Let’s attach some css with our controller and css. Here we are again back to controller class.
GUITemplate.java(some edit)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
@Override public void initialize(URL url, ResourceBundle rb) { //-------------- //Some bindings //-------------- back.widthProperty().bind(widthX.subtract(50)); back.heightProperty().bind(heightX.subtract(100)); front.heightProperty().bind(back.heightProperty().subtract(100)); front.widthProperty().bind(back.widthProperty().subtract(100)); textArea.maxHeightProperty().bind(front.heightProperty()); textArea.maxWidthProperty().bind(front.widthProperty()); //--------- //Some CSS //--------- back.getStyleClass().addAll("rect","back-rect"); front.getStyleClass().addAll("rect","front-rect"); button.getStyleClass().add("control"); clear.getStyleClass().add("control"); textArea.getStyleClass().add("text-area"); //StackPane aligns and margins StackPane.setAlignment(button, Pos.BOTTOM_RIGHT); StackPane.setAlignment(clear, Pos.BOTTOM_LEFT); StackPane.setMargin(button, new Insets(0,70,50,0)); StackPane.setMargin(clear, new Insets(0,0,50,70)); } |
I’ve add some bindings to make the rectangle and control to be updated according to the Stage’s width and height. Also I’ve added some css class to customize the default controls color and style. Finally I did alignment for the clear
and button
Button
to the left and right with some margins.
CSS Stuffs
Now we can head towards CSS for our design.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
/* Class for both buttons */ .control{ -fx-base:#404040; -fx-outer-border:gray; -fx-focus-color: derive(gray,10%); } /* Class default text area */ .text-area{ -fx-outer-border:transparent; -fx-focus-color: transparent; -fx-text-box-border:transparent; -fx-shadow-highlight-color:transparent; -fx-control-inner-background:transparent; } /* Class for both rectangles */ .rect{ -fx-fill:#f3f3f3; -fx-opacity:1; -fx-effect: dropshadow(two-pass-box , black, 5, 0.0 , 0, 1); -fx-arc-width: 20; -fx-arc-height: 20; } /* Class for both front Yellow rectangle */ .front-rect{ -fx-effect: innershadow(two-pass-box , black, 7, 0 , 0,1); -fx-fill: linear-gradient(to bottom, derive(#fdffbb,0%), #fcea72) ; } /* Class for both back black rectangle */ .back-rect{ -fx-fill: linear-gradient(to bottom, derive(#4d4d4d,0%), #0b0b0b); } |
If you are new to CSS of javafx then please have a look at this CSS reference: CSS Ref
Now If compile and run this program you will output like this:
If you like more like run some Java code during initialization of the FXML then Yes, you can do it! You just need to make things static
so that it is accesible by the main-executor class or other class to run specific java task inside FX Thread.
GUITemplate.java( Added Java Task inside initialize )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
//.... public static void loadOnStart(){ textArea.setText("==============================\n" + " Welcome to the Console of JavaFX\n" + "==============================\n"); Task task = new Task<Void>(){ @Override protected Void call() throws Exception { //Timer t = new Timer(); Timer timer = new Timer(5000,new ActionListener(){ @Override public void actionPerformed(java.awt.event.ActionEvent ae) { textArea.appendText("\n : 5 second gone..."); } }); timer.start(); return null; } }; new Thread(task).start(); } @Override public void initialize(URL url, ResourceBundle rb) { //..codes of previous loadOnStart(); } //... |
Now load them inside initialize of the FXController or load them from the Main executor class as per your requirement. I’ve loaded them insize initialize
of the GUITemplate.java
. Now you can see that the “: 5 second gone..” is printed in TextArea every 5 second which is the Java thread.
Project Source Code : FXMLStuff.zip
Ok Thanks for watching the blog. Please feel free for comment.
Have a 🙂 good day