Add a custom component in JavaFX - java

I would like to add a custom element into a VBox.
For example: being able to write VBox.getChildren().add(element) and element is a custom node created by me in FXML.
I already followed this tutorial: https://docs.oracle.com/javafx/2/fxml_get_started/custom_control.htm
but the example only shows how to do this inside the same controller (a single controller, i already have my "big" controller, which is WinnerController, I would like to split the two classes, one that manages the single element, and one that manages the whole scene Winner.fxml).
I already have a class WinnerController which is the controller of my FXML Winner.fxml.
Here the code of my Winner.fxml:
<AnchorPane id="paneWinner" fx:id="paneWinner" prefHeight="800.0" prefWidth="1280.0" stylesheets="#winner.css" xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="client.gui.WinnerController">
<children>
<VBox layoutX="434.0" layoutY="125.0" prefHeight="250.0" prefWidth="413.0" spacing="10.0">
<children>
<AnchorPane id="leaderBoardElement" prefHeight="80.0" prefWidth="413.0" stylesheets="#leaderBoard.css">
<children>
<Text layoutX="49.0" layoutY="45.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Text" wrappingWidth="107.13671875" />
</children></AnchorPane>
</children>
</VBox>
I would like to dynamically add element with the id "leaderBoardElement" (so an AnchorPane + Text) into my VBox.
How can i do that?
Edit: I also tried with this solution:How to understand and use `<fx:root>` , in JavaFX?
but i keep getting nothing. When i do vbox.getChildren().add(new MyComponent());
called in my WinnerControlleri get nothing.
WinnerController class:
public class WinnerController implements Initializable {
#FXML
private VBox leaderBoard;
#FXML
public void initialize(URL location, ResourceBundle resources) {
System.out.println("Winner Init");
MyComponent test = new MyComponent();
System.out.println(test);
// leaderBoard.getChildren().add(new MyComponent());
}
}
My Component class:
public class MyComponent extends AnchorPane {
#FXML
private TextField textField ;
#FXML
private Button button ;
public MyComponent() {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("MyComponent.fxml"));
loader.setController(this);
loader.setRoot(this);
loader.load();
textField.setText("HELLO!");
} catch (IOException exc) {
// handle exception
System.out.println("ELEMENT NOT CREATE!!!");
}
}
}
Winner.fxml:
<AnchorPane id="paneWinner" fx:id="paneWinner" prefHeight="800.0"
prefWidth="1280.0" stylesheets="#winner.css" xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="client.gui.WinnerController">
<children>
<VBox fx:id="leaderBoard" layoutX="434.0" layoutY="125.0" prefHeight="250.0" prefWidth="413.0" spacing="10.0" />
MyComponent.fxml:
<fx:root type="javafx.scene.layout.AnchorPane" fx:id="leaderBoardElement" id="leaderBoardElement">
<TextField fx:id="textField" />
<Button fx:id="button" />
And i call the creation and loading of Winner.fxml from another class like this:
FXMLLoader loader = new FXMLLoader(getClass().getResource("/Winner.fxml"));
if (loader!=null)
System.out.println("LOADER NOT NULL!!");
try{
System.out.println("TRY!");
Parent root = (Parent) loader.load();
if(root!=null)
System.out.println("ROOT NOT NULL!!");
Scene startedGame = new Scene(root, 1280, 800, Color.WHITE);
if(startedGame!=null)
System.out.println("SCENE NOT NULL!");
Stage window = (Stage) paneCarta0.getScene().getWindow();
if (window!=null)
System.out.println("WINDOW NOT NULL!!");
window.setScene(startedGame);
window.show();
catch (IOException Exception) {
System.out.println("View not found. Error while loading");
}
The problem is inside the new MyComponent(), where probably i get an exception and it propagates to my main caller. I've tried everything but i can't figure out why it can't create the MyComponent object.

If your custom component is in a separate FXML file you can do this.
In your WinnerController class:
#FXML
private void initialize() throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getRessource("customElement.fxml"));
fxmlLoader.setController(new CustomElementController()); //Or just specify the Controller in the FXML file
myVBox.getChildren().add(fxmlLoader.load());
}
Edit: In this solution there should be NO <fx:include> tags in your main fxml

