0
votes

OK here is a tough one that has been driving me nuts for a couple of days now...

I have two stages: A users administration stage (Controller: UsersAdminController.java) Users Administration Stage with the following element hierarchy: Hierarchy of elements in the user administration stage and a User addition stage: (Controller: AddUserController.java) User Addition Stage

As a child to the scroll pane of the upper anchor pane of the users admin stage (see elements hierarchy) I add during initialization of the UsersAdminController a GridPane intended to list the users of the system as described here When I add a user through the user addition screen, I try to update the GridPane of the Users Administration stage by getting a reference to the UsersAdminController and then calling a method that updates its contents. However, the GridPane CANNOT BE UPDATED. (I seem unable to perform any gui-related action to the scroll pane neither the gridpane although I manage to get a reference to the relevant controller.

Code: Here is how the gridpane is (correctly) initialized through the initialize method of the UsersAdminController:

public void initialize(URL location, ResourceBundle resources) {
    gridPaneNonSudoUsers = new GridPane();
    gridPaneNonSudoUsers.setId("gridPaneNonSudoUsers");
    // setting column widths for the grid pane
    gridPaneNonSudoUsers.getColumnConstraints().add(new ColumnConstraints(145));
    gridPaneNonSudoUsers.getColumnConstraints().add(new ColumnConstraints(85));
    gridPaneNonSudoUsers.getColumnConstraints().add(new ColumnConstraints(210));
    gridPaneNonSudoUsers.getColumnConstraints().add(new ColumnConstraints(150));

    srcPaneUsers.setContent(gridPaneNonSudoUsers);
    gridPaneNonSudoUsers.setAlignment(Pos.CENTER);

    displayNonSudoUsers(getSystemNonSudoUsers());
}

Here is the displayNonSudoUsers that populates the GridPane

public void displayNonSudoUsers(ArrayList nonSudoUsers) {

    // adding some space between lines
    gridPaneNonSudoUsers.setVgap(15);

    Label lblHeaderUsername = new Label("Username");
    lblHeaderUsername.setPadding(new Insets(0, 0, 0, 20));
    lblHeaderUsername.setId("lblHeaderUsername");
    Label lblHeaderIsProtected = new Label("Προστασία");
    lblHeaderIsProtected.setId("lblHeaderIsProtected");
    GridPane.setHalignment(lblHeaderUsername, HPos.LEFT);
    GridPane.setHalignment(lblHeaderIsProtected, HPos.CENTER);

    // adding header elements to GridPane
    GridPane.setColumnIndex(lblHeaderUsername, 0);
    GridPane.setRowIndex(lblHeaderUsername, 0);
    GridPane.setColumnIndex(lblHeaderIsProtected, 1);
    GridPane.setRowIndex(lblHeaderIsProtected, 0);
    gridPaneNonSudoUsers.getChildren().addAll(lblHeaderUsername,
            lblHeaderIsProtected);

    // adding users
    int i = 1; // starting from 2nd row given that 1st row belongs to
                // headers
    for (NonSudoUser nsuser : nonSudoUsers) {

        /**** Label ****/
        String username = nsuser.getUsername();
        Label lblUsername = new Label(username);
        lblUsername.setPadding(new Insets(5, 0, 5, 20));
        lblUsername.setId("lbl" + username);
        GridPane.setHalignment(lblUsername, HPos.LEFT);

        /**** Image ****/
        boolean isProtected = nsuser.isProtected();
        ImageView imgIsProtected = new ImageView(
                isProtected ? "/resources/media/notOK.png"
                        : "/resources/media/ok.png");
        imgIsProtected.setFitHeight(20);
        imgIsProtected.setFitWidth(20);
        imgIsProtected.setId("img" + username);
        GridPane.setHalignment(imgIsProtected, HPos.CENTER);

        /**** Button for protection ****/
        Button btnSetProtected = new Button("Ενεργοποίηση Προστασίας");
        btnSetProtected.setId("btnProt" + username);
        btnSetProtected.setDisable(!isProtected);
        GridPane.setHalignment(btnSetProtected, HPos.CENTER);

        /**** Button for deletion ****/
        Button btnDeleteUser = new Button("Διαγραφή Χρήστη");
        btnDeleteUser.setId("btnDel" + username);
        GridPane.setHalignment(btnDeleteUser, HPos.CENTER);
        // delete user in a seperate thread
        btnDeleteUser.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                Action response = Dialogs
                        .create()
                        .owner(root)
                        .title("ΔΙΑΓΡΑΦΗ ΧΡΗΣΤΗ")
                        .masthead(
                                "ΠΡΟΣΟΧΗ! ΠΡΟΚΕΙΤΑΙ ΝΑ ΔΙΑΓΡΑΨΕΤΕ ΤΟ ΧΡΗΣΤΗ: "
                                        + username)
                        .message("ΕΙΣΑΣΤΕ ΣΙΓΟΥΡΟΙ?")
                        .actions(Dialog.ACTION_OK, Dialog.ACTION_CANCEL)
                        .showConfirm();
                if (response == Dialog.ACTION_CANCEL)
                    return;
                Task<Void> task = new Task<Void>() {
                    @Override
                    public Void call() throws Exception {
                        String username = ((Button) event.getSource())
                                .getId();
                        LinuxCommand lc = new LinuxCommand("userdel", "-r",
                                username);
                        lc.execute();
                        return null;
                    }
                };
                task.setOnFailed(new EventHandler<WorkerStateEvent>() {
                    public void handle(WorkerStateEvent t) {
                        System.out.println("FAILURE deleting  " + username);
                    }
                });
                task.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
                    public void handle(WorkerStateEvent t) {
                        Platform.runLater(new Task<Void>() {
                            @Override
                            public Void call() throws Exception {
                                ArrayList<Node> toErase = new ArrayList<Node>();
                                for (Node nodeToErase : gridPaneNonSudoUsers
                                        .getChildren()) {
                                    if (nodeToErase.getId().endsWith(
                                            username))
                                        toErase.add(nodeToErase);
                                }
                                gridPaneNonSudoUsers.getChildren()
                                        .removeAll(toErase);
                                // rearrangeGridPane(); - TBD
                                return null;
                            }
                        });
                    }
                });
                executorUserDeletion.submit(task);
            }
        });

        // adding user-related gui items
        GridPane.setColumnIndex(lblUsername, 0);
        GridPane.setRowIndex(lblUsername, i);

        GridPane.setColumnIndex(imgIsProtected, 1);
        GridPane.setRowIndex(imgIsProtected, i);

        GridPane.setColumnIndex(btnSetProtected, 2);
        GridPane.setRowIndex(btnSetProtected, i);

        GridPane.setColumnIndex(btnDeleteUser, 3);
        GridPane.setRowIndex(btnDeleteUser, i);

        gridPaneNonSudoUsers.getChildren().addAll(lblUsername,
                imgIsProtected, btnSetProtected, btnDeleteUser);
        i++;
    }
}

