How to switch stages in JavaFX - javafx

I have a login stage (300 x 250), I want to open another main stage (fullscreen) if the credentials are correct.
I have figured out how to check the login credentials, but how can I close the login stage and open another stage?

If my application is supposed to work in one window I prefer using a GUI manager singleton class, which manages changing windows. Below I provided the complete code of a simple application which uses this mechanism. Let's assume all the files are in one package, called sample.
Main.java - you initialize the JavaFX components here:
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import java.io.IOException;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Main.class.getResource("/sample/root.fxml"));
try{
StackPane rootPane;
rootPane = loader.load();
GuiManager guiModel = GuiManager.getInstance();
guiModel.setRootPane(rootPane);
Scene scene = new Scene(rootPane);
primaryStage.setScene(scene);
primaryStage.show();
guiModel.changeWindow("/sample/firstwindow.fxml");
} catch (IOException exception) {
exception.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
root.fxml - all the windows are supposed to be based on it:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.StackPane?>
<StackPane fx:id="rootPane"
xmlns="http://javafx.com/javafx/8.0.60"
xmlns:fx="http://javafx.com/fxml/1"
prefWidth="1" prefHeight="1"/>
firstwindow.fxml - first actual window which will be displayed:
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.VBox?>
<VBox xmlns:fx="http://javafx.com/fxml" fx:controller="sample.FirstWindowController">
<Label text="First window"/>
<Button text="Change window" onAction="#changeWindow"/>
</VBox>
FirstWindowController.java - a controller class of the first window:
package sample;
import javafx.fxml.FXML;
public class FirstWindowController {
#FXML
private void changeWindow() {
GuiManager.getInstance().changeWindow("/sample/secondwindow.fxml");
}
}
secondwindow.fxml - it will be displayed after clicking the button of the first window:
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.VBox?>
<VBox xmlns:fx="http://javafx.com/fxml" fx:controller="sample.SecondWindowController" >
<Label text="Second window"/>
<Button text="Change window" onAction="#changeWindow"/>
</VBox>
SecondWindowController.java - a controller class of the second window:
package sample;
import javafx.fxml.FXML;
public class SecondWindowController {
#FXML
private void changeWindow() {
GuiManager.getInstance().changeWindow("/sample/firstwindow.fxml");
}
}
GuiManager.java - a class that manages changing windows based on the root:
package sample;
import javafx.collections.ObservableList;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.stage.Window;
import java.io.IOException;
public class GuiManager {
private StackPane rootPane;
private static GuiManager instance;
public static GuiManager getInstance() {
if (instance == null) {
instance = new GuiManager();
}
return instance;
}
private GuiManager() {}
public void changeWindow(String path) {
changeWindow(rootPane, path, this);
rootPane.setPrefWidth(-1);
rootPane.setPrefHeight(-1);
}
public static void changeWindow(Pane pane, String newWindowPath, Object callingController) {
Window window = pane.getScene().getWindow();
double x = window.getX() + getHorizontalMidpoint(window);
double y = window.getY() + getVerticalMidpoint(window);
ObservableList<Node> childrenList = pane.getChildren();
removeAllIncludedChildren(childrenList);
FXMLLoader loader = new FXMLLoader(callingController.getClass().getResource(newWindowPath));
try {
pane.getChildren().add(loader.load());
Stage primaryStage = (Stage) window;
primaryStage.setMinHeight(0);
primaryStage.setMinWidth(0);
window.sizeToScene();
window.setX(x - getHorizontalMidpoint(window));
window.setY(y - getVerticalMidpoint(window));
primaryStage.setMinHeight(window.getHeight());
primaryStage.setMinWidth(window.getWidth());
} catch (IOException exception) {
exception.printStackTrace();
}
}
private static double getHorizontalMidpoint(Window window) {
int horizontalBisectionCoefficient = 2;
return window.getWidth() / horizontalBisectionCoefficient;
}
private static double getVerticalMidpoint(Window window) {
int verticalBisectionCoefficient = 2;
return window.getHeight() / verticalBisectionCoefficient;
}
private static void removeAllIncludedChildren(ObservableList<Node> childrenList) {
for (int childIndex = 0; childIndex < childrenList.size(); childIndex++) {
childrenList.remove(childIndex);
}
}
public void setRootPane(StackPane rootPane) {
this.rootPane = rootPane;
}
}

I just run in the same issue and this answer solved my issue perfectly while being short and clean.
#FXML
private void handleButtonAction(ActionEvent event) {
System.out.println("You clicked me!");
label.setText("Hello World!");
//Here I want to swap the screen!
Stage stageTheEventSourceNodeBelongs = (Stage) ((Node)event.getSource()).getScene().getWindow();
// OR
Stage stageTheLabelBelongs = (Stage) label.getScene().getWindow();
// these two of them return the same stage
// Swap screen
stage.setScene(new Scene(new Pane()));
}
PS.: Remember to click the original answer and upvote it. The guy deserves...
PPS.: I am not sure just copying an answer is okay(instead of just share the link through a comment) but since this doesnt have a correct answer yet i decided to do it for visibility.

Related

how to blend JFXNodeList from the code

I am having a JFXNodeList
<JFXNodesList fx:id="algorithmList" layoutX="285.0" layoutY="215.0" prefHeight="1.0" prefWidth="10.0" />
How can I close (blend the JFXNodeList), from my controller java code, if a user click one button ?
Environment:
JavaFX , Java 8, jfoenix:8.0.3
To close (collapse) JFXNodeList you can use this method:
nodesList.animateList(false);
Complete example:
// src/toumi_jfoenix/Controller.java:
package toumi_jfoenix;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXNodesList;
import javafx.fxml.FXML;
import javafx.scene.control.Tooltip;
public class Controller {
#FXML
public JFXNodesList nodesList;
#FXML
private void initialize() {
JFXButton btnMenu = new JFXButton("Menu");
JFXButton btnOption1 = new JFXButton("Option 1");
JFXButton btnOption2 = new JFXButton("Option 2");
JFXButton btnCollapse = new JFXButton("<<");
btnCollapse.setTooltip(new Tooltip("Collapse menu"));
btnCollapse.setOnAction(e->nodesList.animateList(false));
nodesList.addAnimatedNode(btnMenu);
nodesList.addAnimatedNode(btnOption1);
nodesList.addAnimatedNode(btnOption2);
nodesList.addAnimatedNode(btnCollapse);
}
}
// src/toumi_jfoenix/sample.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.Pane?>
<?import com.jfoenix.controls.JFXNodesList?>
<Pane xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="toumi_jfoenix.Controller">
<JFXNodesList fx:id="nodesList" layoutX="20.0" layoutY="10.0" rotate="-90" spacing="50"/>
</Pane>
// src/toumi_jfoenix/Main.java:
package toumi_jfoenix;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
Scene scene = new Scene(root, 430, 200);
primaryStage.setScene(scene);
primaryStage.show();
}
}