Related

JavaFX text won't appear in TextField or TextArea

I have a program that uses one form to add and display an object. I can use the form to add an object fine but when I try to display the same object in the form after this, no text will appear. The object is definitely added correctly and I can print out all of the elements so nothing is null. I think the error is with my .setText() line. I have created a smaller version of the program that just tries to display text:
public class TestApp extends Application {
private Stage primaryStage;
#FXML public TextField txtField;
#FXML public TextArea txtArea;
#FXML public Button btnTest;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
this.primaryStage = primaryStage;
this.primaryStage.setTitle("Change Solutions");
showWelcome();
}
public void showWelcome(){
try{
AnchorPane page = FXMLLoader.load(TestApp.class.getResource("testFXML.fxml"));
page.setStyle("-fx-background: #FFFFFF;");
Scene scene = new Scene(page);
primaryStage.setScene(scene);
primaryStage.setTitle("Welcome to Change Solutions");
primaryStage.show();
}catch (IOException i)
{
Logger.getLogger(TestApp.class.getName()).log(Level.SEVERE, null, i);
}
}
public void addText(){
txtArea.setText("test");
txtField.setText("test");
showWelcome();
}
public void handleButton(ActionEvent actionEvent) {
addText();
}
}
FXML:
<AnchorPane prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.112" xmlns:fx="http://javafx.com/fxml/1" fx:controller="testpack.TestApp">
<children>
<AnchorPane layoutX="76.0" layoutY="70.0" prefHeight="243.0" prefWidth="309.0">
<children>
<TextField fx:id="txtField" layoutX="45.0" layoutY="40.0" promptText="TextField" AnchorPane.leftAnchor="45.0" AnchorPane.topAnchor="40.0" />
<TextArea fx:id="txtArea" layoutX="45.0" layoutY="81.0" prefHeight="138.0" prefWidth="149.0" promptText="TextArea" AnchorPane.leftAnchor="45.0" AnchorPane.topAnchor="81.0" />
<Button fx:id="btnTest" layoutX="217.0" layoutY="109.0" mnemonicParsing="false" onAction="#handleButton" text="Button" AnchorPane.bottomAnchor="109.0" AnchorPane.rightAnchor="40.0" />
</children>
</AnchorPane>
</children>
</AnchorPane>
The code, both here and in the actual program, compiles without errors.
I have see versions of this question before but none of the solutions work for me so I thought I would start a new thread.

How to obtain data from a database and put it inside fxml?

