VOOZH about

URL: https://www.javacodegeeks.com/2015/01/how-to-allow-users-to-customize-the-ui.html

⇱ How to allow users to customize the UI - Java Code Geeks


Idea

Take advantage of the declarative design pattern of JavafX/FXML and allow users to customize a certain view without any coding just by opening it with e.g. SceneBuilder to re-arrange the layout or add new controls or even change the style according to the users needs.

The FXML file + CSS can be basically be placed whereever they are reachable via a URL. The user must only know the interface/methods of the assigned controller class inside the FXML.
 
 
 

RemoteController

Assuming this simple demo controller class provides methods to remotely control devices and to send MQTT messages, a user is able to customize his own remote control.

public class RemoteController{

 @FXML
 public void onTest(){
 Alert alert = new Alert(Alert.AlertType.INFORMATION);
 alert.setContentText("");
 alert.setHeaderText("WORKS!");
 alert.show();
 }
 
 public void onTest(String value){
 Alert alert = new Alert(Alert.AlertType.INFORMATION);
 alert.setHeaderText("WORKS!");
 alert.setContentText(value);
 alert.show();
 }
 
 public void onSwitch(String houseCode, int groudId, int deviceId, String command){
 Alert alert = new Alert(Alert.AlertType.INFORMATION);
 alert.setHeaderText("Switch!");
 alert.setContentText(String.format("Command: send %s %d %d %s", houseCode, groudId, deviceId, command));
 alert.show();
 }
}

remote.fxml and remote.css

Note the referenced de.jensd.shichimifx.demo.ext.RemoteController and remote.css.

So basically controller actions can be called via:

onAction="#onTest".

Nice:

If you add:

<?language javascript?>

to FXML, it’s also possible to pass parameters by a JavaScript call via the controller-instance.

onAction=controller.onTest('OFF')
onAction=controller.onSwitch('a',1,1,'ON')

Unfortunately I can’t find more documentation about this feature than -> this, but somehow it magically it works ;-). Its even possible to pass different types of parameters.

<?xml version="1.0" encoding="UTF-8"?>

<?language javascript?>
<?import javafx.geometry.*?>
<?import java.lang.*?>
<?import java.net.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<VBox alignment="TOP_CENTER" prefHeight="400.0" prefWidth="600.0" spacing="20.0" styleClass="main-pane" stylesheets="@remote.css" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="de.jensd.shichimifx.demo.ext.RemoteController">
 <children>
 <Label styleClass="title-label" text="Universal Remote" />
 <HBox alignment="CENTER_RIGHT" spacing="20.0">
 <children>
 <Label layoutX="228.0" layoutY="96.0" styleClass="sub-title-label" text="Light Frontdoor" />
 <Button layoutX="43.0" layoutY="86.0" mnemonicParsing="false" onAction="#onTest" prefWidth="150.0" styleClass="button-on" text="ON" />
 <Button layoutX="411.0" layoutY="86.0" mnemonicParsing="false" onAction="#onTest" prefWidth="150.0" styleClass="button-off" text="OFF" />
 </children>
 <padding>
 <Insets left="10.0" right="10.0" />
 </padding>
 </HBox>
 <HBox alignment="CENTER_RIGHT" spacing="20.0">
 <children>
 <Label layoutX="228.0" layoutY="96.0" styleClass="sub-title-label" text="Light Garden" />
 <Button layoutX="43.0" layoutY="86.0" mnemonicParsing="false" onAction="controller.onTest('ON')" prefWidth="150.0" styleClass="button-on" text="ON" />
 <Button layoutX="411.0" layoutY="86.0" mnemonicParsing="false" onAction="controller.onTest('OFF')" prefWidth="150.0" styleClass="button-off" text="OFF" />
 </children>
 <padding>
 <Insets left="10.0" right="10.0" />
 </padding>
 </HBox>
 <HBox alignment="CENTER_RIGHT" spacing="20.0">
 <children>
 <Label layoutX="228.0" layoutY="96.0" styleClass="sub-title-label" text="Light Garden" />
 <Button layoutX="43.0" layoutY="86.0" mnemonicParsing="false" onAction="controller.onSwitch('a', 1,1,'ON')" prefWidth="150.0" styleClass="button-on" text="ON" />
 <Button layoutX="411.0" layoutY="86.0" mnemonicParsing="false" onAction="controller.onTest('OFF')" prefWidth="150.0" styleClass="button-off" text="OFF" />
 </children>
 <padding>
 <Insets left="10.0" right="10.0" />
 </padding>
 </HBox>
 </children>
 <padding>
 <Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
 </padding>