JavaFX: How to drag imageview on a Pane

Can somebody give a simple example about how to set up the EventHandler for dragging imageviews on a Pane(JavaFX). For dragging I mean press the mouse on the image, drag and image should follow, then release the mouse and the imageview will stop at that location.
read docs first Drag and drop in javafx
or you can do it yourself by getMouseX and getMouseY points and change the coordinates of the imageView in AnchorPane ....
I wanted to try out the proposed solution with the drag and drop. I find it to be not optimal.
By doing it with drag and drop you trigger some mechanisms that are unnecessary:
You can drag it outside of your application
Cursor changes ...
I also had problems that the calulation of the position delta seems to be speed dependent
Nether the less, in case someone is interested this is my code:
Main.java
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
FXMLLoader loader = new FXMLLoader(getClass().getResource("sample.fxml"));
Controller controller = new Controller();
loader.setController(controller);
Parent root = (Parent)loader.load();
controller.InitUi();
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root, 300, 275));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Controller.java
package sample;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.input.*;
import javafx.scene.layout.AnchorPane;
import javafx.scene.shape.Rectangle;
public class Controller
{
#FXML
private Rectangle draggable;
private Double lastX = null;
private Double lastY = null;
public void InitUi()
{
if (this.draggable != null)
{
this.draggable.setOnDragOver(new EventHandler<DragEvent>()
{
#Override
public void handle(DragEvent dragEvent)
{
HandleMouseMovement(dragEvent.getSceneX(), dragEvent.getSceneY());
}
});
this.draggable.setOnDragDetected(new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) {
Dragboard db = draggable.startDragAndDrop(TransferMode.ANY);
ClipboardContent content = new ClipboardContent();
content.putString("Does not matter");
db.setContent(content);
event.consume();
lastX = event.getSceneX();
lastY = event.getSceneY();
}
});
}
}
private synchronized void HandleMouseMovement(double sceneX, double sceneY)
{
double deltaX = sceneX - lastX;
double deltaY = sceneY - lastY;
lastX = sceneX;
lastY = sceneY;
double currentXAnchor =AnchorPane.getLeftAnchor(this.draggable);
double currentYAnchor =AnchorPane.getTopAnchor(this.draggable);
AnchorPane.setLeftAnchor( this.draggable, currentXAnchor + deltaX*1.5);
AnchorPane.setTopAnchor(this.draggable, currentYAnchor + deltaY*1.5);
}
}
sample.fxml
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.shape.Rectangle?>
<GridPane xmlns:fx="http://javafx.com/fxml" alignment="center" hgap="10" vgap="10" prefHeight="500" prefWidth="500">
<AnchorPane>
<Rectangle fx:id="draggable" width="40" height="50" AnchorPane.topAnchor="20" AnchorPane.leftAnchor="20"/>
</AnchorPane>
</GridPane>