I'm making some kind of information application about a city which I need to use a database for, I got my database set up and ready and most of the code needed as well; the only part is to extract the data I need from my SQL server into a BarChart in fxml. Can anyone give me a example or something?
My fxml:
<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="1000.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Controllers.ControllerZW">
<BarChart fx:id="graph" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<xAxis>
<CategoryAxis side="BOTTOM" />
</xAxis>
<yAxis>
<NumberAxis side="LEFT" />
</yAxis>
</BarChart>
</Pane>
My controller atm:
package Controllers;
public class ControllerZW implements Interface.Ibacktomenu {
#Override
public void backtomenu() {
try {
Main.mainStage.setScene(
new Scene(FXMLLoader.load(getClass().getResource("../scenes/MainMenu.fxml")))
);
} catch (IOException e) {
System.out.println("Probably couldnt find resource file");
e.printStackTrace();
}
}
}
Do you want to render the data form database to XML format?
I think some template engine maybe help you, such as Freemarker.
You could use Freemarker as view of Spring MVC, please refer to http://viralpatel.net/blogs/spring-mvc-freemarker-ftl-example/
Use a Task to get the data from the database and any method described in Passing Parameters JavaFX FXML to get the data to the controller, e.g.
#Override
public void start(Stage primaryStage) {
Task<Pane> dataLoader = new Task<Pane>() {
#Override
protected Pane call() throws Exception {
// create data
XYChart.Series<String, Double> rain = new XYChart.Series<>();
rain.setName("rain");
Month[] months = Month.values();
for (Month month : months) {
// simulates slow database connection; just adding some random values here
Thread.sleep(200);
rain.getData().add(new XYChart.Data<>(month.toString(), Math.random() * 100));
}
// load chart (replace BarChartLoad.class.getResource("chart.fxml") with your own URL)
FXMLLoader loader = new FXMLLoader(BarChartLoad.class.getResource("chart.fxml"));
Pane pane = loader.load();
// pass data to controller
loader.<ControllerZW>getController().setData(FXCollections.observableArrayList(rain));
return pane;
}
};
// placeholder
Pane root = new Pane();
Scene scene = new Scene(root, 1000, 600);
// set new scene root on successfull completion of the task
dataLoader.setOnSucceeded(evt -> scene.setRoot(dataLoader.getValue()));
// TODO: handle task failure
new Thread(dataLoader).start();
primaryStage.setScene(scene);
primaryStage.show();
}
public class ControllerZW implements Interface.Ibacktomenu {
#FXML
private BarChart<String, Double> graph;
public void setData(ObservableList<XYChart.Series<String, Double>> data) {
graph.setData(data);
}
...

JavaFX initialize() is not called on inner custom component

I am using javaFX and I need to put custom components to my scene. Therefore I have "main_pane.fxml" with grid pane containing my components (for example DocumentModule).
main_pane.fxml
<GridPane xmlns:fx="http://javafx.com/fxml" fx:controller="GUI.MainPane" gridLinesVisible="true" >
<padding>
<Insets bottom="0" top="0" left="0" right="0" />
</padding>
.
.
.
<DocumentModule fx:id="documentModule"
minWidth="200" minHeight="400"
GridPane.columnIndex="0" GridPane.rowIndex="1">
.
.
.
</DocumentModule>
.
.
.
Each of them is defined in separate fxml file.
document_module.fxml
<GridPane xmlns:fx="http://javafx.com/fxml" fx:controller="GUI.DocumentModule" >
<padding>
<Insets bottom="0" top="0" left="0" right="0" />
</padding>
<ToolBar fx:id="toolBar" GridPane.rowIndex = "0" GridPane.columnIndex = "0" orientation="HORIZONTAL" >
.
.
.
</ToolBar>
<ScrollPane fx:id="scrollPane" hbarPolicy="AS_NEEDED" vbarPolicy="AS_NEEDED" GridPane.rowIndex = "1" GridPane.columnIndex = "0">
<DocumentView fx:id="documentView"/>
</ScrollPane>
</GridPane>
Problem is that DocumentModule is not initialized after construction. It's constructor is called but not it's initialize(URL location, ResourceBundle resources) method. Therefore objects from fxml are not injected.
Controller code for document module
public class DocumentModule extends GridPane implements Initializable {
protected Document document;
#FXML
private DocumentView documentView;
#FXML
private ScrollPane scrollPane;
.
.
.
public DocumentModule() {
System.out.println("Document Module constructed.");
//this is called correctly
}
#Override
public void initialize(URL location, ResourceBundle resources) {
System.out.println("Document Module initialized.");
//This is not called at all.
}
}
For MainPane everything works fine but not for any of inner components.
The component tree seems to be constructed correctly, just the inner components are not initialized. Also the inner components are not dispalyed in application scene (if I load their fxml directly they work, if I use fx:include they are just displayed).
MainPane controller
public final class MainPane extends GridPane implements Initializable {
#FXML
private DocumentModule documentModule;
#FXML
private EditModule editModule;
public MainPane() {
System.out.println("Main Pane constructed.");
}
#Override
public void initialize(URL location, ResourceBundle resources) {
System.out.println("Main Pane initialized.");
}
}
Application entry class' start method
#Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("main_pane.fxml"));
GridPane root = fxmlLoader.load();
Scene scene = new Scene(root, 800, 600);
primaryStage.setMaximized(true);
primaryStage.setMinWidth(800);
primaryStage.setMinHeight(600);
primaryStage.setTitle("App");
primaryStage.setScene(scene);
primaryStage.show();
}
I haven't find any topic/page/blog with same problem. Few of them had similar symptoms, but no of solutins helped me. Does anyone have idea why initialize is not called on inner components?
Thanks!
Tom
Nowhere in your code do you actually load document_module.fxml, so the elements defined there will never be created. The initialize() method is called on the controller for an fxml file when the FXMLLoader loads that file, but since you never load the fxml file, the initialize() method is never called.
The element <DocumentModule> in your main FXML merely causes the DocumentModule class to be instantiated (via a call to its no-arg constructor), but there is no link from there to the fxml file.
It looks like you are trying to follow the FXML custom component pattern. To do so, you need to load the FXML file in the custom component constructor. Specify a dynamic root and do not specify the controller class in the fxml, and set both on the FXMLLoader before you call load:
document_module.fxml:
<fx:root type="GridPane" xmlns:fx="http://javafx.com/fxml">
<padding>
<Insets bottom="0" top="0" left="0" right="0" />
</padding>
<ToolBar fx:id="toolBar" GridPane.rowIndex = "0" GridPane.columnIndex = "0" orientation="HORIZONTAL" >
.
.
.
</ToolBar>
<ScrollPane fx:id="scrollPane" hbarPolicy="AS_NEEDED" vbarPolicy="AS_NEEDED" GridPane.rowIndex = "1" GridPane.columnIndex = "0">
<DocumentView fx:id="documentView"/>
</ScrollPane>
</fx:root>
DocumentModule.java:
public class DocumentModule extends GridPane implements Initializable {
protected Document document;
#FXML
private DocumentView documentView;
#FXML
private ScrollPane scrollPane;
.
.
.
public DocumentModule() {
System.out.println("Document Module constructed.");
FXMLLoader loader = new FXMLLoader(getClass().getResource("document_module.fxml"));
loader.setRoot(this);
loader.setController(this);
try {
loader.load();
} catch (IOException exc) {
exc.printStackTrace();
// this is pretty much fatal, so:
System.exit(1);
}
}
#Override
public void initialize(URL location, ResourceBundle resources) {
System.out.println("Document Module initialized.");
// This will now be called after the #FXML-annotated fields are initialized.
}
}

