2

I am using the CharmListView and just noticed that it doesn't have a SelectionModel that the ListView has. I used to use listView.getSelectionModel().SelectedItemProperty().addListener() to respond to an item selection event with a ListView. How is that done with the CharmListView?

EDIT

The app flow is explained below:

The user selects a department of a school. This list is in a ListView

enter image description here

then a semester. This other list is in a CharmListView:

enter image description here

The initialize method of the SemesterPresenter class:

public void initialize(URL url, ResourceBundle rb) {
    loadSemesters();
    semesterListView.setItems(semesters);
    semesterListView.setHeadersFunction(Level::getLevel);
    MobileApplication.getInstance().getView().showingProperty().addListener((obs,ov,nv)->{
        System.out.println(semesterListView.getChildrenUnmodifiable());
    });
}

The first call to getChildrenUnmodifiable() returns an empty array. It's the same scenario when using all the propositions in the posts below with null pointers returned.

Community
  • 1
  • 1
theking
  • 87
  • 13

1 Answers1

1

For now several properties of the inner ListView control are not exposed, like the selectionModel or the focusModel. Those may be in incoming releases.

For now, as a workaround you can lookup for it:

CharmListView<?, ?> charmListView = new CharmListView<>();
...
stage.show();
...
ListView innerList = (ListView)charmListView.lookup(".list-view");
innerList.getSelectionModel().selectedItemProperty().addListener(
    (obs, ov, nv) -> System.out.println("Selected: " + nv));

An issue has been filed with this request.

EDIT

Based on the new info provided by the OP, right after the CharmListView is initialized, the control is created, but it hasn't created its skin yet, so the list of children is empty at this moment.

Adding Platform.runLater(); just delays the retrieval of that list the amount of time required for the control to fully create the skin.

This should work:

@FXML
private CharmListView<String, String> charmListView;

@Override
public void initialize(URL url, ResourceBundle rb) {
    charmListView.setItems(FXCollections.observableArrayList("This", "is", "a", "test"));

    Platform.runLater(() -> {
        for (Node node : charmListView.getChildrenUnmodifiable()) {
            if (node instanceof ListView) {
                ((ListView)node).getSelectionModel().selectedItemProperty().addListener(
                        (obs, ov, nv) -> System.out.println(nv));
            }
        }
    });
}

Also, based on the idea of the skin creation, this will work as well, giving you the exact moment when the ListView is created:

@Override
public void initialize(URL url, ResourceBundle rb) {
    charmListView.setItems(FXCollections.observableArrayList("This", "is", "a", "test"));
    charmListView.skinProperty().addListener((obs, ov, nv) -> {
        for (Node node : charmListView.getChildrenUnmodifiable()) {
            if (node instanceof ListView) {
                ((ListView)node).getSelectionModel().selectedItemProperty().addListener(
                        (obs2, ov2, nv2) -> System.out.println(nv2));
            }
        }
    });
}
José Pereda
  • 44,311
  • 7
  • 104
  • 132
  • I get a null pointer exception for the lookup. When does the stage get shown in a MobileApplication? – theking Dec 15 '15 at 21:14
  • 1
    Try `Platform.runLater(() -> { ListView innerList ... });` in the `postInit(Scene scene)` method, which is called right before showing the stage. – José Pereda Dec 15 '15 at 21:25
  • That solves the problem in the FiftyStates App. In my project I need to call it in the presenter that contains the CharmListView. How would I do that? – theking Dec 15 '15 at 22:42
  • Create a public method in the presenter, get an instance of it and call it in the `postInit` method. Check the Comments2.0 [sample](https://bitbucket.org/gluon-oss/samples/src/ecab7a8819a165fa76fdda3ec2eb19d9118e86fc/Comments2.0/src/main/java/com/gluonhq/demos/comments/CommentsFX.java), it does that precisely. – José Pereda Dec 15 '15 at 22:51
  • Getting a null pointer exception in the postInit method for the presenter object. – theking Dec 16 '15 at 21:16
  • Did you check the link of the Comments2.0 sample? There you get an instance of the presenter in the `init` method, so you can call `presenter.postInitialize()` in the `postInit` one. – José Pereda Dec 16 '15 at 21:20
  • Yes I did and it still returns a `NullPointerException`. I printed out the instance to output after getting it, and noticed that it is printed when the view is accessed for the first time; hence the null pointer. So from what I understand, all the views are not loaded on startup? – theking Dec 16 '15 at 21:55
  • You can try to call `presenter.postInitialize()` inside the `addViewFactory` method: create the view, get the presenter, call postInitialize, and return the view. – José Pereda Dec 16 '15 at 22:02
  • It's really hard for me to tell what is it that you are doing without seeing any line of code... If you are seeing the CharmListView on your view, then you can access its inner ListView. You just need to figure out the right moment to call the lookup. You can try this as well: `charmListView.getChildrenUnmodifiable()`, and find the ListView node. – José Pereda Dec 16 '15 at 22:26
  • I've edited the question and added some explanation. – theking Dec 16 '15 at 23:33