</VBox>

Based on this example a user is able to simple open the FXMl with SceneBuilder and to add new Button calling the controller.onSwitch() method to control different/new devices installed for home automation.

FxmlUtils

The next release of ShichimiFX will contain a new Utilily class to load FXML as shown in the ExternalFXMLDemoController. Note that the loaded Pane is added to the center of the externalPane (BorderPane) of the Demo-Application via onLoadExternalFxml():

public class ExternalFXMLDemoController {

 @FXML
 private ResourceBundle resources;

 @FXML
 private BorderPane externalPane;

 @FXML
 private TextField fxmlFileNameTextField;

 @FXML
 private Button chooseFxmlFileButton;

 @FXML
 private Button loadFxmlFileButton;

 private StringProperty fxmlFileName;

 public void initialize() {
 fxmlFileNameTextField.textProperty().bindBidirectional(fxmlFileNameProperty());
 loadFxmlFileButton.disableProperty().bind(fxmlFileNameProperty().isEmpty());
 }

 public StringProperty fxmlFileNameProperty() {
 if (fxmlFileName == null) {
 fxmlFileName = new SimpleStringProperty("");
 }
 return fxmlFileName;
 }

 public String getFxmlFileName() {
 return fxmlFileNameProperty().getValue();
 }

 public void setFxmlFileName(String fxmlFileName) {
 this.fxmlFileNameProperty().setValue(fxmlFileName);
 }

 @FXML
 public void chooseFxmlFile() {
 FileChooser chooser = new FileChooser();
 chooser.setTitle("Choose FXML file to load");
 if (getFxmlFileName().isEmpty()) {
 chooser.setInitialDirectory(new File(System.getProperty("user.home")));
 } else {
 chooser.setInitialDirectory(new File(getFxmlFileName()).getParentFile());
 }

 File file = chooser.showOpenDialog(chooseFxmlFileButton.getScene().getWindow());
 if (file != null) {
 setFxmlFileName(file.getAbsolutePath());
 }
 }

 @FXML
 public void onLoadExternalFxml() {
 try {
 Optional<URL> url = FxmlUtils.getFxmlUrl(Paths.get(getFxmlFileName()));
 if (url.isPresent()) {
 Pane pane = FxmlUtils.loadFxmlPane(url.get(), resources);
 externalPane.setCenter(pane);
 } else {
 Alert alert = new Alert(Alert.AlertType.WARNING);
 alert.setContentText(getFxmlFileName() + " could not be found!");
 alert.show();
 }
 } catch (IOException ex) {
 Dialogs.create().showException(ex);
 }
 }
}
Reference: How to allow users to customize the UI from our JCG partner Jens Deters at the JavaFX Delight blog.
Do you want to know how to develop your skillset to become a Java Rockstar?
Subscribe to our newsletter to start Rocking right now!
To get you started we give you our best selling eBooks for FREE!
1. JPA Mini Book
2. JVM Troubleshooting Guide
3. JUnit Tutorial for Unit Testing
4. Java Annotations Tutorial
5. Java Interview Questions
6. Spring Interview Questions
7. Android UI Design
and many more ....
I agree to the Terms and Privacy Policy

Thank you!

We will contact you soon.

Tags
JavaFX
πŸ‘ Photo of Jens Deters
Jens Deters
January 29th, 2015Last Updated: January 29th, 2015
0 130 3 minutes read

Jens Deters

Jens Deters is a Senior Software Developer working in the domain of Aviation Authorities. His main objectives are RIA and Desktop Applications also he loves to play with IoT related stuff.
Subscribe

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Back to top button
Close
wpDiscuz