Why does method called from another controller dont change the scene? - java

I got scene first.fxml with firstController, it is BorderPane with one button(birthCert) in the left side.
When i click on button(birthCert) i succefully load second.fxml into center of BorderPane.
#FXML
void birthCert(ActionEvent event) {
Parent root;
try {
root = load(getClass().getResource("second.fxml"));
id_borderPane.setCenter(root);
} catch (IOException e) {
e.printStackTrace();
}
}
second.fxml is conected with secondController class and have 1 button(sendRequest). When this button is clicked i create instance of firstController and i want call method setscene to load third.fxml into center of borderPane.
third.fxml only show message "Your request was sent".
Problem is, when i call method setscene in class secondController with instance of firstController
c.setscene();
public void setscene() {
Parent root;
try {
root = load(getClass().getResource("third.fxml"));
id_borderPane.setCenter(root);
} catch (IOException e) {
e.printStackTrace();
}
}
it don't load third.fxml into center of BorderPane, nothing happens just second.fxml remains loaded.
I tried control printing and i tested if root is null but printing works fine and root is not null so i really don't understand what can cause that it doesn't show third.fxml in center of BorderPane
Here is the whole code:
package controllers;
import static javafx.fxml.FXMLLoader.load;
import java.io.IOException;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Parent;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
public class firstController {
#FXML
private BorderPane id_borderPane;
#FXML
void birthCert(ActionEvent event) {
Parent root;
try {
root = load(getClass().getResource("second.fxml"));
id_borderPane.setCenter(root);
} catch (IOException e) {
e.printStackTrace();
}
}
public void setscene() {
Parent root;
try {
root = load(getClass().getResource("third.fxml"));
id_borderPane.setCenter(root);
} catch (IOException e) {
e.printStackTrace();
}
}
}
package controllers;
import java.io.IOException;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.control.TextArea;
import javafx.scene.input.MouseEvent;
public class secondController{
#FXML
void SendRequset(MouseEvent event) throws IOException {
FXMLLoader loader = new FXMLLoader(getClass().getResource("first.fxml"));
loader.load();
UserGUISendReqController c = loader.getController(); // instance of firstController
c.setscene();
}
}
Thank you a lot for help :)

You have:
FirstController
|- SecondController
Then in second controller you click the button to add third controller you're doing
FirstController
|- SecondController
|- new FirstController.setScene()
You should instantiate a new FirstController, you should either call up to SecondController parent, or pass the references to FirstController into second controller somehow.
You want to use either getParent on SecondController or some other method of passing the active FirstController into the SecondController so that when you call to it, it's the right one.
ps. People will also comment on your naming convention not following standards.

Related

Cannot get both radio buttons to pass values to ObaservableList Java?

