javafx 8 - table pagination issue stack overflow - spring-boot

This is the layout I want to make
This is fxml file: category.main.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Pagination?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.control.TitledPane?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.VBox?>
<AnchorPane prefHeight="381.0" prefWidth="899.0" styleClass="background-white" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.ciro.hm.controller.CategoryMainController">
<children>
<VBox prefHeight="400.0" prefWidth="573.0" style="-fx-min-width: 80%;" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="5.0" AnchorPane.rightAnchor="321.0" AnchorPane.topAnchor="10.0">
<children>
<BorderPane>
<center>
<TableView fx:id="table" prefHeight="323.0" prefWidth="573.0">
<columns>
<TableColumn fx:id="colId" editable="false" minWidth="30.0" prefWidth="75.0" resizable="false" styleClass="table-cell" text="%tbl.id" />
<TableColumn fx:id="colName" editable="false" prefWidth="253.0" resizable="false" styleClass="table-cell" text="%tbl.name" />
<TableColumn fx:id="colInOut" editable="false" minWidth="0.0" prefWidth="155.0" styleClass="table-cell" text="%tbl.in.out" />
<TableColumn fx:id="colBtn" editable="false" minWidth="0.0" prefWidth="90.0" resizable="false" sortable="false" styleClass="table-cell" text="#" />
</columns>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
</TableView>
</center>
</BorderPane>
<Pagination fx:id="pagination" prefHeight="51.0" prefWidth="573.0" />
</children>
</VBox>
<VBox layoutX="448.0" maxWidth="203.0" minWidth="-Infinity" prefHeight="400.0" prefWidth="300.0" AnchorPane.rightAnchor="7.0" AnchorPane.topAnchor="10.0">
<children>
<TitledPane animated="false" collapsible="false" prefHeight="264.0" prefWidth="400.0" text="%app.pane.category">
<content>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="230.0" prefWidth="201.0">
<children>
<Button fx:id="btnSave" layoutX="17.0" layoutY="151.0" mnemonicParsing="false" text="%app.lbl.save" AnchorPane.leftAnchor="0.0" />
<Label layoutX="14.0" layoutY="14.0" text="%app.lbl.name" AnchorPane.leftAnchor="0.0" />
<ComboBox fx:id="fldInOut" layoutX="17.0" layoutY="101.0" prefWidth="150.0" promptText="%app.generic.selection" AnchorPane.leftAnchor="0.0" />
<Label layoutX="71.0" layoutY="80.0" text="%app.lbl.in.out" AnchorPane.leftAnchor="0.0" />
<TextField fx:id="fldName" layoutX="14.0" layoutY="35.0" AnchorPane.leftAnchor="0.0" />
</children>
</AnchorPane>
</content>
</TitledPane>
</children>
</VBox>
</children>
</AnchorPane>
This is controller
package com.ciro.hm.controller;
import com.ciro.hm.model.Category;
import com.ciro.hm.service.CategoryService;
import com.ciro.hm.to.CategoryTO;
import de.jensd.fx.glyphs.GlyphsDude;
import de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.util.Callback;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.net.URL;
import java.util.List;
import java.util.ResourceBundle;
#Component
#Slf4j
public class CategoryMainController extends BaseController implements Initializable {
ObservableList<Category> data;
#FXML
BorderPane mainBorder;
#Value("${app.hm.in-out-value}")
List<String> inOut;
#FXML
TableView<Category> table;
#FXML
TextField fldName;
#FXML
ComboBox<String> fldInOut;
#FXML
TableColumn<Category, Integer> colId;
#FXML
TableColumn<Category, String> colName;
#FXML
TableColumn<Category, String> colInOut;
#FXML
TableColumn<Category, String> colBtn;
private CategoryService categoryService;
#Autowired
public CategoryMainController(CategoryService categoryService){
this.categoryService = categoryService;
}
#Override
public void initialize(URL location, ResourceBundle resources) {
super.initialize(location, resources);
data = categoryService.findAll();
fldInOut.getItems().removeAll();
fldInOut.getItems().addAll(inOut);
btnSave.setOnAction(this::save);
pagination.setCurrentPageIndex(0);
pagination.setPageCount(getPageSize(data));
pagination.setPageFactory(this::createPage);
table.setItems(FXCollections.observableArrayList(data.subList(0, paginationSize)));
colId.setCellValueFactory(new PropertyValueFactory<>("idCategory"));
colName.setCellValueFactory(new PropertyValueFactory<>("name"));
colInOut.setCellValueFactory(new PropertyValueFactory<>("inOut"));
colBtn.setCellFactory(getEditCellFactory());
}
private Callback<TableColumn<Category, String>, TableCell<Category, String>> getEditCellFactory() {
return new Callback<TableColumn<Category, String>, TableCell<Category, String>>() {
#Override
public TableCell<Category,String> call(final TableColumn<Category, String> param) {
return new TableCell<Category, String>() {
Button btn = getEditBtn();
{
btn.setOnAction((ActionEvent event) -> {
Category data = getTableView().getItems().get(getIndex());
save(event);
});
}
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null);
setText(null);
} else {
setGraphic(btn);
setText(null);
}
}
};
}
};
}
#Override
public Button getEditBtn(){
Button b = GlyphsDude.createIconButton(FontAwesomeIcon.EDIT,btnEditText,iconSize,fontSize, ContentDisplay.GRAPHIC_ONLY);
btnEditCssClass.forEach(s->b.getStyleClass().add(s));
return b;
}
private void save(ActionEvent event) {
log.debug(event.toString());
CategoryTO categoryTO = new CategoryTO(fldName.getText(), (String) fldInOut.getValue());
categoryService.save(categoryTO);
}
private Node createPage(int pageIndex) {
int fromIndex = pageIndex * paginationSize;
int toIndex = Math.min(fromIndex + paginationSize, data.size());
pagination.setCurrentPageIndex(pageIndex);
table.setItems(FXCollections.observableArrayList(data.subList(fromIndex, toIndex)));
return mainBorder;
}
}
The first problem is that during the initialization of the controller the createPage method is executed twice. Which seems pretty strange to me. The initialization of the parent class requires only the assignment of the boundle source to a property of the class. The second problem is that at the click of a single page the call to the createPage method goes into a loop generating a stack overflow. As with the guides, the method returns the container in which the table is included. The pagination element is external to it and therefore should not be cyclically reloaded. Some advice?
In any case, the entire application is based on spring boot
EDIT: CHANGE METHOD
I modified this
private Node createPage(int pageIndex) {
log.info("Page index: " + pageIndex);
int fromIndex = pageIndex * paginationSize;
int toIndex = Math.min(fromIndex + paginationSize, data.size());
table.setItems(FXCollections.observableArrayList(data.subList(fromIndex, toIndex)));
return table;
}
and it's initialized and execute once ...but layout explode

