JavaFX - ListView item not selected upon Initialization

Hi all I have a fairly odd question regarding the initialization of a Scene in JavaFX that contains a ListView.

The issue is that when I initialize a scene for my program I want the first item of a ListView to be selected. However, if I am able to select it (through odd means mentioned later on) the ListView itself is not in focus. What I want to happen is that the first item in the ListView is selected and the ListView being in focus.

I'll start with minimal code to try and illustrate my issue:

public class SceneSetter {

static Stage mainStage;
static Scene adminScene;
static AdminController adminCont;

public static void initialize(Stage stage) throws IOException {
    mainStage = stage;

    FXMLLoader adminLoader = new FXMLLoader();
    adminLoader.setLocation(SceneSetter.class.getResource("/view/Admin.fxml"));
    SplitPane adminRoot = adminLoader.load();
    adminScene = new Scene(adminRoot);
    adminCont = adminLoader.getController();

    goToAdmin();
}

public static void goToAdmin() {
    mainStage.setScene(adminScene);
    //adminCont.initialize();
    mainStage.show();
}
}

My original program has multiple scenes that all need to be set upon the program starting. So within this SceneSetter class all those scenes are set and the controllers added in. I have removed those as this bit of code is able to demonstrate the issue.

My admincontroller is as follows:

public class AdminController {
Stage mainStage;
private ObservableList<User> userList;

@FXML
private ListView<User> userListView;

@FXML
private Button adminAdd;

public void initialize() {
    userListView.setItems(Admin.getUserlist());
    userListView.getSelectionModel().select(0);
    userListView.getFocusModel().focus(0);
}

public void setMainStage(Stage s) {
    mainStage = s;
}
}

The problem here is that when I run my code the item that I want to be selected is either:

  1. Not selected
  2. Not in Focus

My confusion is compounded bc of the following. If in my SceneSetter class, in my goToAdmin methods the commented line of code adminCont.initialize() is kept commented the program appears as follows:

enter image description here

When I uncomment the same line of code, the program appears as follows:

enter image description here

In the first instance, the correct item is not even selected. In the second, the ListView is not in focus.

How can I fix this issue?

1 answer

  • answered 2017-11-15 00:01 JKostikiadis

    In order to focus a control you need to request it. The method you are searching for is requestFocus(). But there is a catch. Reading the JavaDoc :

    To be eligible to receive the focus, the node must be part of a scene, it and all of its ancestors must be visible, and it must not be disabled

    So that means you have two choices.

    • You could call the requestFocus() inside a Platform.runLater() in order to be sure that the scene graph have been created.

    • You could call the requestFocus() after you added the control on the Scene.

    Example :

    import javafx.application.Application;
    import javafx.application.Platform;
    import javafx.collections.FXCollections;
    import javafx.collections.ObservableList;
    import javafx.scene.Scene;
    import javafx.scene.control.ListView;
    import javafx.stage.Stage;
    
    public class SceneSetter extends Application {
    
        public static void main(String[] args) {
            launch(args);
        }
    
        @Override
        public void start(Stage mainStage) throws Exception {
            ListView<String> list = new ListView<String>();
            ObservableList<String> items = FXCollections.observableArrayList("Single", "Double", "Suite", "Family App");
            list.setItems(items);
    
            list.getSelectionModel().select(0);
    
            Platform.runLater(new Runnable() {
                @Override
                public void run() {
                    list.requestFocus();
                }
            });
    
            mainStage.setScene(new Scene(list));
            // or here 
            // list.requestFocus();
            mainStage.show();
        }
    
    }
    

    An example with FXML file

    Main :

    import javafx.application.Application;
    import javafx.fxml.FXMLLoader;
    import javafx.scene.Scene;
    import javafx.scene.control.ListView;
    import javafx.stage.Stage;
    
    public class SceneSetter extends Application {
    
        public static void main(String[] args) {
            launch(args);
        }
    
        @Override
        public void start(Stage mainStage) throws Exception {
            ListView<String> list = FXMLLoader.load(this.getClass().getResource("GUI.fxml"));
    
            mainStage.setScene(new Scene(list));
    
            mainStage.show();
        }
    
    }
    

    Controller :

    import javafx.application.Platform;
    import javafx.collections.FXCollections;
    import javafx.collections.ObservableList;
    import javafx.fxml.FXML;
    import javafx.scene.control.ListView;
    
    public class MyController {
    
        @FXML
        private ListView<String> userListView;
    
        @FXML
        public void initialize() {
    
            ObservableList<String> items = FXCollections.observableArrayList("Single", "Double", "Suite", "Family App");
            userListView.setItems(items);
            userListView.getSelectionModel().select(0);
    
            Platform.runLater(new Runnable() {
                @Override
                public void run() {
                    userListView.requestFocus();
                }
            });
        }
    }