0

I'm having a problem with this code I am writing. The project is a password keeper app, and for this current sprint I created a Password model and another class to hold an ArrayList of Passwords called PasswordList. I've created a PasswordList object in every controller class as a private variable and pass it along by loading the controller of the next scene and setting the PasswordList with the current controller's PasswordList (so that the same list is passed throughout the whole project). However, when creating a new Password object, adding it to this PasswordList, then switching scenes, the PasswordList is null.

So, I have a PasswordUI which is the viewer, and from there a user can click on the "Add" button to view the CreatePasswordUI. I've tested to make sure that the password is created and added successfully to the PasswordList by printing it to the console and using the debugger, and everything checks out. I can even go back to add another password, and the list still has all the previous Password objects created. Yet, in the PasswordUI, the PasswordList is still coming up as null even though I am passing the PasswordList from the previous scene.

I am stuck and do not know what to do.

public class PasswordUIController implements Initializable {

    private PasswordList passList;
    /**
     * Initializes the controller class.
     */
    @FXML
    TreeTableView passwordInfo;
    @FXML
    TreeTableColumn<String,String> acctColumn;
    @FXML
    Parent root;
    @FXML
    private void backButtonAction(ActionEvent event) throws Exception {
        Stage stage = (Stage) root.getScene().getWindow();
        FXMLLoader loader = new FXMLLoader(getClass().getResource("MainMenuUI.fxml"));     
        Pane mainMenuUI = (Pane)loader.load();          
        MainMenuController controller = loader.<MainMenuController>getController();
        controller.setPassList(passList);

        Scene scene = new Scene(mainMenuUI); 
        stage.setTitle("Main Menu");
        stage.setScene(scene);
        stage.show();
    }
    @FXML
    private void addButtonAction(ActionEvent event) throws Exception {
        Stage stage = (Stage) root.getScene().getWindow();
        FXMLLoader loader = new FXMLLoader(getClass().getResource("CreatePasswordUI.fxml"));     
        Pane createPassUI = (Pane)loader.load();          
        CreatePasswordUIController controller = loader.<CreatePasswordUIController>getController();
        controller.setPassList(passList);

        Scene scene = new Scene(createPassUI); 
        stage.setTitle("Create Password");
        stage.setScene(scene);
        stage.show();
    }
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        PasswordList pList = passList;
        if (pList != null) {
            ArrayList<Password> thePasswords = pList.getPasswordList();           
            TreeItem<String> passwords = new TreeItem<>("Passwords");
            for (int i = 0; i < thePasswords.size(); i++) {
                Password thePass = thePasswords.get(i);
                //Creating tree items
                TreeItem<String> username = new TreeItem<>("Username: " + thePass.getUsername());
                TreeItem<String> password = new TreeItem<>("Password: " + thePass.getPassword());
                TreeItem<String> comment = new TreeItem<>("Comment: " + thePass.getComment());

                //Creating the root element
                TreeItem<String> account = new TreeItem<>(thePass.getAccount());
                account.setExpanded(true);

                //Adding tree items to the root
                account.getChildren().setAll(username, password, comment);   
                passwords.getChildren().add(account);
            }
            //Creating a column
            acctColumn = new TreeTableColumn<>("Account");

            //Defining cell content
            acctColumn.setCellValueFactory(new Callback<TreeTableColumn.CellDataFeatures<String, String>, ObservableValue<String>>() {
                @Override
                public ObservableValue<String> call(TreeTableColumn.CellDataFeatures<String, String> param){
                    return new SimpleStringProperty(param.getValue().getValue());
                }
            });

            //Creating a tree table view
            passwordInfo = new TreeTableView<>();
            passwordInfo.setRoot(passwords);
            passwordInfo.getColumns().add(acctColumn);
        } else {

        }
    }    

    /**
     * @return the passList
     */
    public PasswordList getPassList() {
        return passList;
    }

    /**
     * @param passList the passList to set
     */
    public void setPassList(PasswordList passList) {
        this.passList = passList;
    }

}

public class CreatePasswordUIController implements Initializable {