And here is the method that is called on action of the ADD USER BUTTON of the User Addition Stage

    public void createUser() throws UserCreationException {

        String username, password1, password2;
        username = txtUsername.getText();
        password1 = txtPassword1.getText();
        password2 = txtPassword2.getText();
        LinuxCommand lc = new LinuxCommand(System.getProperty("user.dir")+"/adduser.sh", username, password2);
    Task<Void> task = new Task<Void>() {
        @Override
        public Void call() throws Exception {
            lc.execute();
            return null;
        }
    };
    task.setOnFailed(new EventHandler<WorkerStateEvent>() {
        public void handle(WorkerStateEvent t) {
            System.out.println("FAILURE creating  " + username);
            System.out.println("exit code: " + lc.getExitCode());
        }
    });
    task.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
        @Override
        public void handle(WorkerStateEvent t) {
            if (lc.getExitCode() != 0)
                // show dialog
                return;
            System.out.println("Successfully created new user:  " + username + " With exit code: " + lc.getExitCode());
            Platform.runLater(new Task<Void>() {
                @Override
                public Void call() throws Exception {                       
                    uac.addUser();          
                    return null;

                }
            });
        }
    });

    executorUserCreation.submit(task);

where uac is a reference to the UserAdministrationController.java and the adduser the method that tries to update the GridPane by CALLING AGAIN the displayNonSudoUsers(). I have also experimented by trying to do various stuff on the scroll pane / gridpane of the Users Admin Stage (e.g. deleting a label etc) but NADA!

Thanks.

EDIT: And this is the way I get the reference to the user admin controller (which is probably right because e.g. I manage to sysout some of its elements's ids etc.) in the initialize method of the AddUserController.java

public void initialize(URL location, ResourceBundle resources) {
    // need to access UsersAdminController to update users list 
    // when adding user
    URL loc = getClass().getResource("/resources/fxml/UsersAdminPane.fxml"); // the UsersAdmin fxml 
    FXMLLoader fxmlLoader = new FXMLLoader();
    fxmlLoader.setLocation(loc);
    fxmlLoader.setBuilderFactory(new JavaFXBuilderFactory());
    try {
        Parent root = (Parent) fxmlLoader.load(loc.openStream());
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    uac = (UsersAdminController)fxmlLoader.getController();
}
1
How are you getting the reference to the UserAdministrationController in the AddUserController?James_D
Answered in the editpkaramol
You are loading a brand new UsersAdminPane in the AddUserController? Doesn't one already exist?James_D
Your code is pretty complex, and it's going to be hard to figure out what's going on. What I'd recommend is creating a new application completely from scratch that involves one controller calling another controller to update its associated view. Other than that make it as simple as you possibly can. Once you have the technique down to get that working, you can try to fix your real app.James_D
If I don't do the Parent root = (Parent) fxmlLoader.load(loc.openStream()); I get a NullPointerException wheh I try to access the uac.pkaramol

1 Answers

1
votes

In this code:

public void initialize(URL location, ResourceBundle resources) {
    // need to access UsersAdminController to update users list 
    // when adding user
    URL loc = getClass().getResource("/resources/fxml/UsersAdminPane.fxml"); // the UsersAdmin fxml 
    FXMLLoader fxmlLoader = new FXMLLoader();
    fxmlLoader.setLocation(loc);
    fxmlLoader.setBuilderFactory(new JavaFXBuilderFactory());
    try {
        Parent root = (Parent) fxmlLoader.load(loc.openStream());
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    uac = (UsersAdminController)fxmlLoader.getController();
}

you load a new copy of UsersAdminPane.fxml, get the reference to its controller... and then discard the view (root) and never do anything with it. Since that view is never displayed, calling methods on the controller is never going to produce any update you will see.

You need to get a reference to the controller associated with the existing view, and call methods on that, instead of creating a new controller. Assuming you load the AddUser fxml file from the UsersAdminController, you can get the AddUserController from the FXMLLoader and pass a reference to the UsersAdminController by defining a setUsersAdminController(...) method in the AddUserController.