Trying to set up an "onshowing" ActionEvent in Combobox in javafx

I'm using Scene Builder to build a javafx gui, and I want a ComboBox where something will happen "On Showing." It looks simple enough, but it crashes when I try to implement it. I created a simple version having nothing but a combobox, and it still crashes.
Here is the Main.java module:
package application;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
// BorderPane root = new BorderPane();
BorderPane root = (BorderPane) FXMLLoader.load(Main.class.getResource("Comboscreen.fxml"));
Scene scene = new Scene(root,400,400);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
Here is the fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.VBox?>
<BorderPane xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.Controller">
<center>
<VBox alignment="CENTER" prefHeight="400.0" prefWidth="400.0" BorderPane.alignment="CENTER">
<children>
<ComboBox fx:id="ComboTestBox" onAction="#ComboDo" onShowing="#Showaction" prefWidth="150.0" promptText="Testbox" />
</children>
</VBox>
</center>
</BorderPane>
and here is the Controller:
package application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.ComboBox;
public class Controller {
#FXML
public ComboBox<String> ComboTestBox;
#FXML
void ComboDo(ActionEvent event) {
System.out.println(" Option Chosen");
}
ObservableList<String> options =
FXCollections.observableArrayList(
"Option 1",
"Option 2",
"Option 3"
);
#FXML
void Showaction(ActionEvent event) {
System.out.println(" TestAction");
}
public void initialize() {
ComboTestBox.setItems(options);
}
}
It looks simple enough, but it crashes every time. If I remove the "onshowing" action, it works just fine. Any advice is appreciated, as I am pretty new at this.
Assuming by "crashing" you mean it gives you a runtime exception (for future reference, please include the stack trace, which has lots of information for you to diagnose the problem, in your question):
The onShowing handler is an EventHandler<Event>, not an EventHandler<ActionEvent>, so you need:
#FXML
void Showaction(Event event) {
System.out.println(" TestAction");
}
Note that if you're not using the Event parameter, you can omit it, and the FXMLLoader will still be able to map to the correct handler method:
#FXML
void Showaction() {
System.out.println(" TestAction");
}
However, if you include the parameter, it must be of the correct type.
As an aside, you should use proper naming conventions, i.e.
#FXML
void showAction(Event event) {
System.out.println(" TestAction");
}
with the corresponding change to your FXML file.

Load fxml as background process - Javafx