    private PasswordList passList;
    /**
     * Initializes the controller class.
     */
    @FXML
    Parent root;
    @FXML
    TextField accountTxt;
    @FXML
    TextField usernameTxt;
    @FXML
    TextField passwordTxt;
    @FXML
    TextField passwordTxt2;
    @FXML
    TextArea commentArea;
    @FXML
    TextField passwordGeneratorTxt;
    @FXML
    Label rating;
    @FXML
    Label matching;
    @FXML
    Label incorrect;
    @FXML
    private void backButtonAction(ActionEvent event) throws Exception {
        Stage stage = (Stage) root.getScene().getWindow();
        FXMLLoader loader = new FXMLLoader(getClass().getResource("MainMenuUI.fxml"));     
        Pane mainMenuUI = (Pane)loader.load();          
        MainMenuController controller = loader.<MainMenuController>getController();
        controller.setPassList(passList);

        Scene scene = new Scene(mainMenuUI); 
        stage.setTitle("Main Menu");
        stage.setScene(scene);
        stage.show();
    }
    @FXML
     private void submitButtonAction(ActionEvent event) throws Exception {
        String account = accountTxt.getText();
        String username = usernameTxt.getText();
        String password = passwordTxt.getText();
        String password2 = passwordTxt2.getText();
        String comment = commentArea.getText();
        if (password.equals(password2) && username.length()>2) {
            PasswordList pList = passList;
            Password thePass = new Password(account, username, password, comment);
            pList.addPassword(thePass);
            Stage stage = (Stage) root.getScene().getWindow();
            FXMLLoader loader = new FXMLLoader(getClass().getResource("PasswordUI.fxml"));     
            Pane passwordUI = (Pane)loader.load();          
            PasswordUIController controller = loader.<PasswordUIController>getController();
            controller.setPassList(pList);

            Scene scene = new Scene(passwordUI); 
            stage.setTitle("Password");
            stage.setScene(scene);    
            stage.show();   
        } else {
            incorrect.setVisible(true);
        }
    }
    @FXML
    private void generateButtonAction(ActionEvent event) {
        PasswordGenerator passGen = new PasswordGenerator();
        String password = passGen.generatePassword(true);
        passwordGeneratorTxt.setText(password); 
    }
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        PasswordRater rater = new PasswordRater();
        passwordTxt.textProperty().addListener(new ChangeListener() {
            @Override
            public void changed(ObservableValue observable, Object oldVal,Object newVal) {
               String password = passwordTxt.getText();
               rater.setPassword(password);
               String ratingStr = rater.displayLevel();
               rating.setText(ratingStr);
               rating.setVisible(true);
               if (passwordTxt.getText().equals(passwordTxt2.getText()) && !password.equals("")) {
                    matching.setText("Good!");
               }
               else
               {
                   matching.setText("Passwords do not match.");
               }
            }
        });
        passwordTxt2.textProperty().addListener(new ChangeListener() {
            @Override
            public void changed(ObservableValue observable, Object oldVal,Object newVal) {
                String password = passwordTxt.getText();
                String password2 = passwordTxt2.getText();
                if (password.equals(password2) && !password.equals("")) {
                    matching.setText("Good!");
                } else {
                    matching.setText("Passwords do not match.");
                }
                matching.setVisible(true);
            }
        });
    }    

    /**
     * @return the passList
     */
    public PasswordList getPassList() {
        return passList;
    }

    /**
     * @param passList the passList to set
     */
    public void setPassList(PasswordList passList) {
        this.passList = passList;
    }

}
fabian
  • 80,457
  • 12
  • 86
  • 114
Ray Beer
  • 1
  • 1

2 Answers2

0

The problem with having a new password list in every controller is that everytime a new instance is created , you are basically Looking at a singleton approach . Either you can try singleton like only one object is created throughout the application or for a simpler approach you can have a single static list in your main class and then reuse it in the subsequent contorllers.

Rahul Singh
  • 19,030
  • 11
  • 64
  • 86
0

If you specify the controller in the fxml file using the fx:controller attribute and do not specify a controller factory, FXMLLoader procedes as follows:

  1. load() method is entered
  2. when the fx:controller attribute is read a new instance of the controller class specified in the attribute value is created.
  3. Any elements with a fx:id attributes are injected to the approprieate fields of the controller instance.
  4. The controller's initialize method is called, if there is one
  5. load() completes returning the element created for the root element of the fxml file

For

FXMLLoader loader = new FXMLLoader(getClass().getResource("CreatePasswordUI.fxml"));     
Pane createPassUI = (Pane)loader.load();          
CreatePasswordUIController controller = loader.<CreatePasswordUIController>getController();
controller.setPassList(passList);

to work however you'd need a different order of operations:

1.
2.
3.
5.
controller.setPassList(passList);
4.

If you want create the controller this way, move the code for initializing the TreeTableView to the setPassList method.

BTW: I'm pretty sure creating a new TreeTableView is not what you want. Instead you should set the data to the existing TreeTableView created by the FXMLLoader:

PasswordUIController

@Override
public void initialize(URL url, ResourceBundle rb) {
    // displaying the item itself in the TreeTableColumn defys
    // the purpose of Tree**Table**View, but we'll ignore this here
    acctColumn.setCellValueFactory(new Callback<TreeTableColumn.CellDataFeatures<String, String>, ObservableValue<String>>() {
        @Override
        public ObservableValue<String> call(TreeTableColumn.CellDataFeatures<String, String> param){
            return new SimpleStringProperty(param.getValue().getValue());
        }
    });
}

public void setPassList(PasswordList passList) {
    if (passList == null) {
        throw new IllegalArgumentException();
    }
    this.passList = passList;

    ArrayList<Password> thePasswords = passList.getPasswordList();           
    TreeItem<String> passwords = new TreeItem<>("Passwords");
    for (int i = 0; i < thePasswords.size(); i++) {
        Password thePass = thePasswords.get(i);
        //Creating tree items
        TreeItem<String> username = new TreeItem<>("Username: " + thePass.getUsername());
        TreeItem<String> password = new TreeItem<>("Password: " + thePass.getPassword());
        TreeItem<String> comment = new TreeItem<>("Comment: " + thePass.getComment());

        //Creating the root element
        TreeItem<String> account = new TreeItem<>(thePass.getAccount());
        account.setExpanded(true);

        //Adding tree items to the root
        account.getChildren().setAll(username, password, comment);   
        passwords.getChildren().add(account);
    }

    // set content of the TreeTableView
    passwordInfo.setRoot(passwords);
}

There are other ways of passing data to a fxml controller. You can find some good answers here: Passing Parameters JavaFX FXML

Community
  • 1
  • 1
fabian
  • 80,457
  • 12
  • 86
  • 114