Simple Javafx TreeView throws Nullpointer Exception

I've got the following classes:
Main:
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
BorderPane root = FXMLLoader.load(getClass().getResource("../view/PersonOverview.fxml"));
AnchorPane view2 = FXMLLoader.load(getClass().getResource("../view/view2.fxml"));
root.setLeft(view2);
primaryStage.setScene(new Scene(root, 1000, 600));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
TreeController:
public class TreeController implements Initializable {
//Set icon for folder
Node folderIcon = new ImageView(new Image(this.getClass().getResourceAsStream("../icon/icon.jpg")));
//Set root
TreeItem<String> root;
#FXML TreeView<String> tree;
//Set other Items
private TreeItem<String> item1 = new TreeItem<String>("item1", folderIcon);
private TreeItem<String> item2 = new TreeItem<String>("item2", folderIcon);
private TreeItem<String> item3 = new TreeItem<String>("item3", folderIcon);
private TreeItem<String> item4 = new TreeItem<String>("item4", folderIcon);
private TreeItem<String> item5 = new TreeItem<String>("item5", folderIcon);
//Add Children to root
private void makeChildren() {
root.getChildren().add(item1);
root.getChildren().add(item2);
root.getChildren().add(item3);
root.getChildren().add(item4);
root.getChildren().add(item5);
}
#Override
public void initialize(URL location, ResourceBundle resources) {
root = new TreeItem<String>("root", folderIcon);
makeChildren();
root.setExpanded(true);
tree.setRoot(root);
}
}
And of course my view2 fxml file:
<AnchorPane
maxHeight="-Infinity" maxWidth="-Infinity"
minHeight="-Infinity" minWidth="-Infinity"
prefHeight="400.0" prefWidth="354.0"
xmlns="http://javafx.com/javafx/8.0.40"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="control.TreeController">
<children>
<TreeView
layoutX="69.0" layoutY="118.0"
prefHeight="400.0" prefWidth="354.0"
AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0"
AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
</children>
</AnchorPane>
Now the problem I have is that it will throw a Nullpointer Exception at tree.setRoot(root);
And a ConstructLoad Exception in my Main at:
AnchorPane view2 = FXMLLoader.load(getClass().getResource("../view/view2.fxml"));
I'm still learning this stuff but I was told that when using FXML, you don't need to initialize TreeViews using "new" as the #FXML annotation will already take care of this with tree.setRoot(root).
Sorry for such a noobish question but I've been googling for the past 2 hours and haven't gotten any wiser.
I'm still learning this stuff but I was told that when using FXML, you don't need to initialize TreeViews using "new" as the #FXML annotation will already take care of this with tree.setRoot(root).
You guessed right, but in order for JavaFX to inject your Treeview (= make the "new" for you) you need to declare something like:
<Treeview fx:id="tree" />
in view2.fxml.
With the fx:id attribute setted to the same name as your Treeview variable in Java code.