My initial fxml(say home.fxml) has a lot of functionalities, hence it takes a lot of time to load completely. So to avoid the time gap between program start and fxml loading I introduced one more fxml(say loader.fxml) with a gif image which should appear while the main fxml is loading.
The problem is the gif image in my loader.fxml is not moving as in the program is hanging until the home.fxml is loaded completely.
To avoid this I moved the home.fxml loading into a thread as shown in below code.
public class UATReportGeneration extends Application {
private static Stage mainStage;
#Override
public void start(Stage stage) {
Parent loaderRoot = null;
try {
loaderRoot = FXMLLoader.load(getClass().getResource("/uatreportgeneration/fxml/Loader.fxml"));
} catch (IOException ex) {
Logger.getLogger(UATReportGeneration.class.getName()).log(Level.SEVERE, null, ex);
}
Scene loadScene = new Scene(loaderRoot);
stage.setScene(loadScene);
stage.initStyle(StageStyle.UNDECORATED);
stage.getIcons().add(new Image(this.getClass().getResourceAsStream("/uatreportgeneration/Images/logo.png")));
stage.show();
mainStage = new Stage(StageStyle.UNDECORATED);
mainStage.setTitle("Upgrade Analysis");
mainStage.getIcons().add(new Image(this.getClass().getResourceAsStream("/uatreportgeneration/Images/logo.png")));
setStage(mainStage);
new Thread(() -> {
Platform.runLater(() -> {
try {
FXMLLoader loader = new FXMLLoader();
Parent root = loader.load(getClass().getResource("/uatreportgeneration/fxml/Home.fxml"));
Scene scene = new Scene(root);
mainStage.setScene(scene);
mainStage.show();
stage.hide();
System.out.println("Stage showing");
// Get current screen of the stage
ObservableList<Screen> screens = Screen.getScreensForRectangle(new Rectangle2D(mainStage.getX(), mainStage.getY(), mainStage.getWidth(), mainStage.getHeight()));
// Change stage properties
Rectangle2D bounds = screens.get(0).getVisualBounds();
mainStage.setX(bounds.getMinX());
mainStage.setY(bounds.getMinY());
mainStage.setWidth(bounds.getWidth());
mainStage.setHeight(bounds.getHeight());
System.out.println("thread complete");
} catch (IOException ex) {
Logger.getLogger(UATReportGeneration.class.getName()).log(Level.SEVERE, null, ex);
}
});
}).start();
}
public static Stage getStage() {
return mainStage;
}
public static void setStage(Stage stage) {
mainStage = stage;
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
But after this code also my program is hanging(The gif image is not moving). If I load the fxml outside the Platform.runLater(), I get the exception Not on FX Thread.
I also tired using Task() but from that the gif image is moving but the fxml is not loading in the background, if I try to load the fxml outside Platform.runLater().
Can anyone please help me and tell me how can I correct the code so that my fxml loads in the background without disturbing the foreground process.
Use a Task. You need to arrange to create the scene and update the stage on the FX Application Thread. The cleanest way is to use a Task<Parent>:
Task<Parent> loadTask = new Task<Parent>() {
#Override
public Parent call() throws IOException {
FXMLLoader loader = new FXMLLoader();
Parent root = loader.load(getClass().getResource("/uatreportgeneration/fxml/Home.fxml"));
return root ;
}
};
loadTask.setOnSucceeded(e -> {
Scene scene = new Scene(loadTask.getValue());
mainStage.setScene(scene);
mainStage.show();
stage.hide();
System.out.println("Stage showing");
// Get current screen of the stage
ObservableList<Screen> screens = Screen.getScreensForRectangle(new Rectangle2D(mainStage.getX(), mainStage.getY(), mainStage.getWidth(), mainStage.getHeight()));
// Change stage properties
Rectangle2D bounds = screens.get(0).getVisualBounds();
mainStage.setX(bounds.getMinX());
mainStage.setY(bounds.getMinY());
mainStage.setWidth(bounds.getWidth());
mainStage.setHeight(bounds.getHeight());
System.out.println("thread complete");
});
loadTask.setOnFailed(e -> loadTask.getException().printStackTrace());
Thread thread = new Thread(loadTask);
thread.start();
Here is a SSCCE using this technique:
main.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.VBox?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TextField?>
<VBox spacing="10" xmlns:fx="http://javafx.com/fxml/1" fx:controller="MainController">
<padding>
<Insets top="24" left="24" right="24" bottom="24"/>
</padding>
<TextField />
<Button fx:id="button" text="Show Window" onAction="#showWindow"/>
</VBox>
MainController (uses the Task approach shown above):
import java.io.IOException;
import javafx.concurrent.Task;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.stage.Stage;
public class MainController {
#FXML
private Button button ;
#FXML
private void showWindow() {
Task<Parent> loadTask = new Task<Parent>() {
#Override
public Parent call() throws IOException, InterruptedException {
// simulate long-loading process:
Thread.sleep(5000);
FXMLLoader loader = new FXMLLoader(getClass().getResource("test.fxml"));
Parent root = loader.load();
return root ;
}
};
loadTask.setOnSucceeded(e -> {
Scene scene = new Scene(loadTask.getValue());
Stage stage = new Stage();
stage.initOwner(button.getScene().getWindow());
stage.setScene(scene);
stage.show();
});
loadTask.setOnFailed(e -> loadTask.getException().printStackTrace());
Thread thread = new Thread(loadTask);
thread.start();
}
}
test.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Button?>
<?import javafx.geometry.Insets?>
<BorderPane xmlns:fx="http://javafx.com/fxml/1" fx:controller="TestController">
<padding>
<Insets top="24" left="24" right="24" bottom="24"/>
</padding>
<center>
<Label fx:id="label" text="This is a new window"/>
</center>
<bottom>
<Button text="OK" onAction="#closeWindow" BorderPane.alignment="CENTER">
<BorderPane.margin>
<Insets top="5" bottom="5" left="5" right="5"/>
</BorderPane.margin>
</Button>
</bottom>
</BorderPane>
TestController:
import javafx.fxml.FXML;
import javafx.scene.control.Label;
public class TestController {
#FXML
private Label label ;
#FXML
private void closeWindow() {
label.getScene().getWindow().hide();
}
}
Main application:
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws IOException {
primaryStage.setScene(new Scene(FXMLLoader.load(getClass().getResource("main.fxml"))));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Notice that after pressing the button, you can still type in the text field during the five seconds it takes to "load" the FXML, so the UI is remaining responsive.
your approach using Task was already correct. you were just missing a bit more: you were just missing another Platform#invokeLater() to update the UI:
new Thread(new Task() {
#Override
protected Object call() throws Exception {
// Simulating long loading
Thread.sleep(5000);
FXMLLoader loader = new FXMLLoader(getClass().getResource("home.fxml"));
Parent root = loader.load();
Scene scene = new Scene(root);
// Updating the UI requires another Platform.runLater()
Platform.runLater(new Runnable() {
#Override
public void run() {
mainStage.setScene(scene);
mainStage.show();
stage.hide();
System.out.println("Stage showing");
// Get current screen of the stage
ObservableList<Screen> screens = Screen.getScreensForRectangle(new Rectangle2D(mainStage.getX(), mainStage.getY(), mainStage.getWidth(), mainStage.getHeight()));
// Change stage properties
Rectangle2D bounds = screens.get(0).getVisualBounds();
mainStage.setX(bounds.getMinX());
mainStage.setY(bounds.getMinY());
mainStage.setWidth(bounds.getWidth());
mainStage.setHeight(bounds.getHeight());
System.out.println("thread complete");
}
});
return null;
}
}).start();
In addition to #James_D answer. As mentioned by him, Stages and Scene should not be added in background thread, they should be added only in FX main thread.
I have added tooltips in my home.fxml, which is nothing but a PopupWindow. Therefore to the background thread, it appeared as a new stage. Hence it threw IllegalStateException. After removing the tooltips from the fxml, the fxml was able to load as a background process as there were no stages created in that thread.

Javafx 8, scenebuilder 2, and controlsfx with fontawesome?

I'm relatively new to javafx, and have recently started a project using java 8 and javafx. I am using Scenebuilder 2.0 to build my javafx ui. I was wondering if anyone have managed to use fontawesome in scenebuilder? Currently I need to do this to add graphics to a label
levelLabel1.setGraphic(create(FontAwesome.Glyph.CHEVRON_RIGHT));
public static Node create(Glyph glyph) {
FontAwesome fontAwesome = new FontAwesome();
fontAwesome.fontColor(color);
Node result = fontAwesome.create(glyph.getChar());
result.setScaleX(SCALE);
result.setScaleY(SCALE);
return result;
}
You can use FontAwesomeFX 8.1, that have a simply way to do this.
With ControlsFx you need edit fxml file. (more info)
<?import org.controlsfx.glyphfont.*?>
//...
<Label>
<graphic>
<Glyph fontFamily="FontAwesome" icon="PLUS" />
</graphic>
</Label>
//...
You will have to create a custom component for it.
Then you will be able to load it there (but still not able to see the Glyph there) and will be able to set the glyphs easier:
Code available on gist
Main.java
import org.controlsfx.glyphfont.FontAwesome;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
FALabel label = new FALabel();
label.setGlyph(FontAwesome.Glyph.ANDROID);
label.setValue("RoBOZUKU");
Pane p = new Pane();
p.getChildren().add(label);
Scene scene = new Scene(p);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
FALabel.java
import org.controlsfx.glyphfont.FontAwesome;
import org.controlsfx.glyphfont.FontAwesome.Glyph;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.paint.Color;
public class FALabel extends Label{
private Color color;
private Glyph glyph;
public void setValue(String text){
this.setText(text);
this.setGraphic(create(getGlyph()));
}
public FALabel() {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("FALabel.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (Exception exception) {
throw new RuntimeException(exception);
}
}
public Node create(Glyph glyph) {
FontAwesome fontAwesome = new FontAwesome();
fontAwesome.fontColor(getColor());
Node result = fontAwesome.create(glyph.getChar());
result.setScaleX(this.getScaleX());
result.setScaleY(this.getScaleY());
return result;
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
public Glyph getGlyph() {
return glyph;
}
public void setGlyph(Glyph fontAwesome) {
this.glyph = fontAwesome;
}
}
FALabel.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<fx:root type="javafx.scene.control.Label" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"/>
PS: I know this probably wasn't exactly what you are looking for, but scene builder is still very limited.
PS2: You can also create a custom component using the Font Awesome Icons and implementing then in a Pane ( AnchorPane, Pane, HBox) with a ImageView and a Label.

Resources