I'm writing an music player and I can't link my Observable Array with TableView defined in controller. When project runned, I get NullPointerException on line under comment. I don't know what is making it happen and how find way around this problem.
Main.java
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.SplitPane;
import javafx.stage.Stage;
public class Main extends Application {
ObservableList<CModel> modelData = FXCollections.observableArrayList();
#Override
public void start(Stage primaryStage) {
try {
FXMLLoader loader = new FXMLLoader();
SplitPane root = FXMLLoader.load(getClass().getResource("Player.fxml"));
Scene scene = new Scene(root);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
PlayerController controller = loader.getController();
//this line gives exception
controller.setData(this);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public ObservableList<CModel> getPersonData() {
return modelData;
}
public static void main(String[] args) {
launch(args);
}
}
PlayerController.java
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Menu;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
public class PlayerController {
#FXML
private TableView<CModel> cTable;
#FXML
private TableColumn<CModel, String> artCol;
#FXML
private TableColumn<CModel, String> albCol;
#FXML
private TableColumn<CModel, String> trNameCol;
#FXML
private TableColumn<CModel, String> trNoCol;
#FXML
private TableColumn<CModel, String> durCol;
#FXML
private Menu addFile;
#FXML
private Menu addFolder;
#FXML
private Menu savePlayL;
#FXML
private Menu loadPlayL;
private Files files;
private Main main;
public PlayerController() {
}
#FXML
private void initialize() {
artCol.setCellValueFactory(
new PropertyValueFactory<CModel,String>("artistName")
);
albCol.setCellValueFactory(
new PropertyValueFactory<CModel,String>("albumName")
);
trNameCol.setCellValueFactory(
new PropertyValueFactory<CModel,String>("trackName")
);
trNoCol.setCellValueFactory(
new PropertyValueFactory<CModel,String>("trackDurationName")
);
durCol.setCellValueFactory(
new PropertyValueFactory<CModel,String>("trackNumberName")
);
}
#FXML
protected void handleAddFile(ActionEvent event) {
files = new Files();
files.openFile();
}
public void setData(Main mainApp) {
this.main = mainApp;
cTable.setItems(main.getPersonData());
}
}
You need to call loader.load() method of instantiated object, instead of using static method, before getting controller, take a look here for details.
There are few things to be considered here. In order to get the controller, you need to remember the following things :
Use the FXMLoader reference to load the FXML
Call the non-static load method. Inorder to do that pass a InputStream as a parameter.
Inside your Main.Java, you should have :
FXMLLoader loader = new FXMLLoader();
SplitPane root = (SplitPane)loader.load(getClass().getResource("Player.fxml").openStream());
If you don't want to use InputStream, you can also pass the resource in the constructor and call the non-staic load() method
FXMLLoader loader = new FXMLLoader(getClass().getResource("Player.fxml"));
SplitPane root = (SplitPane)loader.load();
Related
I'm new to Java and JavaFX. As a first project I try to make an adress book but I am getting a problem which I can't resolve.
I have a MainClass which opens a window where the user can select to search a Person or add a Person. I also have a second window which opens when the Person, which the user enters by first- and last name is found and displays the Person's details. This window provides a button which opens another (a third) window where the user can change the details. All the information is stored in a Arzt.java class which contains an ObservableList.
My Problem is that any changes I apply aren't saved in the Arzt.java class ObservableList.
I hope you can help me there. Help is much appreciated!
App.java (MainClass):
package com.mycompany.doktorenkartei;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
public class App extends Application {
private Scene scene;
private Stage stage;
#Override
public void start(Stage stage) throws IOException {
this.stage = stage;
showStartpage();
}
public void showStartpage() throws IOException {
try {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(App.class.getResource("startpage.fxml"));
scene = new Scene(loader.load());
stage.setScene(scene);
stage.setResizable(false);
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
Controller of the first window:
package com.mycompany.doktorenkartei;
import java.io.IOException;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.stage.Stage;
public class StartpageController {
#FXML
private Button findDocWindow;
#FXML
private Button addDocWindow;
#FXML
private void findDoctorWindow() throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("arztSuchen.fxml"));
Parent root = (Parent) fxmlLoader.load();
Stage stage = new Stage();
stage.setTitle("Suche");
stage.setScene(new Scene(root));
stage.show();
}
#FXML
private void addDoctorWindow() {
System.out.println("Button works also");
}
}
Controller of the searchwindow:
package com.mycompany.doktorenkartei;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
public class ArztSuchenController implements Initializable {
private Kartei kartei;
#FXML
private TextField fieldNachname;
#FXML
private TextField fieldVorname;
#FXML
private Button searchButton;
#Override
public void initialize(URL location, ResourceBundle resources){
kartei = new Kartei();
}
public void setKartei(Kartei kartei){
this.kartei = kartei;
}
public ArztSuchenController(){
}
#FXML
void searchForDoctor(ActionEvent event) throws IOException {
String vorname = fieldVorname.getText();
String name = fieldNachname.getText();
if (this.kartei.arztExsist(vorname, name)) {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("arztFenster.fxml"));
Parent root1 = loader.load();
Stage stage = new Stage();
stage.setScene(new Scene(root1));
ArztFensterController controller = loader.getController();
controller.showInformations(this.kartei.getArzt(vorname, name));
//closing stage if Arzt found
Stage stageSuchen = (Stage) searchButton.getScene().getWindow();
stageSuchen.close();
stage.show();
} else {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("nichtGefundenFenster.fxml"));
Parent root1 = loader.load();
Stage stage = new Stage();
stage.setScene(new Scene(root1));
stage.show();
}
}
}
Controller of the Window where details are changed:
package com.mycompany.doktorenkartei;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
public class ArztBearbeitenController {
private Arzt ausgewählterArzt;
#FXML
private Button speichern;
#FXML
private TextArea textAnmerkung;
#FXML
private TextField textApprobation;
#FXML
private TextField textArbeitsbegin;
#FXML
private TextField textBerufstätig;
#FXML
private TextField textBundesland;
#FXML
private TextField textErhaltRate;
#FXML
private TextField textFacharzt;
#FXML
private TextField textFamilienstand;
#FXML
private TextField textGeburtstag;
#FXML
private TextField textHeimatadresse;
#FXML
private TextField textImpfstatus;
#FXML
private TextField textNachname;
#FXML
private TextField textName;
#FXML
private TextField textNationalität;
#FXML
private TextField textSprachkurs;
#FXML
private TextField textSprachniveau;
#FXML
private TextField textStudium;
#FXML
private TextField textUnterkunft;
#FXML
private TextField textVisum;
public ArztBearbeitenController() {
}
#FXML
void saveTextfield(ActionEvent event) {
this.ausgewählterArzt.setVorname(textName.getText());
this.ausgewählterArzt.setNachname(textNachname.getText());
this.ausgewählterArzt.setGeburtsdatum(textGeburtstag.getText());
this.ausgewählterArzt.setNationalität(textNationalität.getText());
this.ausgewählterArzt.setFamilienstand(textFamilienstand.getText());
this.ausgewählterArzt.setHeimatadresse(textHeimatadresse.getText());
this.ausgewählterArzt.setAdresseUnterkunft(textUnterkunft.getText());
this.ausgewählterArzt.setVisum(textVisum.getText());
this.ausgewählterArzt.setImpfstatus(textImpfstatus.getText());
this.ausgewählterArzt.setSprachniveau(textSprachniveau.getText());
this.ausgewählterArzt.setBerufstätig(textBerufstätig.getText());
this.ausgewählterArzt.setBundesland(textBundesland.getText());
this.ausgewählterArzt.setSprachkurs(textSprachkurs.getText());
this.ausgewählterArzt.setFacharzt(textFacharzt.getText());
this.ausgewählterArzt.setApprobation(textApprobation.getText());
this.ausgewählterArzt.setStudium(textStudium.getText());
this.ausgewählterArzt.setArbeitsbegin(textArbeitsbegin.getText());
this.ausgewählterArzt.setErhaltRate(textErhaltRate.getText());
this.ausgewählterArzt.setAnmerkungen(textAnmerkung.getText());
}
public void fillTextfields(Arzt arzt) {
this.ausgewählterArzt = arzt;
textName.setText(arzt.getVornameString());
textNachname.setText(arzt.getNachnameString());
textGeburtstag.setText(arzt.getGeburtsdatumString());
textNationalität.setText(arzt.getNationalitätString());
textFamilienstand.setText(arzt.getFamilienstandString());
textHeimatadresse.setText(arzt.getHeimatadresseString());
textUnterkunft.setText(arzt.getAdresseUnterkunftString());
textVisum.setText(arzt.getVisumString());
textImpfstatus.setText(arzt.getImpfstatusString());
textSprachniveau.setText(arzt.getSprachniveauString());
textBerufstätig.setText(arzt.getBerufstätigString());
textBundesland.setText(arzt.getBundeslandString());
textSprachkurs.setText(arzt.getSprachkursString());
textFacharzt.setText(arzt.getFacharztString());
textApprobation.setText(arzt.getApprobationString());
textStudium.setText(arzt.getStudiumString());
textArbeitsbegin.setText(arzt.getArbeitsbeginString());
textErhaltRate.setText(arzt.getErhaltRateString());
textAnmerkung.setText(arzt.getAnmerkungenString());
}
}
The class where the Data should be stored(temporary, in future saved as xml file):
package com.mycompany.doktorenkartei;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
public class Kartei {
private ObservableList<Arzt> kartei = FXCollections.observableArrayList();
#FXML private ArztSuchenController suchenController;
#FXML private ArztFensterController arztController;
public Kartei() {
//data for testing
kartei.add(new Arzt("Nelson", "Mandela"));
kartei.add(new Arzt("Isaac", "Newton"));
kartei.add(new Arzt("Josepe", "Trymeout"));
}
public ObservableList<Arzt> getKartei() {
return this.kartei;
}
#FXML private void initialize(){
suchenController.setKartei(this);
}
public boolean arztExsist(String vorname, String nachname) {
for (Arzt e : this.kartei) {
if (e.getVornameString().equalsIgnoreCase(vorname) && e.getNachnameString().equalsIgnoreCase(nachname)) {
return true;
}
}
return false;
}
public Arzt getArzt(String vorname, String nachname) {
for (Arzt e : this.kartei) {
if (e.getVornameString().equalsIgnoreCase(vorname) && e.getNachnameString().equalsIgnoreCase(nachname)) {
return e;
}
}
return null;
}
}
The Person Class:
package com.mycompany.doktorenkartei;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class Arzt {
private StringProperty vorname;
private StringProperty nachname;
private StringProperty geburtsdatum;
private StringProperty nationalität;
private StringProperty familienstand;
private StringProperty heimatadresse;
private StringProperty adresseUnterkunft;
private StringProperty visum;
private StringProperty impfstatus;
private StringProperty Sprachniveau;
private StringProperty berufstätig;
private StringProperty facharzt;
private StringProperty approbation;
private StringProperty studium;
private StringProperty bundesland;
private StringProperty sprachkurs;
private StringProperty arbeitsbegin;
private StringProperty erhaltRate;
private StringProperty anmerkungen;
public Arzt(String vorname, String nachname) {
this.vorname = new SimpleStringProperty(vorname);
this.nachname = new SimpleStringProperty(nachname);
//dummyData
this.geburtsdatum = new SimpleStringProperty("asdasdasd");
this.nationalität = new SimpleStringProperty("asdasdasd");
this.familienstand = new SimpleStringProperty("asdasdasd");
this.heimatadresse = new SimpleStringProperty("asdasdasd");
this.adresseUnterkunft = new SimpleStringProperty("asdasdasd");
this.visum = new SimpleStringProperty("asdasdasd");
this.impfstatus = new SimpleStringProperty("asdasdasd");
this.Sprachniveau = new SimpleStringProperty("asdasdasd");
this.berufstätig = new SimpleStringProperty("asdasdasd");
this.facharzt = new SimpleStringProperty("asdasdasd");
this.approbation = new SimpleStringProperty("asdasdasd");
this.studium = new SimpleStringProperty("asdasdasd");
this.bundesland = new SimpleStringProperty("asdasdasd");
this.sprachkurs = new SimpleStringProperty("asdasdasd");
this.arbeitsbegin = new SimpleStringProperty("asdasdasd");
this.erhaltRate = new SimpleStringProperty("asdasdasd");
this.anmerkungen = new SimpleStringProperty("asdasdasd");
}
// getters and setters
Assuming your getters and setters are correct, you probably forgot to set the on-action function of your button.
You can do that in your fxml file by adding an "onAction" argument like this:
<Button text="Save" onAction=#saveTextfield/>
Or you can do that in your SceneBuilder like this:
If this is not the problem, maybe show your getters and setters, and provide a minimal reproducable example.
(I should probably write this as a comment and not an answer, but I don't have 50 rep yet.)
I have desktop app with side menu bar. Main window is BorderPane with InsertLeft containing VBox. I set Hbox buttons and their behaviour then I add them one by one to the VBox. InsertCenter has just Pane with alot of elements.
I've created 3 fxml files for each GUI layout.
sample.fxml - BorderPane: InsertLeft->Menu(VBox), InsertCenter->Empty Pane
tab1_content.fxml - Pane filled with ProgressBar, Labels and Buttons
tab2_content.fxml - Not yet implemented (Empty Pane)
Each of these fxml files has their controllers.
I would like to switch content of borderPane.center() inside sample.fxml on menu button click.
I've managed to fix some issues, but main problem is with loading data into .fxml views.
As I run my App it works perfectly, each fxml file has his FXMLLoader which will load content into borderPane right inside main Controller.
Problem occurs while I click on Buttons. It will switch panes, but actual content will reset to default state and Main.class initialization is completely ignored. Button listeners and label values are not initialized. It's just empty fxml layout. Every variable inside Main.class, what I want to access from Tab1Controller is returning NullPointerException - even methods.
Each controller extends AbstractController, which contains Main.class instance which is initialized inside start() method. So i should be able to have access to every Main.class method/variable at any time.
Issue Gif:
Some code samples:
My Main.class start() method:
public Controller myController;
#Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/sample.fxml"));
myController = new Controller();
myController.setMainApp(this);
loader.setController(myController);
Parent root = loader.load();
primaryStage.setTitle("Simple App");
primaryStage.setScene(new Scene(root));
primaryStage.show();
<other stuff>
}
public void setDefaultViewProperties(){
currentScanningFileProperty = new SimpleStringProperty();
myController.tab1Controller.actualPath.textProperty().bind(currentScanningFileProperty); //NullPointerException while called from Controller
fileCounterProperty = new SimpleLongProperty();
myController.tab1Controller.numOfScanned.textProperty().bind(fileCounterProperty.asString());
maliciousFilesCounterProperty = new SimpleIntegerProperty();
myController.tab1Controller.numOfMaliciousFiles.textProperty().bind(maliciousFilesCounterProperty.asString());
myController.tab1Controller.fileChoiceBtn.setOnMouseClicked(event -> chooseFile());
myController.tab1Controller.runScanBtn.setOnMouseClicked(event -> new Thread(() -> {
try {
resetValues();
startFileWalking(chosenFile);
} catch (IOException e) {
e.printStackTrace();
}
}).start());
}
MainController:
package sample;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.geometry.Insets;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
public class Controller extends AbstractController implements Initializable{
public HBox sideMenu;
public VBox mainMenu;
public BorderPane borderPane;
public Boolean isButton1Pressed = false;
public Boolean isButton2Pressed = false;
public static final String TAB_1 = "TAB-1";
public static final String TAB_2 = "TAB-2";
public Button malwareButton;
public Button webShieldButton;
public Tab1Controller tab1Controller;
public Tab2Controller tab2Controller;
#Override
public void initialize(URL location, ResourceBundle resources) {
createMenuButtons();
setSideMenu();
setMenuButtonsListeners();
}
private void setSideMenu(){
mainMenu.getChildren().add(item(malwareButton));
mainMenu.getChildren().add(item(webShieldButton));
mainMenu.setStyle("-fx-background-color:#004D40");
}
private HBox item(Button menuButton){
menuButton.setPrefSize(200, 50);
menuButton.setStyle("-fx-background-color: transparent;");
menuButton.setTextFill(Color.web("#E0F2F1"));
menuButton.setPadding(Insets.EMPTY);
sideMenu = new HBox(menuButton);
return sideMenu;
}
public void setMenuButtonsListeners(){
malwareButton.setOnMousePressed(event -> {
setButtonStylePressed(malwareButton);
setButtonStyleUnpressed(webShieldButton);
isButton1Pressed = true;
isButton2Pressed = false;
loadTab1Content();
main.setDefaultViewProperties();
});
webShieldButton.setOnMousePressed(event -> {
setButtonStylePressed(webShieldButton);
setButtonStyleUnpressed(malwareButton);
isButton1Pressed = false;
isButton2Pressed = true;
loadTab2Content();
});
malwareButton.setOnMouseExited(event -> {
if(!isButton1Pressed){
setButtonStyleUnpressed(malwareButton);
}
});
webShieldButton.setOnMouseExited(event -> {
if(!isButton2Pressed){
setButtonStyleUnpressed(webShieldButton);
}
});
malwareButton.setOnMouseEntered(event -> setButtonStylePressed(malwareButton));
webShieldButton.setOnMouseEntered(event -> setButtonStylePressed(webShieldButton));
}
public void setButtonStylePressed(Button btn){
btn.setStyle("-fx-background-color: #E0F2F1");
btn.setTextFill(Color.web("#004D40"));
}
public void setButtonStyleUnpressed(Button btn){
btn.setStyle("-fx-background-color: transparent");
btn.setTextFill(Color.web("#E0F2F1"));
}
private void loadTab1Content(){
FXMLLoader tab1loader = new FXMLLoader();
tab1loader.setLocation(getClass().getResource("/tab_1_content.fxml"));
try {
if (tab1Controller == null){
tab1Controller = new Tab1Controller();
}
tab1loader.setController(tab1Controller);
borderPane.setCenter(tab1loader.load());
} catch (IOException e) {
e.printStackTrace();
}
}
private void loadTab2Content(){
FXMLLoader tab2loader = new FXMLLoader();
tab2loader.setLocation(getClass().getResource("/tab_2_content.fxml"));
try {
if (tab2Controller == null){
tab2Controller = new Tab2Controller();
}
tab2loader.setController(tab2Controller);
borderPane.setCenter(tab2loader.load());
} catch (IOException e) {
e.printStackTrace();
}
}
private void createMenuButtons(){
malwareButton = new Button();
malwareButton.setText(TAB_1);
webShieldButton = new Button();
webShieldButton.setText(TAB_2);
}
}
Tab1Controller:
package sample;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.stage.Modality;
import javafx.stage.Stage;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.ResourceBundle;
/**
* Created by admin on 5. 5. 2018.
*/
public class Tab1Controller extends AbstractController implements Initializable {
public ProgressBar progressBar;
public Button runScanBtn;
public Button fileChoiceBtn;
public Label chosenPath;
public Label actualPath;
public Label numOfMaliciousFiles;
public Label hashValue;
public Label scanFinishedMsg;
public Label numOfScanned;
public Button showFoundMalwareButton;
#Override
public void initialize(URL location, ResourceBundle resources) {
runScanBtn.setDisable(true);
scanFinishedMsg.setVisible(false);
showFoundMalwareButton.setVisible(false);
showFoundMalwareButton.setOnAction(event -> showPopupWindow());
}
Update#1 - Updating fxml values through Main.class after button click
I've finally managed to run app without exception. I had to create next Controller for pane fxml layout itself called Tab1Controller. When I initialized Controller, it instantly initialized Tab1Controller inside. So when I want to change Center BorderPane label i had to call myController.tab1Controller.tabLabel.setText()
I don't know if it's good approach to this problem.
But now I'm back to my old problem. When I click on TAB-1 it will load content, but values are not initialized to default state.
For example I have couple of labels updated in real time. I binded some SimpleProperties into it with default values. It worked before, but as I have three controllers it will load data for a first time, but when I click TAB-1 button it will load just fxml content, but it will not set those labels.
So i made public method inside Main.class which I will call everytime I switch to TAB-1 from Controller.
public void setDefaultViewProperties(){
myController.tab1Controller.actualPath.textProperty().bind(currentScanningFileProperty);
myController.tab1Controller.numOfScanned.textProperty().bind(fileCounterProperty.asString());
myController.tab1Controller.numOfMaliciousFiles.textProperty().bind(maliciousFilesCounterProperty.asString());
}
But now everytime I click on TAB-1 I've got
java.lang.NullPointerException: Cannot bind to null
You can make two pane and switch between them using setVisible() method
example:
void btn1Clicked() {
pane1.setVisible(true);
pane2.setVisible(false);
}
void btn2Clicked() {
pane1.setVisible(false);
pane2.setVisible(true);
}
You could use a TabPane to achieve this behaviour:
https://docs.oracle.com/javase/8/javafx/api/javafx/scene/control/TabPane.html
Solved. I'm not sure how, but setDefaultViewProperties() are not throwing NullPointerException at the moment. I did not change anything inside the code:
malwareButton.setOnMousePressed(event -> {
setButtonStylePressed(malwareButton);
setButtonStyleUnpressed(webShieldButton);
isButton1Pressed = true;
isButton2Pressed = false;
loadTab1Content();
main.setDefaultViewProperties();
});
I have following code:
package pl.javastart.youtufy.controller;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ToggleButton;
import javafx.scene.web.WebEngine;
import javafx.stage.Stage;
public class ConnectionErrorController implements Initializable {
#FXML
private Label infoLabel;
#FXML
private Button tryButton;
#FXML
private Button exitButton;
#Override
public void initialize(URL location, ResourceBundle resources) {
MainController mc = new MainController();
infoLabel.setText("Connection lost, please try again");
tryButton.setText("try again");
exitButton.setText("exit");
tryButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
WebEngine webEngine = mc.getContentPaneController().getVideoWebView().getEngine(); // 1
ToggleButton playButton = mc.getControlPaneController().getPlayButton(); // 2
Node source = (Node) event.getSource();
Stage stage = (Stage) source.getScene().getWindow();
if (mc.testInet()) {
stage.close();
mc.play(webEngine, playButton);
} else {
stage.close();
MainController.exist = false;
}
}
});
exitButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
Platform.exit();
}
});
}
}
I am trying to use WebEngine and ToggleButton Objects from controllers in MainController (I generated getters and setters to them in MainController):
public class MainController implements Initializable {
#FXML
private ContentPaneController contentPaneController;
#FXML
private ControlPaneController controlPaneController;
#FXML
private MenuPaneController menuPaneController;
#FXML
private SearchPaneController searchPaneController;
private Youtube youtubeInstance;
public static boolean exist = false;
public ControlPaneController getControlPaneController() {
return controlPaneController;
}
public void setControlPaneController(ControlPaneController controlPaneController) {
this.controlPaneController = controlPaneController;
}
public ContentPaneController getContentPaneController() {
return contentPaneController;
}
public void setContentPaneController(ContentPaneController contentPaneController) {
this.contentPaneController = contentPaneController;
}
But its still returns NullPointerException. I had same problem, when I tried simply make references to the controllers in ConnectionErrorController. How to refer to the ToggleButton i WebEngine Objects from controllers in ConnectionErrorController properly?
Regards
You are creating a controller instance "by hand" with
MainController mc = new MainController();
#FXML-annotated fields are initialized by the FXMLLoader when it creates the controller for you as part of the process of loading the FXML file. Since the controller you created is not the controller instance created by the FXMLLoader, its #FXML-annotated fields are uninitialized (i.e. they are null), and hence you get a null pointer exception.
You can get a reference to the controller created by the FXMLLoader by calling getController() on the FXMLLoader instance after calling load().
If you want one controller to communicate with another, then pass the reference to one controller to the other controller, by defining appropriate methods in the second controller:
public class ConnectionErrorController implements Initializable {
private MainController mainController ;
public void setMainController(MainController mainController) {
this.mainController = mainController ;
}
// ...
#Override
public void initialize(URL location, ResourceBundle resources) {
infoLabel.setText("Connection lost, please try again");
tryButton.setText("try again");
exitButton.setText("exit");
tryButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
WebEngine webEngine = mainController.getContentPaneController().getVideoWebView().getEngine(); // 1
ToggleButton playButton = mainController.getControlPaneController().getPlayButton(); // 2
if (mainController.testInet()) {
mainController.play(webEngine, playButton);
} else {
// obviously you can now do something better than the "public static field hack" here:
MainController.exist = false;
}
tryButton.getScene().getWindow().hide();
}
});
// ...
}
}
Assuming you are loading the second fxml file in a method in MainController, you can then just do something like:
public class MainController {
// ...
public void showConnectionErrorWindow(String fileName) {
FXMLLoader loader = new FXMLLoader(getClass().getResource("path/to/ConnectionError.fxml"));
Parent root = loader.load();
ConnectionErrorController connectionErrorController = loader.getController();
connectionErrorController.setMainController(this);
Scene scene = new Scene(root);
Stage stage = new Stage();
// etc...
}
// ...
}
Note that there are much more elegant ways of solving this problem, such as passing the ConnectionErrorController a callback function (in the form of a lambda expression) to process the call to play(...), which avoid the tight coupling between the ConnectionErrorController and the MainController. However, as you seem to be new to Java, this simpler approach might be more suitable.
See Passing Parameters JavaFX FXML for more information on passing values to controllers.
I have following code:
package pl.javastart.youtufy.controller;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ToggleButton;
import javafx.scene.web.WebEngine;
import javafx.stage.Stage;
public class ConnectionErrorController implements Initializable {
#FXML
private Label infoLabel;
#FXML
private Button tryButton;
#FXML
private Button exitButton;
#Override
public void initialize(URL location, ResourceBundle resources) {
MainController mc = new MainController();
infoLabel.setText("Connection lost, please try again");
tryButton.setText("try again");
exitButton.setText("exit");
tryButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
WebEngine webEngine = mc.getContentPaneController().getVideoWebView().getEngine(); // 1
ToggleButton playButton = mc.getControlPaneController().getPlayButton(); // 2
Node source = (Node) event.getSource();
Stage stage = (Stage) source.getScene().getWindow();
if (mc.testInet()) {
stage.close();
mc.play(webEngine, playButton);
} else {
stage.close();
MainController.exist = false;
}
}
});
exitButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
Platform.exit();
}
});
}
}
I am trying to use WebEngine and ToggleButton Objects from controllers in MainController (I generated getters and setters to them in MainController):
public class MainController implements Initializable {
#FXML
private ContentPaneController contentPaneController;
#FXML
private ControlPaneController controlPaneController;
#FXML
private MenuPaneController menuPaneController;
#FXML
private SearchPaneController searchPaneController;
private Youtube youtubeInstance;
public static boolean exist = false;
public ControlPaneController getControlPaneController() {
return controlPaneController;
}
public void setControlPaneController(ControlPaneController controlPaneController) {
this.controlPaneController = controlPaneController;
}
public ContentPaneController getContentPaneController() {
return contentPaneController;
}
public void setContentPaneController(ContentPaneController contentPaneController) {
this.contentPaneController = contentPaneController;
}
But its still returns NullPointerException. I had same problem, when I tried simply make references to the controllers in ConnectionErrorController. How to refer to the ToggleButton i WebEngine Objects from controllers in ConnectionErrorController properly?
Regards
You are creating a controller instance "by hand" with
MainController mc = new MainController();
#FXML-annotated fields are initialized by the FXMLLoader when it creates the controller for you as part of the process of loading the FXML file. Since the controller you created is not the controller instance created by the FXMLLoader, its #FXML-annotated fields are uninitialized (i.e. they are null), and hence you get a null pointer exception.
You can get a reference to the controller created by the FXMLLoader by calling getController() on the FXMLLoader instance after calling load().
If you want one controller to communicate with another, then pass the reference to one controller to the other controller, by defining appropriate methods in the second controller:
public class ConnectionErrorController implements Initializable {
private MainController mainController ;
public void setMainController(MainController mainController) {
this.mainController = mainController ;
}
// ...
#Override
public void initialize(URL location, ResourceBundle resources) {
infoLabel.setText("Connection lost, please try again");
tryButton.setText("try again");
exitButton.setText("exit");
tryButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
WebEngine webEngine = mainController.getContentPaneController().getVideoWebView().getEngine(); // 1
ToggleButton playButton = mainController.getControlPaneController().getPlayButton(); // 2
if (mainController.testInet()) {
mainController.play(webEngine, playButton);
} else {
// obviously you can now do something better than the "public static field hack" here:
MainController.exist = false;
}
tryButton.getScene().getWindow().hide();
}
});
// ...
}
}
Assuming you are loading the second fxml file in a method in MainController, you can then just do something like:
public class MainController {
// ...
public void showConnectionErrorWindow(String fileName) {
FXMLLoader loader = new FXMLLoader(getClass().getResource("path/to/ConnectionError.fxml"));
Parent root = loader.load();
ConnectionErrorController connectionErrorController = loader.getController();
connectionErrorController.setMainController(this);
Scene scene = new Scene(root);
Stage stage = new Stage();
// etc...
}
// ...
}
Note that there are much more elegant ways of solving this problem, such as passing the ConnectionErrorController a callback function (in the form of a lambda expression) to process the call to play(...), which avoid the tight coupling between the ConnectionErrorController and the MainController. However, as you seem to be new to Java, this simpler approach might be more suitable.
See Passing Parameters JavaFX FXML for more information on passing values to controllers.
I know how to parse variables to controllers in JavaFX with fxml. But i need to use them in the initialize method of my controller. Is there a ways to do this? The background is, that i have a interface, where you can define different settings. Now you can safe them and have to be able to reopen them. So now when i open a rule, i need to set the values in the new option view. I know, that it works on text fields (UI-Elements) to set Text during initialize but not for variables. I tried different approaches. Like binding with properties (works for visibility property of button (UI-Element) but not for variables to set. Do you know a way or maybe an other approach?
Here is my example:
Controller1:
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.stage.Stage;
/**
*
* #author Sandro
*/
public class FXMLDocumentController implements Initializable {
#FXML
private Button btn_openWindow;
#FXML
private void handleButtonAction(ActionEvent event) {
try {
Stage stage = new Stage();
FXMLLoader loader = new FXMLLoader();
Parent root = loader.load(getClass().getResource("fxml_second.fxml").openStream());
Fxml_secondController cont = (Fxml_secondController)loader.getController();
cont.setFlag(0x00000002);
cont.setIsChange(false);
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
} catch (IOException ex) {
Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
}
}
#Override
public void initialize(URL url, ResourceBundle rb) {
btn_openWindow.setOnAction(this::handleButtonAction);
}
Controller 2:
/**
* FXML Controller class
*
* #author Sandro
*/
public class Fxml_secondController implements Initializable {
#FXML private Button btn_printOut;
private boolean isChange = true;
private int flag = 0x00000001;
private void printOut(ActionEvent event){
System.out.println("isChange: "+isChange);
System.out.println("flag: "+flag);
}
public boolean isIsChange() {
return isChange;
}
public void setIsChange(boolean isChange) {
this.isChange = isChange;
}
public int getFlag() {
return flag;
}
public void setFlag(int flag) {
this.flag = flag;
}
#Override
public void initialize(URL url, ResourceBundle rb) {
btn_printOut.setOnAction(this::printOut);
System.out.println(flag);
}
In controller 2 you see the problem. The console-output in initialize shows 1 but it need to show 2. If i klick on printOut (Button) it prints out the right values which i have set in Controller 1.
Set the controller in the Java code, instead of in FXML.
Remove the fx:controller attribute from fxml_second.fxml, and change the code in FXMLDocumentController as follows:
#FXML
private void handleButtonAction(ActionEvent event) {
try {
Stage stage = new Stage();
FXMLLoader loader = new FXMLLoader(getClass().getResource("fxml_second.fxml"));
Fxml_secondController cont = new Fxml_secondController();
cont.setFlag(0x00000002);
cont.setIsChange(false);
loader.setController(cont);
Parent root = loader.load();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
} catch (IOException ex) {
Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
}
}
Another option would be to use a custom component approach for the second fxml.