NullPointerException passing a string from a window to another - javafx

Long story short, I searched for similar problems to mine, so I could troubleshoot this "by my own". I found these examples here and here, but none of them worked for me.
I need to pass to the next window a string that was typed in the TextField of the first window.
My main:
public class Main extends Application{
/**
* #param stage
* #throws java.lang.Exception
*/
#Override
public void start(Stage stage) throws Exception {
FXMLLoader floader = new FXMLLoader();
Parent root = FXMLLoader.load(getClass().getResource("java1.fxml"));
Java1Controller j1 = (Java1Controller)floader.getController();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.setResizable(false);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
As I'm using FXML, here's the controller of Window1 (java1):
public class Java1Controller implements Initializable {
#FXML
private TextField tSend;
#FXML
private Button bSend;
/**
* Initializes the controller class.
*/
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
#FXML
private void sendText(ActionEvent event) throws IOException {
FXMLLoader fLd = new FXMLLoader();
Parent novo = FXMLLoader.load(getClass().getResource("java2.fxml"));
Java2Controller j2 = (Java2Controller)fLd.getController();
j2.setLbText(tSend.getText());
Scene novScene = new Scene(novo);
Stage novStage = (Stage)((Node)(event.getSource())).getScene().getWindow();
novStage.setScene(novScene);
novStage.setResizable(false);
novStage.show();
}
}
And the controller of Window2 (java2):
public class Java2Controller implements Initializable {
#FXML
private Label lbText;
#FXML
private Button bOK;
/**
* Initializes the controller class.
* #param url
* #param rb
*/
/**
* #param string the string to set
*/
public void setLbText(String string) {
lbText.setText(string);
}
#FXML
private void closeJPane(ActionEvent event) {
Stage stage = (Stage)((Node)(event.getSource())).getScene().getWindow();
stage.close();
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}
The problem is pointed to the Java1Controller line where I setText with my custom function (j2.setLbText). Why? If it matters, I'm using Netbeans 8.2 and JavaFX Scene Builder 11.0.
FXML Java1:
<Pane maxHeight="252.0" maxWidth="388.0" minHeight="252.0" minWidth="388.0" prefHeight="252.0" prefWidth="388.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="main.Java1Controller">
<children>
<Label layoutX="126.0" layoutY="76.0" text="Insira texto aqui:">
<font>
<Font size="16.0" />
</font>
</Label>
<TextField fx:id="tSend" layoutX="109.0" layoutY="102.0" />
<Button fx:id="bSend" layoutX="169.0" layoutY="178.0" mnemonicParsing="false" onAction="#sendText" text="Send" />
</children>
</Pane>
FXML Java2:
<Pane maxHeight="388.0" maxWidth="252.0" minHeight="252.0" minWidth="388.0" prefHeight="252.0" prefWidth="388.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="main.Java2Controller">
<children>
<Label fx:id="lbText" layoutX="137.0" layoutY="106.0" text="Texto enviado">
<font>
<Font size="16.0" />
</font>
</Label>
<Button fx:id="bOK" layoutX="164.0" layoutY="178.0" mnemonicParsing="false" onAction="#closeJPane" prefHeight="26.0" prefWidth="61.0" text="OK" />
</children>
</Pane>

You're using static load methods to load the fxmls. This way a new FXMLLoader instance is created by the method that you cannot get a reference to. The FXMLLoader instance you create yourself is never used to load an fxml file, so no controller is available via its getController property:
// here you create a loader without setting a location
FXMLLoader fLd = new FXMLLoader();
// here a static method uses another loader instance to load the fxml
Parent novo = FXMLLoader.load(getClass().getResource("java2.fxml"));
// here you try to retrieve the controller from the loader instance that is still in the same state as after the constructor completion
Java2Controller j2 = (Java2Controller)fLd.getController();
Change your code an use the loader instance you created yourself to load the fxml:
// create loader with location set
FXMLLoader fLd = new FXMLLoader(getClass().getResource("java2.fxml"));
// use loader instance to load fxml from location specified
Parent novo = fLd.load();
// the controller should now be available
Java2Controller j2 = (Java2Controller)fLd.getController();
assert j2 != null

Related

Update component in javafx

Hy guys, I'm developing an application using javafx and fxml.
What I'm currently trying to do is to update a flowpane, adding components to it when the user performs an action (is not the case but let's take as an example the click of a button).
Let's suppose that the method just has to add buttons with the passed labels to the flowpane.
In the Controller of the fxml that contains the flowpane I have this:
public class CategoryPaneController implements Initializable {
#FXML
private FlowPane categoryContainer;
public void setCategories(String[] labels) throws IOException{
for(String label : labels){
Button button = new Button(label);
categoryContainer.getChildren().add(button);
}
}
}
This method is called in another controller as follows:
public class AddCategoryController implements Initializable {
#FXML
private Pane addCategoryPane;
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
#FXML
private void refreshCategories(ActionEvent event) throws IOException {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/view/categoryPane.fxml"));
loader.load();
CategoryPaneController cat = loader.getController();
String[] labels = {"categoria3", "categoria4"};
cat.setCategories(labels);
}
}
The categoryPane.fxml is the following:
<ScrollPane fx:id="storeMainPane" fx:controller="controller.CategoryPaneController">
<content>
<VBox prefHeight="629.0" prefWidth="862.0">
<children>
<Label alignment="TOP_CENTER" contentDisplay="CENTER" prefHeight="68.0" prefWidth="857.0" text="Magazzino" />
<FlowPane fx:id="categoryContainer" prefHeight="549.0" prefWidth="862.0" />
</children>
</VBox>
</content>
</ScrollPane>
And the following is the addCategory.fxml file
<Pane fx:id="addCategoryPane" fx:controller="controller.AddCategoryController">
<children>
<Button onAction="#refreshCategories" text="aggiungi categoria" />
</children>
</Pane>
I've debbugged the code and the method is called in the right way, it adds the buttons to the flowpane but the latter doesn't change.
Thanks in advance. <3
Every time you load a new FXML a new Controller instance and new nodes will be generated.
If you want to use an existing controller and nodes, you need to store a reference to the originally loaded controller and invoke methods on that.
Calling methods on a controller.
Or you can use MVC:
Applying MVC With JavaFx

Using JavaFX to pass data to an already opened window

I'm new to JavaFX. This was easy to do without FXML, but the FXML controllers are stumping me.
What I'm trying to do: Set up a main window that has a button. When clicked, the button launches a second popup window in which the user submits a value. Upon closing the second window (done currently with a button click on the pop-up), I'd like the user's input to be passed back to the main controller-- the main window that is already open.
So far, I've got 2 .fxml files(one for a main window the other for a popup), and the corresponding controllers: MainWindowController:
public class MainController implements Initializable {
#FXML
public Label label;
#FXML
private Button button;
#FXML
private void popBtnClick(ActionEvent event) throws IOException {
//creates new pop-up window
Stage popupSave = new Stage();
popupSave.initModality(Modality.APPLICATION_MODAL);
popupSave.initOwner(ComWins.stage);
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("PopUp.fxml"));
Parent root = loader.load();
PopUpController controller = loader.getController();
//calls a method in the PopUpController, and uses it to pass data to
//the Popup window.
controller.dataToPopUp(7);
Scene scene = new Scene(root);
popupSave.setScene(scene);
popupSave.showAndWait();
}
I also tried calling this method from the popup window with no success in
changing Main's label.
public void dataPass(String name){
label.setText(name);
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}
And PopUpController:
public class PopUpController implements Initializable {
#FXML
private Button ok_btn;
#FXML
public TextField input_tf;
#FXML
private String input;
#FXML
private void okBtnClick() throws IOException {
input = input_tf.getText();
/*my attempt to pass the variable-- using a loader to get the
controller and then referencing the public label. */
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("Main.fxml"));
Parent root = loader.load();
FXMLDocumentController controller = loader.getController();
//this line works, and retrieves the label's text.
String temp = controller.label.getText();
//but this line does not work. Why?
controller.label.setText(input);
//closes this pop-up
Stage stage = (Stage)input_tf.getScene().getWindow();
stage.close();
}
//this method is called in the maincontroller and used to pass data to
//the popup's textfield.
public void dataToPopUp(int x){
input_tf.setText(Integer.toString(x));
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}
Using the above, Main passes ('7') into the PopUp's textfield. But if the user enters something else into the textfield, I cannot seem to get that data back to Main. This is like having a Settings Pop-up window, and then passing the user's selections from the Settings popup back to the main window. I just cannot figure out how to pass things back to the main window.
I am not using SpringBoot, but thanks for the suggestion.
Thank you in advance!
If you are using Spring Boot, MPV Java on YouTube has great examples of connecting your controllers together allowing you to pass information cleanly and easily between them.In my application I've been able to implement these examples. Each controller is registered as a bean using #Component which means you can #Autowire the controller into another controller. In your main controller I would recommend setting up some basic getters/setters to allow outside interaction with your fields so other controllers can "talk" to the main controller.
A really basic example would be:
#Component
public class MyMainController {
#FXML private TextField exampleTextField;
...
...
/* Get the text of a field from this controller: can be accessed from another controller */
public String getExampleTextField() {
exampleTextField.getText();
}
/* Set the text of a field on this controller: can be accessed from another controller */
public void setExampleTextField(String text) {
exampleTextField.setText(text);
}
}
#Component
public class AnotherController {
#Autowired private MyMainController myMainController;
...
...
public void someMethod(String newText) {
// Do some work here and set some text back to the main controller
myMainController.setExampleTextField(newText);
}
}
MPV Java does a much better job of explaining this concept.
https://www.youtube.com/watch?v=hjeSOxi3uPg
I reviewed the suggestions and was unable to get anything to work for me-- many of the concepts were over my head, as I'm new to Java. After several attempts, I was able to get a fairly simple solution to the problem. It is likely far from best practices, but it works:
In the main window's controller, use the popup's controller to call the Pop Up's string variable and set it as the label's text (label.setText(controller.test)). The string variable has to be public, and is set once the pop-up is closed by the button click. See the code below:
Main.fxml:
<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="switchingpass.MainController">
<children>
<Button fx:id="button" layoutX="126" layoutY="90" onAction="#popBtnClick" text="Click Me!" />
<Label fx:id="label2" layoutX="126" layoutY="120" minHeight="16" minWidth="69" />
<Label fx:id="label" layoutX="143.0" layoutY="38.0" text="Label" />
</children>
</AnchorPane>
MainController:
public class MainController implements Initializable {
#FXML
public Label label;
#FXML
private Button button;
#FXML
private void popBtnClick(ActionEvent event) throws IOException {
//creates new pop-up window
Stage popupSave = new Stage();
popupSave.initModality(Modality.APPLICATION_MODAL);
popupSave.initOwner(SwitchingPass.stage);
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("PopUp.fxml"));
Parent root = loader.load();
PopUpController controller = loader.getController();
Scene scene = new Scene(root);
popupSave.setScene(scene);
popupSave.showAndWait();
//after the popup closes, this will run, setting the label's text to the popup's test variable, which is public.
label.setText(controller.test);
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}
PopUp.fxml:
<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="switchingpass.PopUpController">
<children>
<TextField fx:id="input_tf" layoutX="207.0" layoutY="65.0" />
<Button fx:id="close_btn" layoutX="268.0" layoutY="185.0" mnemonicParsing="false" onAction="#closeBtnClick" text="Close" />
</children>
</AnchorPane>
PopUpController:
public class PopUpController implements Initializable {
#FXML
public Button close_btn;
#FXML
public TextField input_tf;
#FXML
public String test;
#FXML
private void closeBtnClick() throws IOException {
//stores textfield input as a string
test = input_tf.getText();
Stage stage = (Stage)input_tf.getScene().getWindow();
stage.close();
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}
Please note that the code's main class that extends Application must declare the stage variable as a public static variable:
public class SwitchingPass extends Application {
//this is necessary to initialize the owner of the popup
public static Stage stage;
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("Main.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Again, probably not the best way to accomplish this, but it works, and perhaps it is helpful to someone else.
I did that this way.
First create an interface
public interface DataSender {
void send(String data);
}
and then implement that interface to your Main Window Controller
public class FXMLDocumentController implements Initializable,DataSender {
#FXML
private Label label;
#FXML
private void handleButtonAction(ActionEvent event) {
try {
Stage popupSave = new Stage();
popupSave.initModality(Modality.NONE);
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("PopUp.fxml"));
Parent root = loader.load();
PopUpController controller = loader.getController();
controller.setX(7);
//this is the line use to get data from popup
controller.setSendDataSender(this);
Scene scene = new Scene(root);
popupSave.setScene(scene);
popupSave.show();
} catch (IOException ex) {
Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
}
}
//this method can call from popus controller
#Override
public void send(String data) {
label.setText(data);
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}
and then override implemented interface method and inside the method you can change Main window UI data I changed label text.
and then create variable in pupup controller with type DataSender(created interface befor) and create method to set that interface
public class PopUpController implements Initializable {
private int x;
//this is the variable
private DataSender dataSender;
#FXML
private Button btnOk;
#FXML
private TextField txtText;
#Override
public void initialize(URL url, ResourceBundle rb) {
btnOk.setOnAction(e->{
//When Click this button will call Main Window send method
dataSender.send(txtText.getText());
});
}
public void setX(int x){
this.x=x;
}
//this is the method to set variable value from Main Window
public void setSendDataSender(DataSender ds){
this.dataSender=ds;
}
}
and then when popup window button clicked then call send method with data and then will change main window label text.
This solution is work for me.hope this useful for you also .

How to add a javafx shortcut key combinations for buttons

My UI has a adding button and I want to assign a keyboard shortcut combination for that. I have failed to use the setAcceleartor for this purpose.
What is the easiest way to set up keyboard shortcuts in javafx applications?
button declaration in the UI:
<Button fx:id="addButton" alignment="CENTER" minWidth="-Infinity" mnemonicParsing="false" onAction="#addAction" prefHeight="31.0" prefWidth="130.0" text="Add" HBox.hgrow="ALWAYS" />
Controller button binding:
#FXML
private Button addButton;
The method that wants to setOnAction for the shortcut for the button:
public void addAction(ActionEvent event) throws SQLException, ClassNotFoundException {
if (validateInput()) {
String productName = productField.getText();
double unitPrice = Double.parseDouble(priceField.getText());
int quantity = Integer.parseInt(quantityField.getText());
double total = unitPrice * quantity;
ITEMLIST.add(new Item(productName, unitPrice, quantity, total));
calculation();
resetAdd();
productTableView.getSelectionModel().clearSelection();
ObservableList<Product> productsData = ProductDAO.searchProducts();
populateProducts(productsData);
searchField.setText("");
}
}
initialize() method:
#FXML
private void initialize() throws SQLException, ClassNotFoundException, IOException {
setSaveAccelerator(addButton);
}
The code I tried with setAccelerator:
private void setSaveAccelerator(final Button button) {
Scene scene = button.getScene();
if (scene == null) {
throw new IllegalArgumentException("setSaveAccelerator must be called when a button is attached to a scene");
}
scene.getAccelerators().put(
new KeyCodeCombination(KeyCode.S, KeyCombination.SHORTCUT_DOWN),
new Runnable() {
#FXML public void run() {
button.fire();
}
}
);
}
In your setSaveAccelerator method, instead of directly calling addAction(ActionEvent event), just instruct the button to fire its event to its listeners such as: button.fire(). For example:
private void setSaveAccelerator(Button button) {
if(button==null) {
System.out.println("Button is null! "); // check that the button was injected properly through your fxml
}
Scene scene = button.getScene();
if (scene == null) {
throw new IllegalArgumentException("setSaveAccelerator must be called when a button is attached to a scene");
}
scene.getAccelerators().put(
new KeyCodeCombination(KeyCode.S, KeyCombination.SHORTCUT_DOWN),
new Runnable() {
#FXML public void run() {
button.fire();
}
}
);
}
EDIT
To also avoid the IllegalArgumentException you must attach the accelerator after the button is attached to a scene. I managed to achieve this by creating a public method in the controller to attach the accelerator after the scene has been set. Then, in the class where the scene is loaded the controller's method can be called which sets up this functionality. See the example below:
In the controller class (in my case MainController):
public void setup() {
setSaveAccelerator(button);
}
In your main class when loading the fxml file:
FXMLLoader loader = new FXMLLoader(MainController.class.getResource("mainFXML.fxml"));
AnchorPane page = (AnchorPane) loader.load();
MainController controller = loader.getController();
Scene scene = new Scene(page);
controller.setup(); // calls the setup method attaching the accelerators
FULL EXAMPLE
Main class:
public class Main extends Application{
public static Stage primaryStage;
#Override
public void start(Stage primaryStage) throws Exception {
Main.primaryStage=primaryStage;
FXMLLoader loader = new FXMLLoader(MainController.class.getResource("mainFXML.fxml"));
AnchorPane page = (AnchorPane) loader.load();
MainController controller = loader.getController();
Scene scene = new Scene(page);
primaryStage.setTitle("Shortcut example");
primaryStage.setScene(scene);
controller.setup();
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Maincontroller:
public class MainController {
#FXML
private ResourceBundle resources;
#FXML
private URL location;
#FXML
private Button button;
#FXML
private AnchorPane rootPane;
#FXML
private TextArea textarea;
#FXML
void action(ActionEvent event) {
textarea.setText("Action fired!!");
}
#FXML
void initialize() {
assert button != null : "fx:id=\"button\" was not injected: check your FXML file 'MainFXML.fxml'.";
assert rootPane != null : "fx:id=\"rootPane\" was not injected: check your FXML file 'MainFXML.fxml'.";
assert textarea != null : "fx:id=\"textarea\" was not injected: check your FXML file 'MainFXML.fxml'.";
}
public void setup() {
setSaveAccelerator(button);
}
private void setSaveAccelerator(Button button) {
if(button==null) {
System.out.println("Button null!!");
}
Scene scene = button.getScene();
if (scene == null) {
throw new IllegalArgumentException("setSaveAccelerator must be called when a button is attached to a scene");
}
scene.getAccelerators().put(
new KeyCodeCombination(KeyCode.S, KeyCombination.SHORTCUT_DOWN),
new Runnable() {
#FXML public void run() {
button.fire();
}
}
);
}
}
MainFXML.fxml
<AnchorPane fx:id="rootPane" prefHeight="408.0" prefWidth="330.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.MainController">
<children>
<Button fx:id="button" layoutX="139.0" layoutY="350.0" mnemonicParsing="false" onAction="#action" text="Button" />
<TextArea fx:id="textarea" layoutX="73.0" layoutY="38.0" prefHeight="200.0" prefWidth="200.0" />
</children>
</AnchorPane>

On Mouse Entered Method to swap Button position

I would like to develop a mouse entered method that swaps the locations of two buttons in real time using FXML and JavaFX which I am unfortunately very new to. Relocate(x,y), get/setLayoutX/Y and below get/setTranslateX/Y all throw IllegalArgumentEceptions with not much more understandable information in the stack trace. What is the preferred Button Property to use in order to get and then set a real-time location swap?
#FXML protected void neinHover (ActionEvent evt){
double jTmpX, jTmpY, nTmpX, nTmpY;
nTmpX = neinButton.getTranslateX();
nTmpY = neinButton.getTranslateY();
jTmpX = jaButton.getTranslateX();
jTmpY = jaButton.getTranslateY();
jaButton.setTranslateX(nTmpX);
jaButton.setTranslateY(nTmpY);
neinButton.setTranslateX(jTmpX);
neinButton.setTranslateY(jTmpY);
}
I supose you want something like this:
FXML:
<fx:root onMouseClicked="#swap" type="Pane" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8">
<children>
<Button fx:id="b1" mnemonicParsing="false" text="1" />
<Button fx:id="b2" layoutX="90.0" mnemonicParsing="false" text="2" />
</children>
</fx:root>
Controller:
public class MockPane extends Pane {
#FXML
private Button b1;
#FXML
private Button b2;
public MockPane() {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource(
"MockPane.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
#FXML
private void swap() {
double b1x = b1.getLayoutX();
double b1y = b1.getLayoutY();
double b2x = b2.getLayoutX();
double b2y = b2.getLayoutY();
b1.setLayoutX(b2x);
b1.setLayoutY(b2y);
b2.setLayoutX(b1x);
b2.setLayoutY(b1y);
}
}
App:
public class MockApp extends Application {
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage stage) throws Exception {
MockPane root = new MockPane();
Scene scene = new Scene(root, 200, 100);
stage.setScene(scene);
stage.show();
}
}

External jar FXML Load Exception

I try to load a class located in an external jar using classloader. The class "FXMLbase" loads ok, but the error is triggered when the FXMLdocument.fxml try to instantiate the FXMLDocumentController. However when the "FXMLbase" is instantiate throught the JavaFXApplication5.java (located at the external jar) it works fine. Any Ideas?
Class Loader
File file = new File("C:/Users/Os/Dropbox/CODE_OS/JavaFXApplication5/dist/JavaFXApplication5.jar");
URLClassLoader clazzLoader = URLClassLoader.newInstance(new URL[]{file.toURI().toURL()}, this.getClass().getClassLoader());
Class c = clazzLoader.loadClass("javafxapplication5.FXMLbase");
PluginInterface fXMLbase = (PluginInterface) c.newInstance();
Parent loadScreen = fXMLbase.getRoot();
FXMLbase.java -- external jar --
public Parent getRoot() {
Parent root = null;
try {
System.out.println("Class Name:" + getClass().getName());
root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
} catch (IOException ex) {
Logger.getLogger(FXMLbase.class.getName()).log(Level.SEVERE, null, ex);
}
return root;
}
FXMLdocument.fxml -- external jar --
<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="javafxapplication5.FXMLDocumentController">
<children>
<Button fx:id="button" layoutX="126" layoutY="90" onAction="#handleButtonAction" text="Click Me! app5" />
<Label fx:id="label" layoutX="126" layoutY="120" minHeight="16" minWidth="69" />
</children>
FXMLDocumentController.java -- external jar --
public class FXMLDocumentController implements Initializable{
#FXML
private Label label;
#FXML
private void handleButtonAction(ActionEvent event) {
System.out.println("You clicked me!");
label.setText("Hello World!");
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}
JavaFxApplication5.java -- external jar --
public void start(Stage stage) throws Exception {
FXMLbase fXMLbase=new FXMLbase();
Parent root = fXMLbase.getRoot();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
Error:
ago 28, 2014 2:26:16 PM javafxapplication5.FXMLbase getRoot
SEVERE: null
javafx.fxml.LoadException:
file:/C:/Users/Os/Dropbox/CODE_OS/JavaFXApplication5/dist/JavaFXApplication5.jar!/javafxapplication5/FXMLDocument.fxml:9
....
Caused by: java.lang.ClassNotFoundException: javafxapplication5.FXMLDocumentController
The FXMLLoader at some point has to load the controller class from the value of the fx:controller attribute in the root element of the FXML file. It looks like it is using the system class loader to do this: I think this is because the system class loader finds the FXMLLoader class and loads it, rather than the class loader used to load your FXMLBase class.
The only fix I can find for this is to explicitly set the controller class from the FXMLbase class, instead of specifying it in the FXML. This is a bit unsatisfactory; perhaps there is a better way I am missing.
Updated FXMLbase class:
public Parent getRoot() {
Parent root = null;
try {
System.out.println("Class Name:" + getClass().getName());
FXMLLoader loader = new FXMLLoader(getClass().getResource("FXMLDocument.fxml"));
loader.setController(new FXMLDocumentController());
root = loader.load();
} catch (IOException ex) {
Logger.getLogger(FXMLbase.class.getName()).log(Level.SEVERE, null, ex);
}
return root;
}
and you need to remove the fx:controller attribute from the FXML file.

Resources