I am in the process of learning Java and I can't seem to make this function work. I am working on a project for an inventory system. Where parts are added to an observable list. In the add part screen, I have two radio buttons to select whether the part is an InHouse made or OutSourced. I have an if statement using a toggle group to check which radio button is selected. I was trying to use an else statement to pass the values if it was an outsourced part. Right now it will pass the values correctly if the radio button is set to InHouse, but when set to Outsource it throws a null pointer exception at the line the if statement is on.
Here is the code I am trying to make work.
package ViewController;
import Model.InHouse;
import Model.Inventory;
import Model.OutSource;
import Model.Part;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.input.MouseEvent;
import javafx.stage.Stage;
import java.io.IOException;
import java.net.URL;
import java.util.Optional;
import java.util.ResourceBundle;
public class AddPart implements Initializable {
public RadioButton addPartInHouse;
public TextField partIDTxtbox;
public TextField partNameTxtbox;
public TextField invTxtbox;
public TextField pricePerUnitTxtbox;
public TextField maxQtyTxtbox;
public TextField minQtyTxtbox;
public Button addPartSaveButton;
public Button addPartCancelButton;
public RadioButton addPartOutSource;
public Label companyNameLabel;
public TextField companyNamePrompt;
public ToggleGroup switchfield;
public void addPartInHouse(ActionEvent actionEvent) {
companyNameLabel.setText("Machine ID");
companyNamePrompt.setPromptText("Machine ID");
addPartOutSource.setSelected(false);
}
public void addPartOutsource(ActionEvent actionEvent) {
companyNameLabel.setText("Company Name");
companyNamePrompt.setPromptText("Company Name");
addPartInHouse.setSelected(false);
}
public void addPartSaveButton(ActionEvent e) throws IOException {
/*this is my line 55 below*/
if (this.switchfield.getSelectedToggle().equals(this.addPartInHouse)) {
Part partadd = new InHouse(0, "", 0.0, 0,0,0,0);
if(partIDTxtbox.getText().isEmpty()){
partadd.setPartID(Inventory.getPartIDCount());
}
if (!partNameTxtbox.getText().isEmpty()){
partadd.setPartName(partNameTxtbox.getText());
}
if (!pricePerUnitTxtbox.getText().isEmpty()){
partadd.setPartPrice(Double.parseDouble(pricePerUnitTxtbox.getText()));
}
if (!invTxtbox.getText().isEmpty()){
partadd.setPartInStock(Integer.parseInt(invTxtbox.getText()));
}
if(!minQtyTxtbox.getText().isEmpty()){
partadd.setMin(Integer.parseInt(minQtyTxtbox.getText()));
}
if(!maxQtyTxtbox.getText().isEmpty()){
partadd.setMax(Integer.parseInt(maxQtyTxtbox.getText()));
}
if(!companyNamePrompt.getText().isEmpty()){
((InHouse)partadd).setMachineID(Integer.parseInt(companyNamePrompt.getText()));
}
Inventory.addPart(partadd);
}
else{
Part partaddout = new OutSource(0, "", 0.0, 0,0,0,"");
if(partIDTxtbox.getText().isEmpty()){
partaddout.setPartID(Inventory.getPartIDCount());
}
if (!partNameTxtbox.getText().isEmpty()){
partaddout.setPartName(partNameTxtbox.getText());
}
if (!pricePerUnitTxtbox.getText().isEmpty()){
partaddout.setPartPrice(Double.parseDouble(pricePerUnitTxtbox.getText()));
}
if (!invTxtbox.getText().isEmpty()){
partaddout.setPartInStock(Integer.parseInt(invTxtbox.getText()));
}
if(!minQtyTxtbox.getText().isEmpty()){
partaddout.setMin(Integer.parseInt(minQtyTxtbox.getText()));
}
if(!maxQtyTxtbox.getText().isEmpty()){
partaddout.setMax(Integer.parseInt(maxQtyTxtbox.getText()));
}
if(!companyNamePrompt.getText().isEmpty()){
((OutSource)partaddout).setCompanyName((companyNamePrompt.getText()));
}
Inventory.addPart(partaddout);
}
Parent addPartSave = FXMLLoader.load(getClass().getResource("MainScreen.fxml"));
Scene scene = new Scene(addPartSave);
Stage window = (Stage) ((Node) e.getSource()).getScene().getWindow();
window.setScene(scene);
window.show();
}
public void addPartCancelButton(MouseEvent mouseEvent) throws IOException {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setTitle("Cancel add part");
alert.setHeaderText("You are about to return to the Main screen!");
Optional<ButtonType> result = alert.showAndWait();
if (result.get() == ButtonType.OK) {
Parent addPartCancel = FXMLLoader.load(getClass().getResource("MainScreen.fxml"));
Scene scene = new Scene(addPartCancel);
Stage window = (Stage) ((Node) mouseEvent.getSource()).getScene().getWindow();
window.setScene(scene);
window.show();
}
else{
return;
}
}
#Override
public void initialize(URL location, ResourceBundle resources) {
switchfield = new ToggleGroup();
this.addPartInHouse.setToggleGroup(switchfield);
}
}
'''
This is not an answer but it is more readable as an answer than as a comment.
Either switchfield is null or switchfield.getSelectedToggle() returns null.
Add the following line of code before line 55.
System.out.println(switchfield)
Then run your code. If it shows that switchfield is not null, then change it to
System.out.println(switchfield.getSelectedToggle())
And run the code again.
That should show that switchfield.getSelectedToggle() returns null.
Then you need to look at the code for method getSelectedToggle() in class ToggleGroup and see when that method returns null.
My guess is that method addPartSaveButton() is being called before you have selected one of the radio buttons.

Opening a TabPane when button is clicked from another view

I have two separate views one which contains a button say view A and another a TabPane with 3 tabs call it view B. These two views are controlled by two separate view controller classes. I want to be able to click a button in view A and be able to to open a specific tab in view B's TabPane.
So far I have tried extending the controller for view A with view B such that I can get the TabPane defined in view B's controller then call myTabPane.getSelectionModel().select(myTab); however this hasn't worked as it throws a NullPointerException.
My question is it possible to click a button in view A such that it opens view B and opens a specific Tab on view B's TabPane.
I have also looked at these links with no luck 1. setting selected tab, 2. switch through tabs programatically, 3. switch between tabs in tabpane
Lets say the above image is view A and when u click right it should open view B and open a specific tab in view B's TabPane.
Lets say the above image is view B and when the button right on view A is clicked it should open view B and set the tab to tab C.
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.Initializable;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.stage.Stage;
import javafx.scene.control.SelectionModel;
public class SucessfulCreateProjectViewController extends AdminViewController {
#FXML
private Button OkButton;
#FXML
void handleCreateTasksButtonAction(ActionEvent event) {
try{
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(getClass().getResource("AdminView.fxml"));
Scene scene = new Scene(fxmlLoader.load());
Stage stage = new Stage();
stage.setScene(scene);
stage.show();
AdminTabPane.getSelectionModel().select(1);;
}catch(Exception e){
ErrorHandlerController.infoBox("Error Opening AdminPage", "Fail", null);
e.printStackTrace();
}
}
#FXML
void handleOKButtonAction(ActionEvent event) {
Stage stage = (Stage) OkButton.getScene().getWindow();
stage.close();
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
} }
Mediator is a design pattern that is used to communicate between objects that do not know each other.
This is an example of a mediator that would have done your job.
public class Mediator {
private static Mediator instance;
private Consumer<String> consumer;
public static Mediator getInstance() {
if(instance == null) {
instance = new Mediator();
}
return instance;
}
private Mediator() {
}
public void register(Consumer<String> consumer) {
this.consumer = consumer;
}
public void fireEvent(String string) {
if(consumer != null) {
consumer.accept(string);
}
}
}
and respectively, the two controllers
public class ViewAController {
#FXML
private Button btnL, btnR;
#FXML
private void initialize() {
btnL.setOnAction(event -> Mediator.getInstance().fireEvent("left"));
btnR.setOnAction(event -> Mediator.getInstance().fireEvent("right"));
}
}
public class ViewBController {
#FXML
private TabPane tabPane;
#FXML
private void initialize() {
Mediator.getInstance().register(s -> {
switch (s) {
case "left":
tabPane.getSelectionModel().select(0);
break;
case "right":
tabPane.getSelectionModel().select(2);
break;
}
});
}
}
and this is a test application that opens two windows at once.
public class Main extends Application {
#Override
public void start(Stage stageA) throws Exception{
Parent viewA = FXMLLoader.load(getClass().getResource("view_a.fxml"));
Parent viewB = FXMLLoader.load(getClass().getResource("view_b.fxml"));
stageA.setTitle("View A");
stageA.setScene(new Scene(viewA));
stageA.show();
Stage stageB = new Stage();
stageB.setTitle("View B");
stageB.setScene(new Scene(viewB));
stageB.show();
}
public static void main(String[] args) {
launch(args);
}
}
if you do not want to use two windows at once, just change the middleman.

JavaFX TableColumn nullpointerexception [duplicate]

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.

What's causing my StackOverflowError

So, I'm getting a StackOverflowError (Unwrapped from a InvocationTargetException), and I can't for the life of me figure out why.
package gui;
import errorhandling.ErrorLogBook;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class GUIRouter extends Application{
public static void main(String[] args)
{
try
{
Application.launch(GUIRouter.class, (String[])null);
}
catch (Exception e)
{
System.out.println(e.getCause().toString());
}
}
#Override
public void start (Stage primaryStage)
{
try
{
StackPane page = (StackPane) FXMLLoader.load(GUIRouter.class.getResource("LoginScreen.fxml"));
Scene scene = new Scene(page);
primaryStage.setScene(scene);
primaryStage.show();
}
catch (Exception e)
{
ErrorLogBook.logReport(e);
}
}
It fails at the first try block with:
Application.launch(GUIRouter.class, (String[])null);
This is a FXML application that I'm building with NetBeans and JavaFX Scene Builder 2.0
Any ideas about why my code keeps crashing?
My guess would be that your .fxml in "LoginScreen.fxml" has GuiRouter defined as its controller, which it then creates through reflection. My guess is that during that creation it ends up calling start(..) creating a loop.
Try this:
package gui;
import errorhandling.ErrorLogBook;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class GUIRouter extends Application{
public static void main(String[] args)
{
launch(args);
}
#Override
public void start (Stage primaryStage)
{
try
{
StackPane page = FXMLLoader.load(getClass().getResource("/gui/LoginScreen.fxml"));
Scene scene = new Scene(page);
primaryStage.setScene(scene);
primaryStage.show();
}
catch (Exception e)
{
e.printStackTrace();
ErrorLogBook.logReport(e);
}
}
Without having the .fxml file and/or the stack trace, I (see no way but to ) guess the main cause of the exception in exactly the same way as Kiskae did.
However, why you do not replace the line
Application.launch(GUIRouter.class, (String[])null);
with the more simpler form
Application.launch(args);
Or at least
Application.launch(args, new String[0]);
To see if the exception still remains.
Thanks for all the responses!
However, after playing around with it, I have found the root of the problem.
I replaced
StackPane page = (StackPane) FXMLLoader.load(GUIRouter.class.getResource("LoginScreen.fxml"));
with
Parent root = FXMLLoader.load(getClass().getResource("LoginScreen.fxml"));
and now it's working just fine.

javafx using objects from MainController or other Controllers in proper Controller class

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.

Categories

Resources