why Javafx standalone application accepting double click?

Here is my Main java file.The probelm is that the Whole project is working on double click when i launch it.
public Stage primaryStage;
public BorderPane rootLayout;
private Pane splashLayout;
private ProgressBar loadProgress;
private Label progressText;
private static final int SPLASH_WIDTH = 600;
private static final int SPLASH_HEIGHT = 400;
public static void main(String[] args) throws Exception {
launch(args);
}
#Override
public void start(final Stage initStage) throws Exception {
//this.primaryStage = primaryStage;
FXMLLoader fxmlLoader1 = new FXMLLoader(getClass().getResource(
"KDAF_Splash.fxml"));
try {
// flag = false;
Parent root2 = fxmlLoader1.load();
Stage stage2 = new Stage();
stage2.initStyle(StageStyle.TRANSPARENT);
// masterpane = new Pane();
// masterpane.setOpacity(1);
// stage2.setTitle("Create New Project");
stage2.setScene(new Scene(root2, 600, 400));
stage2.show();
PauseTransition delay = new PauseTransition(Duration.seconds(5));
delay.setOnFinished( event ->{ stage2.close();showMainStage();} );
delay.play();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
};
private void showMainStage(
) {
try {
// Load root layout from fxml file.
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Preloader.class.getResource("RootLayout.fxml"));
rootLayout = (BorderPane) loader.load();
Stage stage=new Stage();
stage.setTitle("Activation");
Scene scene = new Scene(rootLayout);
//stage.initStyle(StageStyle.DECORATED);
stage.setScene(scene);
stage.initStyle(StageStyle.UNDECORATED);
stage.show();
showPersonOverview();
//mainStage.show();
/* mainStage.setTitle("Activation Wizard");
// Show the scene containing the root layout.
Scene scene = new Scene(rootLayout);
// primaryStage.initStyle(StageStyle.UTILITY);
mainStage.setResizable(false);
mainStage.initStyle(StageStyle.UNDECORATED);
mainStage.setScene(scene);
mainStage.show();
showPersonOverview();*/
} catch (IOException e) {
e.printStackTrace();
}
}
public void showPersonOverview() {
try {
// Load person overview.
FXMLLoader loader = new FXMLLoader();
loader.setLocation(MainApp.class.getResource("activation wizard.fxml"));
AnchorPane personOverview = (AnchorPane) loader.load();
personOverview.setPrefHeight(400);
// Set person overview into the center of root layout.
rootLayout.setCenter(personOverview);
} catch (IOException e) {
e.printStackTrace();
}
}
private void showSplash(
final Stage initStage,
Task<?> task,
InitCompletionHandler initCompletionHandler
) {
progressText.textProperty().bind(task.messageProperty());
loadProgress.progressProperty().bind(task.progressProperty());
task.stateProperty().addListener((observableValue, oldState, newState) -> {
if (newState == Worker.State.SUCCEEDED) {
loadProgress.progressProperty().unbind();
loadProgress.setProgress(1);
initStage.toFront();
FadeTransition fadeSplash = new FadeTransition(Duration.seconds(1.2), splashLayout);
fadeSplash.setFromValue(1.0);
fadeSplash.setToValue(0.0);
fadeSplash.setOnFinished(actionEvent -> initStage.hide());
fadeSplash.play();
initCompletionHandler.complete();
} // todo add code to gracefully handle other task states.
});
Scene splashScene = new Scene(splashLayout);
initStage.initStyle(StageStyle.UNDECORATED);
final Rectangle2D bounds = Screen.getPrimary().getBounds();
initStage.setScene(splashScene);
initStage.setX(bounds.getMinX() + bounds.getWidth() / 2 - SPLASH_WIDTH / 2);
initStage.setY(bounds.getMinY() + bounds.getHeight() / 2 - SPLASH_HEIGHT / 2);
initStage.show();
}
public interface InitCompletionHandler {
public void complete();
}
}
The FXml is given below. Please help me to resolve this issue. If the question is not clear help me to explain better. The main problem is when the application is launched after splash screen. The button accepts double click and then moves to load next FXML. this is been very painful as i have to double click everytime instead of single click. I am not able to identify the problem here. Whether it is a problem that persists from scene builder or the problem is in the main preloader class.Even the menu item is accepting double click. I try to google the solution for but could not find any solution. please look int the code and help to resolve this issue. I have done a lot of R&D but all went vain . There might be a little problem in it but i am not being able to identify it. Please ignore the formatting of code and unused variables. The code is not final yet. finally i would like to remind the main problem is that after launching, the application is working only on double click. lets look at the work flow to understand it better. SPLASH SCREEN->ACTIVATION WIZARD-DOUBLE CLICK ON A BUTTON->TIP SCREEN-DOUBLE CLICK ON A BUTTON->PROJECT SCREEN->DOUBLE CLICK TO OPEN ANYTHING. It is really frustrating. please help.
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.text.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.image.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" style="-fx-border-color: black;" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="EventHandlingController">
<children>
<Button layoutX="301.0" layoutY="333.0" mnemonicParsing="false" text="Buy Full Version" />
<Button fx:id="myButton7" layoutX="420.0" layoutY="333.0" mnemonicParsing="false" onAction="#Showtip" prefHeight="25.0" prefWidth="114.0" text="Continue Trial " />
<TextField editable="false" layoutX="85.0" layoutY="108.0" prefHeight="151.0" prefWidth="449.0" style="-fx-background-color: silver;" text="You have <xx> days left on your trial.">
<font>
<Font size="21.0" />
</font>
</TextField>
<Label layoutX="85.0" layoutY="23.0" prefHeight="37.0" prefWidth="135.0" text="Activation Wizard">
<font>
<Font name="System Bold" size="15.0" />
</font>
</Label>
<Button fx:id="closebutt" layoutX="573.0" layoutY="2.0" mnemonicParsing="false" onAction="#closebuttonD" prefHeight="15.0" prefWidth="20.0" text="X" />
</children>
</AnchorPane>

Categories