Ok instead of
pagination.setPageFactory
just use
pagination.currentPageIndexProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
createPage(newValue.intValue());
}
});
then change createPage method in this way
private void createPage(int pageIndex) {
log.info("Page index: " + pageIndex);
int fromIndex = pageIndex * paginationSize;
int toIndex = Math.min(fromIndex + paginationSize, data.size());
table.setMinHeight(400);
table.getItems().clear();
table.setItems(FXCollections.observableArrayList(data.subList(fromIndex, toIndex)));
}
moreover
private void createPage(int pageIndex) {
int fromIndex = pageIndex * paginationSize;
int toIndex = Math.min(fromIndex + paginationSize, data.size());
table.getItems().clear();
table.setItems(FXCollections.observableArrayList(data.subList(fromIndex, toIndex)));
}
moreover borderpane node is not necessary

Related

How to load an fxml file from a controller that is linked to a different fxml file?

I am building a JavaFX which has two windows: a signin window and a register window. The fxml file of the former has a "username" label and text field, a "password" label and text field, a "signin" button, a "close" button and a hyperlink that reads "or create a new user". I want that when users click on the hyperlink, a registration window pop-up with labels and text fields asking for the user to enter a user name, password, first name, etc.
I have a Login.fxml file and a LoginController.java file for the sign in window. And for the registration window I have a CreateUser.fxml file and a CreateUSerController.java file.
My problem is how to load the CreateUser.fxml file (and make the registration window pop-up) from the LoginController.java file. I handle the clicking on the "or create a new user" hyperlink event in LoginController.java, and basically the result I expect of the handling is to make the registration window to pop-up. I get a runtime error.
When I click on the "or create a new user" hyperlink in the login window I get the following error: The Eclipse debugger says "Thread[JavaFX Application Thread](Suspended(uncaught exception RuntimeException))". Also, when I check the value of the variables during execution there is a "runWithoutRenderLock() is throwing", and its value is RuntimeException. Also says that its cause is a "InvocationTargetException", and that the cause of this exception is a "null". Also, a "QuantumToolkit.class" tab appears in eclipse with the message "Source not found" "The JAR file ... has no source attachment". It also has a clickable button that reads "Attach source"
To load "CreateUser.fxml" from "LoginController.java" I used a handler which tries to load the fxml file with this line of code: "root = FXMLLoader.<Parent>load(CreateUserController.class.getResource("CreateUser.fxml"));". Here is where the exception occurs
Please find below my Main class which is where I load the "Login.fxml" file, the "Login.fxml", "LoginController.java", "CreateUser.fxml" and CreateUSerController.java files. Also, an image of my file structure.
File structure
src
/application
-Main.java
/controller
-LoginController.java
-CreateUserController.java
/model
/view
-Login.fxml
-CreateUser.fxml
-module-info.java
Main.java
package application;
import java.io.IOException;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.fxml.FXMLLoader;
public class Main extends Application {
#Override
public void start(Stage signinStage) throws IOException {
try {
BorderPane root = (BorderPane)FXMLLoader.load(getClass().getResource("/view/Login.fxml"));
Scene scene = new Scene(root,400,400);
signinStage.setTitle("Welcome to MyHEalth");
signinStage.setScene(scene);
signinStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
launch(args);
}
}
Login.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Hyperlink?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<BorderPane xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controller.LoginController">
<center>
<VBox alignment="CENTER" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="400.0" BorderPane.alignment="CENTER">
<children>
<Label maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="21.0" prefWidth="300.0" text="Username">
<VBox.margin>
<Insets bottom="10.0" />
</VBox.margin>
</Label>
<TextField fx:id="userNameField" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="25.0" prefWidth="300.0">
<VBox.margin>
<Insets bottom="20.0" />
</VBox.margin>
</TextField>
<Label prefHeight="17.0" prefWidth="300.0" text="Password">
<VBox.margin>
<Insets bottom="10.0" />
</VBox.margin>
</Label>
<TextField fx:id="passwordField" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="25.0" prefWidth="300.0" />
<BorderPane prefHeight="100.0" prefWidth="200.0">
<center>
<HBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="30.0" prefWidth="170.0" BorderPane.alignment="CENTER">
<children>
<Button fx:id="signinButton" maxWidth="-Infinity" mnemonicParsing="false" onAction="#signin" prefWidth="70.0" text="Sign in" />
<Button fx:id="closeButton" alignment="CENTER" maxWidth="-Infinity" mnemonicParsing="false" onAction="#close" prefWidth="60.0" text="Close" textAlignment="RIGHT">
<HBox.margin>
<Insets left="40.0" />
</HBox.margin>
</Button>
</children>
</HBox>
</center>
<bottom>
<Hyperlink fx:id="newUserLink" onAction="#openNewUserWindow" text="or create new user" BorderPane.alignment="CENTER" />
</bottom>
</BorderPane>
</children>
</VBox>
</center>
</BorderPane>
LoginController.java
package controller;
import java.io.IOException;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Hyperlink;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
import model.User;
public class LoginController {
#FXML
private Button closeButton;
#FXML
private Hyperlink newUserLink;
#FXML
private TextField passwordField;
#FXML
private Button signinButton;
#FXML
private TextField userNameField;
private Stage stage;
private Parent root;
#FXML
void signin(ActionEvent event) {
passwordField.getText();
userNameField.getText();
User user = new User(passwordField.getText(), "first name", "last name", userNameField.getText(), "imagepath");
//still have to get the rest of the information from the database
System.out.print(user.getProfile().getFirstName());//debugging message
}
#FXML
void close(ActionEvent event) {
System.out.print("Thanks for visiting MyHealth. Bye");
System.exit(0);
}
#FXML
void openNewUserWindow(ActionEvent event) {
try {
System.out.print("1st line Inside 'try' block of 'openNewUserWindow' in LoginController");
//System.out.println("\nJust after FXMLLoader Inside 'try' block of 'openNewUserWindow' in LoginController");
root = FXMLLoader.<Parent>load(CreateUserController.class.getResource("CreateUser.fxml"));
//System.out.print("last line Inside 'try' block of 'openNewUserWindow' in LoginController");
}
catch(IOException e){
System.out.print("Problem getting 'CreateUSer.fxml'");
}
Stage createUserStage = new Stage();
Scene createUserScene = new Scene(root, 400, 400);
createUserStage.setScene(createUserScene);
createUserStage.setTitle("Create a new user");
createUserStage.show();
}
}
CreateUser.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="500.0" prefWidth="400.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controller.CreateUserController">
<children>
<VBox layoutY="30.0" prefHeight="440.0" prefWidth="400.0">
<children>
<ImageView fitHeight="82.0" fitWidth="100.0" pickOnBounds="true" preserveRatio="true">
<VBox.margin>
<Insets left="150.0" top="10.0" />
</VBox.margin>
</ImageView>
<Label fx:id="clickImage" text="Click to select profile picture" textFill="#00000093">
<VBox.margin>
<Insets bottom="20.0" left="125.0" />
</VBox.margin>
</Label>
<Label text="Username">
<VBox.margin>
<Insets bottom="5.0" left="50.0" />
</VBox.margin>
</Label>
<TextField fx:id="userName" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="25.0" prefWidth="280.0">
<VBox.margin>
<Insets bottom="10.0" left="50.0" />
</VBox.margin>
</TextField>
<Label text="First name">
<VBox.margin>
<Insets bottom="5.0" left="50.0" />
</VBox.margin>
</Label>
<TextField fx:id="firstName" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefWidth="280.0">
<VBox.margin>
<Insets bottom="10.0" left="50.0" />
</VBox.margin>
</TextField>
<Label text="Last name">
<VBox.margin>
<Insets bottom="5.0" left="50.0" />
</VBox.margin>
</Label>
<TextField fx:id="lastName" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefWidth="280.0">
<VBox.margin>
<Insets bottom="10.0" left="50.0" />
</VBox.margin>
</TextField>
<Label text="Password">
<VBox.margin>
<Insets bottom="5.0" left="50.0" />
</VBox.margin>
</Label>
<TextField fx:id="password" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefWidth="280.0">
<VBox.margin>
<Insets bottom="10.0" left="50.0" />
</VBox.margin>
</TextField>
<VBox prefHeight="200.0" prefWidth="100.0">
<children>
<HBox prefHeight="100.0" prefWidth="200.0">
<children>
<Button fx:id="createButton" mnemonicParsing="false" onAction="#create" text="Create user">
<HBox.margin>
<Insets left="100.0" top="15.0" />
</HBox.margin>
</Button>
<Button fx:id="closeButton" mnemonicParsing="false" onAction="#close" text="Close">
<HBox.margin>
<Insets left="30.0" top="15.0" />
</HBox.margin>
</Button>
</children>
</HBox>
<Label fx:id="createdLabel" text="Created user" textFill="#2b784f">
<VBox.margin>
<Insets left="125.0" top="20.0" />
</VBox.margin>
</Label>
</children>
</VBox>
</children>
</VBox>
</children>
</AnchorPane>
CreateUSerController.java
package controller;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
public class CreateUserController {
#FXML
private Label clickImage;
#FXML
private Button closeButton;
#FXML
private Button createButton;
#FXML
private Label createdLabel;
#FXML
private TextField firstName;
#FXML
private TextField lastName;
#FXML
private TextField password;
#FXML
private TextField userName;
#FXML
void close(ActionEvent event) {
}
#FXML
void create(ActionEvent event) {
}
}
First of all, I personally prefer to instantiate a new FXMLLoader instance to load a fxml file. Then you can also specify a location and some other kind of stuff like a controller factory.
You can lookup the setter methods here: https://docs.oracle.com/javase/8/javafx/api/javafx/fxml/FXMLLoader.html
But in this case your only mistake is that you load the fxml from the wrong class location.
When you use "CreateUserController.class.getResource("CreateUser.fxml")", it will try to find the fxml file in the same directory like the class. You have to use another path like you did before with the login fxml file. ("/view/CreateUser.fxml")
I hope that helps.

When I want to insert data without image this error occurred java.lang.NullPointerException

I am working on a library Management System (LMS) project. I am using Apache NetBeans 11.3 and JDK 8 and I have a problem in inserting data into MySQL, when I want to insert students table data into MySQL without image this NullPointerException error occurred. I know this errors says me to insert image with my data too, but sometimes I want to insert students table data into database without any images, what can I do for it to work well.
This error occurred:
java.lang.NullPointerException
at ulms.ui.addStudents.AddStudentsController.addStudents(AddStudentsController.java:226)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at sun.reflect.misc.Trampoline.invoke(MethodUtil.java:71)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at sun.reflect.misc.MethodUtil.invoke(MethodUtil.java:275)
at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1769)
at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1657)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Node.fireEvent(Node.java:8411)
at javafx.scene.control.Button.fire(Button.java:185)
at com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:182)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:96)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:89)
at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Scene$MouseHandler.process(Scene.java:3757)
at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485)
at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:394)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$2(GlassViewEventHandler.java:432)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:410)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:431)
at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
at com.sun.glass.ui.View.notifyMouse(View.java:937)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$4(WinApplication.java:186)
at java.lang.Thread.run(Thread.java:748)
AddStudentsController.java
package ulms.ui.addStudents;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXComboBox;
import com.jfoenix.controls.JFXTextField;
import java.awt.image.BufferedImage;
import java.net.URL;
import java.util.Random;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.layout.AnchorPane;
import java.sql.*;
import javafx.scene.control.Alert;
import javafx.stage.Stage;
import java.io.*;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.stage.FileChooser;
import javax.imageio.ImageIO;
import javax.swing.JOptionPane;
public class AddStudentsController implements Initializable {
Connection con;
PreparedStatement pst;
ResultSet rs;
#FXML
private AnchorPane rootAnchorS;
#FXML
private JFXTextField txtSID;
#FXML
private JFXTextField txtSName;
#FXML
private JFXTextField txtSFName;
#FXML
private JFXComboBox<String> cbxSFaculty;
#FXML
private JFXComboBox<String> cbxSDep;
#FXML
private JFXComboBox<String> cbxSYear;
#FXML
private JFXComboBox<String> cbxSSemister;
#FXML
private JFXButton btnCancelS;
#FXML
private JFXButton btnSaveS;
#FXML
private ImageView viewSImage;
#FXML
private JFXButton btnSImage;
private FileChooser fileChooser;
private File file;
private Stage stage;
private Image image;
private FileInputStream fis;
private BufferedImage bimg;
#Override
public void initialize(URL url, ResourceBundle rb) {
Random();
SFaculty();
SDep();
SYear();
SSemister();
}
public void Random(){
Random rand = new Random();
txtSID.setText("" + rand.nextInt(1000000 + 1));
}
public void SFaculty(){
cbxSFaculty.getItems().add(("کمپیوترساینس"));
cbxSFaculty.getItems().add(("علوم اجتماعی"));
cbxSFaculty.getItems().add(("اقتصاد"));
cbxSFaculty.getItems().add(("زراعت"));
cbxSFaculty.getItems().add(("حقوق و علوم سیاسی"));
cbxSFaculty.getItems().add(("انجنیری"));
cbxSFaculty.getItems().add(("تعلیم و تربیه"));
cbxSFaculty.getItems().add(("ادبیات"));
cbxSFaculty.getItems().add(("شرعیات"));
cbxSFaculty.getItems().add(("طب"));
}
public void SDep(){
cbxSDep.getItems().add(("مهندسی نرم افزار"));
cbxSDep.getItems().add(("فناوری اطلاعات"));
cbxSDep.getItems().add(("فناوری اطلاعات و ارتباطات"));
cbxSDep.getItems().add(("دیتابیس"));
cbxSDep.getItems().add(("مهندسی شبکه"));
cbxSDep.getItems().add(("----------"));
cbxSDep.getItems().add(("تاریخ"));
cbxSDep.getItems().add(("جفرافیه"));
cbxSDep.getItems().add(("جامعه شناسی"));
cbxSDep.getItems().add(("----------"));
cbxSDep.getItems().add(("منجمنت و اداره تشبثات"));
cbxSDep.getItems().add(("امور مالی و بانکی"));
cbxSDep.getItems().add(("----------"));
cbxSDep.getItems().add(("جنگلات و منابع طبیعی"));
cbxSDep.getItems().add(("علوم حیوانی"));
cbxSDep.getItems().add(("هارتیکلچر یا باغداری"));
cbxSDep.getItems().add(("----------"));
cbxSDep.getItems().add(("قضا و ثارنوالی"));
cbxSDep.getItems().add(("اداره و دیپلوماسی"));
cbxSDep.getItems().add(("----------"));
cbxSDep.getItems().add(("سیول"));
cbxSDep.getItems().add(("میخانیک"));
cbxSDep.getItems().add(("مهندسی"));
cbxSDep.getItems().add(("طراحی شهری"));
cbxSDep.getItems().add(("برق و الکترونیک"));
cbxSDep.getItems().add(("انرژی"));
cbxSDep.getItems().add(("----------"));
cbxSDep.getItems().add(("ریاضی"));
cbxSDep.getItems().add(("فیزیک"));
cbxSDep.getItems().add(("کیمیا"));
cbxSDep.getItems().add(("بیولوژی"));
cbxSDep.getItems().add(("----------"));
cbxSDep.getItems().add(("زبان و ادبیات فارسی دری"));
cbxSDep.getItems().add(("زبان و ادبیات پشتو"));
cbxSDep.getItems().add(("زبان و ادبیات انگلیسی"));
cbxSDep.getItems().add(("زبان و ادبیات عربی"));
cbxSDep.getItems().add(("ژورنالیزم"));
cbxSDep.getItems().add(("----------"));
cbxSDep.getItems().add(("تعلیمات اسلامی"));
cbxSDep.getItems().add(("----------"));
cbxSDep.getItems().add(("طب عمومی"));
}
public void SYear(){
cbxSYear.getItems().add("1");
cbxSYear.getItems().add("2");
cbxSYear.getItems().add("3");
cbxSYear.getItems().add("4");
cbxSYear.getItems().add("5");
cbxSYear.getItems().add("6");
cbxSYear.getItems().add("7");
}
public void SSemister(){
cbxSSemister.getItems().add("1");
cbxSSemister.getItems().add("2");
cbxSSemister.getItems().add("3");
cbxSSemister.getItems().add("4");
cbxSSemister.getItems().add("5");
cbxSSemister.getItems().add("6");
cbxSSemister.getItems().add("7");
cbxSSemister.getItems().add("8");
cbxSSemister.getItems().add("9");
cbxSSemister.getItems().add("10");
cbxSSemister.getItems().add("11");
cbxSSemister.getItems().add("12");
cbxSSemister.getItems().add("13");
cbxSSemister.getItems().add("14");
}
#FXML
private void cancelStudents(ActionEvent event) {
stage = (Stage) rootAnchorS.getScene().getWindow();
stage.close();
}
#FXML
private void addStudents(ActionEvent event) {
String SID = txtSID.getText();
String SName = txtSName.getText();
String SFName = txtSFName.getText();
String SFaculty = cbxSFaculty.getItems().toString();
String SDep = cbxSDep.getItems().toString();
String SYear = cbxSYear.getItems().toString();
String SSemister = cbxSSemister.getItems().toString();
if(SID.isEmpty() || SName.isEmpty() || SFName.isEmpty() || SFaculty.isEmpty() || SDep.isEmpty() ||
SYear.isEmpty() || SSemister.isEmpty()){
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.setHeaderText(null);
alert.setTitle("خطا");
alert.setContentText("لطفا تمام فیلد ها را پر کنید");
alert.showAndWait();
}
else{
String addStudent = "insert into students (SID, SName, SFName, Faculty, Department, Year, Semister, SImage) values (?,?,?,?,?,?,?,?)";
try {
Class.forName("com.mysql.jdbc.Driver").newInstance();
String url = ("jdbc:mysql://localhost:3306/ulms");
String user = "root";
String pass = "Mysql786";
con = DriverManager.getConnection(url, user, pass);
pst = con.prepareStatement(addStudent);
pst.setString(1, txtSID.getText());
pst.setString(2, txtSName.getText());
pst.setString(3, txtSFName.getText());
pst.setString(4, (String)cbxSFaculty.getSelectionModel().getSelectedItem());
pst.setString(5, (String)cbxSDep.getSelectionModel().getSelectedItem());
pst.setString(6, (String)cbxSYear.getSelectionModel().getSelectedItem());
pst.setString(7, (String)cbxSSemister.getSelectionModel().getSelectedItem());
pst.setBinaryStream(8, (InputStream)fis, (int)file.length());
pst.executeUpdate();
pst.close();
con.close();
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setHeaderText(null);
alert.setTitle("اطلاعات");
alert.setContentText("دانشجو جدید موفقانه ایجاد شد");
alert.showAndWait();
txtSID.setText("");
txtSName.setText("");
txtSFName.setText("");
SFaculty();
SDep();
SYear();
SSemister();
viewSImage.setImage(null);
Random();
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException | SQLException e) {
e.printStackTrace();
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.setHeaderText(null);
alert.setTitle("خطا");
alert.setContentText("دانشجو جدید ایجاد نشد");
alert.showAndWait();
} catch(NullPointerException e){
e.printStackTrace();
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.setHeaderText(null);
alert.setTitle("خطا");
alert.setContentText("لطفا تصویر را انتخاب کنید");
alert.showAndWait();
}
}
}
#FXML
private void openImageS(ActionEvent event) {
fileChooser = new FileChooser();
FileChooser.ExtensionFilter ext1 = new FileChooser.ExtensionFilter("JPG files(*.jpg)", "*.JPG");
FileChooser.ExtensionFilter ext2 = new FileChooser.ExtensionFilter("PNG files(*.png)", "*.PNG");
FileChooser.ExtensionFilter ext3 = new FileChooser.ExtensionFilter("ICON files(*.ico)", "*.ICO");
fileChooser.getExtensionFilters().addAll(ext1, ext2, ext3);
stage = (Stage) rootAnchorS.getScene().getWindow();
file = fileChooser.showOpenDialog(stage);
if(file != null){
String p = file.getAbsolutePath();
try {
fis = new FileInputStream(file);
bimg = ImageIO.read(file);
image = SwingFXUtils.toFXImage(bimg, null);
image = new Image(file.getAbsoluteFile().toURI().toString(), viewSImage.getFitWidth(), viewSImage.getFitHeight(), true, true);
viewSImage.setImage(image);
viewSImage.setPreserveRatio(true);
} catch (IOException e) {
e.printStackTrace();
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.setHeaderText(null);
alert.setTitle("خطا");
alert.setContentText("تصویر وارد نشد");
alert.showAndWait();
}
}
}
}
addStudents.java
package ulms.ui.addStudents;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class addStudents extends Application {
#Override
public void start(Stage stage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("addStudents.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
stage.setTitle("ایجاد دانشجو جدید");
}
public static void main(String[] args) {
launch(args);
}
}
addStudents.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXComboBox?>
<?import com.jfoenix.controls.JFXTextField?>
<?import java.net.URL?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<AnchorPane id="AnchorPane" fx:id="rootAnchorS" prefHeight="393.0" prefWidth="600.0" styleClass="mainFxmlClass" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="ulms.ui.addStudents.AddStudentsController">
<stylesheets>
<URL value="#addstudents.css" />
</stylesheets>
<children>
<VBox layoutX="255.0" prefHeight="399.0" prefWidth="345.0">
<children>
<JFXTextField fx:id="txtSID" alignment="CENTER_RIGHT" disable="true" editable="false" labelFloat="true" promptText="آی دی">
<VBox.margin>
<Insets bottom="10.0" left="10.0" right="10.0" top="20.0" />
</VBox.margin>
<font>
<Font size="13.0" />
</font>
</JFXTextField>
<JFXTextField fx:id="txtSName" alignment="CENTER_RIGHT" labelFloat="true" layoutX="10.0" layoutY="10.0" promptText="نام">
<VBox.margin>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</VBox.margin>
<font>
<Font size="13.0" />
</font>
</JFXTextField>
<JFXTextField fx:id="txtSFName" alignment="CENTER_RIGHT" labelFloat="true" layoutX="10.0" layoutY="35.0" promptText="نام پدر">
<VBox.margin>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</VBox.margin>
<font>
<Font size="13.0" />
</font>
</JFXTextField>
<JFXComboBox fx:id="cbxSFaculty" labelFloat="true" prefWidth="325.0" promptText="دانشکده">
<VBox.margin>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</VBox.margin>
</JFXComboBox>
<JFXComboBox fx:id="cbxSDep" labelFloat="true" layoutX="20.0" layoutY="226.0" prefWidth="325.0" promptText="بخش">
<VBox.margin>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</VBox.margin>
</JFXComboBox>
<JFXComboBox fx:id="cbxSYear" labelFloat="true" layoutX="20.0" layoutY="177.0" prefWidth="325.0" promptText="سال">
<VBox.margin>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</VBox.margin>
</JFXComboBox>
<JFXComboBox fx:id="cbxSSemister" labelFloat="true" layoutX="20.0" layoutY="222.0" prefWidth="325.0" promptText="سمستر">
<VBox.margin>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</VBox.margin>
</JFXComboBox>
<HBox prefHeight="66.0" prefWidth="345.0">
<children>
<JFXButton fx:id="btnCancelS" alignment="CENTER" cancelButton="true" contentDisplay="RIGHT" onAction="#cancelStudents" prefHeight="55.0" prefWidth="180.0" stylesheets="#addstudents.css" text="لغو کردن" textAlignment="CENTER">
<font>
<Font name="B Nazanin Bold" size="15.0" />
</font>
<HBox.margin>
<Insets top="10.0" />
</HBox.margin>
</JFXButton>
<JFXButton fx:id="btnSaveS" alignment="CENTER" contentDisplay="RIGHT" defaultButton="true" layoutX="10.0" layoutY="10.0" onAction="#addStudents" prefHeight="55.0" prefWidth="180.0" stylesheets="#addstudents.css" text="ذخیره کردن" textAlignment="CENTER">
<font>
<Font name="B Nazanin Bold" size="15.0" />
</font>
<HBox.margin>
<Insets top="10.0" />
</HBox.margin>
</JFXButton>
</children>
</HBox>
</children>
</VBox>
<ImageView fx:id="viewSImage" fitHeight="187.0" fitWidth="197.0" layoutX="25.0" layoutY="21.0" pickOnBounds="true" preserveRatio="true" />
<JFXButton fx:id="btnSImage" layoutX="58.0" layoutY="227.0" onAction="#openImageS" prefHeight="38.0" prefWidth="131.0" stylesheets="#addstudents.css" text="وارد کردن تصویر">
<font>
<Font name="B Nazanin Bold" size="14.0" />
</font>
</JFXButton>
</children>
</AnchorPane>

JavaFX and Spring - Reusable FXML component

I am building a GUI with Scene Builder in JavaFX and Spring Boot. Several of my scenes have one element in common, which is a simple KPI indicator, called PerformanceBeacon. Depending on the configuration, done by the controller class, the beacon can be used e.g. for project parameters like budget, time and so one. Ideally, even a single scene may have multiple of this elements.
The issue is, having multiple KPI beacons in a single scene does somehow not work, since all embedded controllers are pointing to the same memory and hence, I can only manipulate one - which is the last - KPI beacon.
The snipped from the fxml file looks like this:
...
<VBox layoutX="301.0" layoutY="325.0" spacing="6.0" AnchorPane.leftAnchor="2.0" AnchorPane.topAnchor="24.0">
<children>
<fx:include source="PerformanceBeacon.fxml" fx:id="embeddedTimeKPI" />
<fx:include source="PerformanceBeacon.fxml" fx:id="embeddedBudgetKPI"/>
<fx:include source="PerformanceBeacon.fxml" fx:id="embeddedResourcesKPI"/>
<fx:include source="PerformanceBeacon.fxml" fx:id="embeddedScopeKPI"/>
<fx:include source="PerformanceBeacon.fxml" fx:id="embeddedEffortKPI"/>
<fx:include source="PerformanceBeacon.fxml" fx:id="embeddedQualityKPI"/>
</children>
</VBox>
...
The embedded controllers are defined in the controller class of the enclosing UI and the code should "only" set the label of each of the Hyperlinks in each PerformanceBeacon.
#Controller
public class ProductManagerCtrl implements Initializable {
...
#FXML protected PerformanceBeaconCtrl embeddedTimeKPIController;
#FXML protected PerformanceBeaconCtrl embeddedBudgetKPIController;
#FXML protected PerformanceBeaconCtrl embeddedResourcesKPIController;
#FXML protected PerformanceBeaconCtrl embeddedScopeKPIController;
#FXML protected PerformanceBeaconCtrl embeddedEffortKPIController;
#FXML protected PerformanceBeaconCtrl embeddedQualityKPIController;
...
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
...
initializePerformanceIndicator();
...
}
protected void initializePerformanceIndicator() {
embeddedBudgetKPIController.setHyperlink("Budget", null);
embeddedScopeKPIController.setHyperlink("Scope", null);
embeddedTimeKPIController.setHyperlink("Time", null);
embeddedQualityKPIController.setHyperlink("Quality", null);
embeddedResourcesKPIController.setHyperlink("Resources", null);
embeddedEffortKPIController.setHyperlink("Effort estimates", null);
}
When I debug the code, each of these embedded controllers points to the same memory. So effectively I have one controller and can only manipulate the last element. In the end the last beacon has the "Effort estimates" label and all others are unchanged.
The PerformanceBeacon.fxml is rather simple. I copy it, in case you want to try yourself
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.Double?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Hyperlink?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.shape.Circle?>
<?import javafx.scene.shape.Polygon?>
<GridPane styleClass="pane" stylesheets="#../stylesheets/PerformanceBeacon.css" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.agiletunes.productmanager.controllers.PerformanceBeaconCtrl">
<children>
<Circle fx:id="beacon" fill="#1fff4d" radius="10.0" stroke="BLACK" strokeType="INSIDE" GridPane.columnIndex="1" GridPane.valignment="CENTER">
<GridPane.margin>
<Insets bottom="12.0" left="12.0" right="6.0" top="12.0" />
</GridPane.margin>
</Circle>
<Polygon fx:id="trendArrow" fill="#11ff1c" rotate="45.0" stroke="#2e229a" strokeType="INSIDE" GridPane.columnIndex="2" GridPane.valignment="CENTER">
<points>
<Double fx:value="-10.0" />
<Double fx:value="10.0" />
<Double fx:value="-5.0" />
<Double fx:value="10.0" />
<Double fx:value="-5.0" />
<Double fx:value="15.0" />
<Double fx:value="5.0" />
<Double fx:value="15.0" />
<Double fx:value="5.0" />
<Double fx:value="10.0" />
<Double fx:value="10.0" />
<Double fx:value="10.0" />
<Double fx:value="0.0" />
<Double fx:value="-10.0" />
</points>
<GridPane.margin>
<Insets bottom="12.0" left="12.0" right="12.0" top="12.0" />
</GridPane.margin>
</Polygon>
<Hyperlink fx:id="hyperlink" onAction="#showDetails" text="Subject">
<GridPane.margin>
<Insets left="24.0" />
</GridPane.margin>
</Hyperlink>
</children>
<columnConstraints>
<ColumnConstraints hgrow="ALWAYS" maxWidth="1.7976931348623157E308" minWidth="170.0" />
<ColumnConstraints minWidth="10.0" />
<ColumnConstraints minWidth="10.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints />
</rowConstraints>
</GridPane>
And last but not least the Controller of the PerformanceBeacon
#Controller
public class PerformanceBeaconCtrl {
#FXML protected Circle beacon;
#FXML private Polygon trendArrow;
#FXML private Hyperlink hyperlink;
#FXML
public void showDetails(ActionEvent event) {
// TODO
}
public void setHyperlink(String label, URL url) {
Platform.runLater(() -> {
hyperlink.setText(label);
});
}
public void setBeaconColor(Color color) {
Platform.runLater(() -> {
beacon.setFill(color);
});
}
public void setTrend(Double angle) {
Platform.runLater(() -> {
trendArrow.rotateProperty().set(angle);
});
}
}
I am successfully using embedded UI elements / controller also elsewhere in my code. But never the same element multiple times.
I am not sure whether this is a Spring side effect?
What am I doing wrong? Thank you in advance.
The described observation suggests that the issue was related to a singleton somewhere in the design. My suspicion regarding the Spring influence was right. The ProductManagerCtrl controller class gets created using
fxmlLoader.setControllerFactory(c -> ProdMgrApp.springContext.getBean(c));
and as it turns out, this approach creates singletons by default. Therefore all embedded controller are also singletons. The way to fix it is to annotate the PerformanceBeaconCtrl controller class also with
#Scope("prototype")

How to pass a value to fxml scene

I'm making this javaFX application, but in a given moment i wanna get the text exibited in the scene from a method in anothe class, how can i pass this value to my text box in the FXML doccument?
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.effect.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/8.0.72" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.crapgames.calourosimulator.views.pcna.intro.Introduction">
<children>
<ImageView fx:id="imgClick" fitHeight="600.0" fitWidth="800.0" onMouseClicked="#nextScene" pickOnBounds="true">
<image>
<Image url="#../../assets/pnca-monitor-text.png" />
</image>
</ImageView>
<Text fx:id="text1" fill="#f5eded" layoutX="8.0" layoutY="452.0" strokeType="OUTSIDE" strokeWidth="0.0" text="where i want my string variable" wrappingWidth="787.0">
<font>
<Font name="Comic Sans MS" size="25.0" />
</font></Text>
</children>
</AnchorPane>
Create a method in the controller class to accept the text value. You can leverage the textProperty of the Text if you want:
public class Introduction {
#FXML
private Text text1 ;
public StringProperty textProperty() {
return text1.textProperty();
}
public final void setText(String text) {
textProperty().set(text);
}
public final String getText() {
return textProperty().get();
}
// existing code ...
}
Now you can do:
FXMLLoader loader = new FXMLLoader(getClass().getResource("path/to/fxml/file.fxml"));
Parent root = loader.load();
Introduction controller = loader.getController();
controller.setText("Hello World!");
Scene scene = new Scene(root);
// etc...

TableView: the last line becomes unselectable after row deletion -Is this a bug

for more information see this link Sometimes TableView cannot select last row after row deletion.
the problem only appears when the TableView must contain exactly 6 lines. if I delete the fourth or fifth line, the last line (necessarily fifth) becomes inaccessible (not selectable). as soon as I make another line suppression, the line that was not unreachable becomes selectable !!.
My Controller has the following code:
public class FXMLIssueController implements Initializable {
#FXML
private TableView<User> userTable;
#FXML
private TableColumn<User, String> nameCol;
#FXML
private TableColumn<User, LocalDate> birthdayCol;
#FXML
private TableColumn<User, String> emailCol;
#FXML
private TextField name;
#FXML
private TextField email;
#FXML
private DatePicker birthday;
private ObservableList<User> data;
private LocalDate birth;
/**
* Initializes the controller class.
*/
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
data = FXCollections.observableArrayList();
birthday.setOnAction((ActionEvent evnt) -> {
birth = birthday.getValue();
});
userTable.getSelectionModel().selectedItemProperty().addListener(userListener);
configureColumn();
fill_in();
}
#FXML
private void newUser(ActionEvent event) {
userTable.getSelectionModel().clearSelection();
userTable.getSelectionModel().selectedItemProperty().removeListener(userListener);
name.clear();
birthday.valueProperty().set(null);
email.clear();
userTable.getSelectionModel().selectedItemProperty().addListener(userListener);
}
#FXML
private void addUser(ActionEvent event) {
User u = new User();
u.setName(name.getText());
u.setEmail(email.getText());
u.setBirthday(birthday.getValue());
data.add(u);
}
#FXML
private void deleteUser(ActionEvent event) {
User u = userTable.getSelectionModel().selectedItemProperty().getValue();
if (u != null) {
data.remove(u);
}
}
#FXML
private void populate() {
data.clear();
fill_in();
}
private void configureColumn() {
nameCol.setCellValueFactory(new PropertyValueFactory<User, String>("name"));
emailCol.setCellValueFactory(new PropertyValueFactory<User, String>("email"));
birthdayCol.setCellValueFactory(new PropertyValueFactory<User, LocalDate>("birthday"));
birthdayCol.setCellFactory(p -> {
return new TableCell<User, LocalDate>() {
#Override
protected void updateItem(LocalDate item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setText(null);
} else {
final DateTimeFormatter format = DateTimeFormatter.ofPattern("dd/MM/yyyy");
setText(item.format(format));
}
}
};
});
}
private final ChangeListener<User> userListener = (value, oldV, newV) -> {
if (oldV != null) {
name.textProperty().unbindBidirectional(oldV.nameProperty());
email.textProperty().unbindBidirectional(oldV.emailProperty());
birthday.valueProperty().unbindBidirectional(oldV.birthdayProperty());
}
if (newV != null) {
name.textProperty().bindBidirectional(newV.nameProperty());
email.textProperty().bindBidirectional(newV.emailProperty());
birthday.valueProperty().bindBidirectional(newV.birthdayProperty());
}
};
private void fill_in(){
for (int i = 0; i < 6; i++) {
User u = new User();
u.setName("u"+i);
u.setBirthday(LocalDate.now().plusDays(i));
u.setEmail("mail"+i+"#gmail.com");
data.addAll(u);
}
userTable.setItems(data);
userTable.getSelectionModel().select(0);
}
}
My FXML File:
<?import javafx.geometry.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="300.0" prefWidth="381.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="issue.FXMLIssueController">
<bottom>
<TableView fx:id="userTable" prefHeight="141.0" prefWidth="381.0" BorderPane.alignment="CENTER">
<columns>
<TableColumn fx:id="nameCol" prefWidth="75.0" text="Name" />
<TableColumn fx:id="birthdayCol" prefWidth="163.0" text="Birthday" />
<TableColumn fx:id="emailCol" prefWidth="141.0" text="Email" />
</columns>
</TableView>
</bottom>
<top>
<HBox alignment="CENTER_RIGHT" prefHeight="40.0" prefWidth="381.0" spacing="10.0" BorderPane.alignment="CENTER">
<children>
<HBox alignment="CENTER_LEFT" prefHeight="30.0" prefWidth="213.0">
<children>
<Button mnemonicParsing="false" onAction="#populate" text="Populate" />
</children>
</HBox>
<Button mnemonicParsing="false" onAction="#newUser" text="New" />
<Button mnemonicParsing="false" onAction="#addUser" text="Add" />
<Button mnemonicParsing="false" onAction="#deleteUser" text="Delete" />
</children>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
</HBox>
</top>
<center>
<GridPane prefHeight="100.0" prefWidth="600.0" BorderPane.alignment="CENTER">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="294.0" minWidth="10.0" prefWidth="91.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="477.0" minWidth="10.0" prefWidth="387.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label text="Name:" />
<Label text="Birthday" GridPane.rowIndex="1" />
<Label text="email" GridPane.rowIndex="2" />
<TextField fx:id="name" prefHeight="25.0" prefWidth="375.0" GridPane.columnIndex="1" GridPane.hgrow="ALWAYS" />
<TextField fx:id="email" GridPane.columnIndex="1" GridPane.hgrow="ALWAYS" GridPane.rowIndex="2" />
<DatePicker fx:id="birthday" prefHeight="25.0" prefWidth="346.0" GridPane.columnIndex="1" GridPane.rowIndex="1" />
</children>
<padding>
<Insets bottom="7.0" left="7.0" right="7.0" top="7.0" />
</padding>
</GridPane>
</center>
</BorderPane>
Here is the code of the User Class:
public class User {
private final StringProperty name = new SimpleStringProperty();
private final StringProperty email = new SimpleStringProperty();
private final ObjectProperty<LocalDate> birthday = new SimpleObjectProperty<>();
public StringProperty nameProperty() {
return name;
}
public String getName() {
return name.get();
}
public void setName(String name) {
this.name.set(name);
}
public StringProperty emailProperty() {
return email;
}
public String getEmail() {
return email.get();
}
public void setEmail(String email) {
this.email.set(email);
}
public ObjectProperty<LocalDate> birthdayProperty() {
return birthday;
}
public LocalDate getBirthday() {
return birthday.get();
}
public void setBirthday(LocalDate birthday) {
this.birthday.set(birthday);
}
}
class Main:
public class Test extends Application {
#Override
public void start(Stage stage) throws IOException {
Parent root = FXMLLoader.load(getClass().getResource("/issue/FXMLIssue.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.setResizable(false);
stage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}}
I invite you to test the program as follows:
delete the fourth or fifth line.
try to select the last line using the mouse.
if no problem, click the button populate and try again.
Use the following links to download and test the program:
complete project
executable file

Resources