1

When I test JavaFx 8 ListView, I have encountered a strange problem. This is code:

Main.java:

package application;

import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;

public class Main extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("Test.fxml"));

        Scene scene = new Scene(root);

        stage.setScene(scene);
        stage.show();
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) 
    {
        launch(args);
    }

}

TestController.java:

package application;

import java.net.URL;
import java.util.ArrayList;
import java.util.ResourceBundle;

import javafx.collections.ObservableList;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener.Change;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ListView;
import javafx.scene.control.SelectionMode;

public class TestController implements Initializable 
{
    @FXML
    ListView<String> listView;

    private ArrayList <String> list;

    @Override
    public void initialize(URL url, ResourceBundle rb) 
    {
        listView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);

        fillList();
        listView.getSelectionModel().getSelectedItems().addListener(
                (Change<? extends String> change) ->
                {
                    list.clear();

                    ObservableList<String> oList = listView.getSelectionModel().getSelectedItems(); 
                    System.out.println(oList);          
                });
    }

    private void fillList() 
    {
        list = new  ArrayList<>();
        list.add("1.item");
        list.add("2.item");
        list.add("3.item");

        ObservableList<String> items = FXCollections.observableArrayList(list);
        listView.setItems(items);

    }

}

Test.fxml:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.ListView?>
<?import javafx.scene.layout.AnchorPane?>


<AnchorPane id="AnchorPane" prefHeight="399.0" prefWidth="320" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.TestController">
   <children>
      <ListView fx:id="listView" layoutX="14.0" layoutY="85.0" prefHeight="200.0" prefWidth="200.0" />
   </children>
</AnchorPane>

When I selected first 1.item, then 2.item, then deselected 1.item (with ctrl); listView.getSelectionModel().getSelectedItems() return null, program output is:

[1.item]
[1.item, 2.item]
[null]

but when I selected first 2.item, then 1.item, then deselected 2.item (with ctrl); result is normal, program output is:

[2.item]
[1.item, 2.item]
[1.item] 

What's the problem?

Seyit Bilal
  • 191
  • 2
  • 16
  • 1
    Possibly this bug: https://bugs.openjdk.java.net/browse/JDK-8160973 . Looks like it won't be fixed in 8, but there is a workaround. – Itai Feb 22 '18 at 11:15
  • Yes, the only difference I deselected previous item by using ctrl, this deselected previous item by selecting posterior item. In addition, this bug is realized with just 2 items, not any more. Thanks. – Seyit Bilal Feb 22 '18 at 12:03
  • in fx8, the selectionModels are completely broken (to the extend to be not useable at all), no prediction can be made as to when the change notification reports what (meaning that the bug mentioned might be the bug you experience or not - for me it looks similar enough). In fx9 the situation improved considerably (no wonder coming from such an incredibly broken state ;) - though still far from good nor even acceptable ... Not much you can do about it: try hacking (up to implement your own MultipleSelectionModel), listening to other change indicators, upgrade .. – kleopatra Feb 22 '18 at 13:17
  • @kleopatra Java recommended version is still Version 8 Update 161, therefore I didn't want to upgrade java 9, I do a tricky (When getSelectedItems() return null, I use getSelectedItem() method) for this situation, but when I read your comment, I think there are different bugs that you know – Seyit Bilal Feb 22 '18 at 14:45
  • yeah there are indeed .. search the bug database if you like horror stories ;) – kleopatra Feb 22 '18 at 16:38

1 Answers1

1

Through the problem in my question arise from a bug, I share my tricky way for this situation (I used getSelectedItem() method when getSelectedItems() return null). Changed TestController.java:

package application;

import java.net.URL;
import java.util.ArrayList;
import java.util.ResourceBundle;

import javafx.collections.ObservableList;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener.Change;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ListView;
import javafx.scene.control.SelectionMode;


public class TestController implements Initializable 
{

    @FXML
    ListView<String> listView;

    private ArrayList <String> list;



    @Override
    public void initialize(URL url, ResourceBundle rb) 
    {
        listView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);

        fillList();
        listView.getSelectionModel().getSelectedItems().addListener(
                (Change<? extends String> change) ->
                {
                    list.clear();

                    ObservableList<String> oList = listView.getSelectionModel().getSelectedItems(); 

                    if(oList != null)
                        System.out.println(oList);
                    else
                        System.out.println(listView.getSelectionModel().getSelectedItem());
                });
    }

    private void fillList() 
    {
        list = new  ArrayList<>();
        list.add("1.item");
        list.add("2.item");
        list.add("3.item");

        ObservableList<String> items = FXCollections.observableArrayList(list);
        listView.setItems(items);

    }

}
Seyit Bilal
  • 191
  • 2
  • 16
  • 1
    I know it's a trick and as such good as long as it works for your :) Anyway, beware: the result of accessing other properties (selectedItem) in a listener to one property (selectedItems) is unspecified! So you may or may not get what you want/need, and even if you get it, there's no guarantee that you'll get in all execution paths ... just saying .. – kleopatra Feb 22 '18 at 16:37
  • I apply this trick on another project implementation, there is no undesirable result by now, but thanks for all, I'm sure that I don't use that for critical missions :) – Seyit Bilal Feb 23 '18 at 06:09