JavaFX ObservableList предотвращает автоматический выбор

У меня есть приложение, которое использует JavaFX. Он содержит ListView (который использует ObservableList). Я добавил ChangeListener, используя

list.getSelectionModel().selectedItemProperty().addListener(new ChangeListener...

и это работает нормально. Каждый раз, когда я выбираю другой элемент, вызывается слушатель.

Но он также вызывается, когда я удаляю элемент из ObservableList. После удаления элемента автоматически выбирается другой элемент списка и вызывается прослушиватель.

Как я могу предотвратить такое поведение?

Спасибо!


person Franz Deschler    schedule 24.02.2014    source источник
comment
Вы должны удалить прослушиватель, удалить элемент, а затем повторно добавить прослушиватель. Где это сделать, зависит от вашего кода, но, возможно, где элемент удаляется или в слушателе изменения списка с помощью getRemoved().   -  person brian    schedule 24.02.2014


Ответы (3)


В случае, если мой комментарий был слишком загадочным;

package listchange;

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ListView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class ListChange extends Application {

    @Override
    public void start(Stage primaryStage) {
        ObservableList<String> data = FXCollections.observableArrayList();
        data.addAll("one","two","three","four");

        ChangeListener changeListener = new ChangeListener() {
            @Override
            public void changed(ObservableValue observable, Object oldValue, Object newValue) {
                System.out.println("new val "+newValue);
            }
        };

        ListView lv = new ListView(data);
        lv.getSelectionModel().selectedItemProperty().addListener(changeListener);

        data.addListener(new ListChangeListener<String>() {
            @Override
            public void onChanged(ListChangeListener.Change<? extends String> c) {
                c.next();
                if (c.wasRemoved()){
                    lv.getSelectionModel().selectedItemProperty().removeListener(changeListener);
                }
            }
        });

        Button b = new Button("delete");
        b.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                //you can remove listener here or in data ListChangeListener
                //lv.getSelectionModel().selectedItemProperty().removeListener(changeListener);
                if (data.size() > 0) data.remove(0);
                //you have to re-add the listener after removing
                lv.getSelectionModel().selectedItemProperty().addListener(changeListener);
            }
        });

        VBox root = new VBox();
        root.getChildren().addAll(lv,b);

        Scene scene = new Scene(root, 300, 250);

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

}

Таким образом, вы по-прежнему будете получать события изменения выбора при обходе с использованием клавиш. Если вы знаете, где происходит удаление, легко просто удалить, а затем снова добавить прослушиватель.

person brian    schedule 24.02.2014
comment
Спасибо, я понял. Я нашел другое решение, которое работает для меня очень хорошо. Я устанавливаю флаг непосредственно перед удалением элемента из списка. В методе обработчика выбора я проверяю этот флаг, и если это правда, я просто игнорирую событие (и устанавливаю флаг обратно на flase). - person Franz Deschler; 26.02.2014

Попробуй это:

final ObservableList<String> fruits = FXCollections.observableArrayList("Apple", "Banana", "Pear", "Strawberry", "Peach", "Orange", "Plum", "Melon", "Cherry", "Blackberry", "Melon", "Cherry", "Blackberry");
final ComboBox fruit = new ComboBox(fruits);

fruit.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<String>() {
    public void changed(ObservableValue<? extends String> ov, String old_val, String new_val) {
        //TODO: your remove method
    }
});
person Suzon    schedule 24.02.2014
comment
Любой компонент, который вы можете использовать для ComboBox вместо ListView с final lv = new ... - person Suzon; 24.02.2014

Я нашел решение, которое работает, но это не очень хорошее решение.

Вместо того, чтобы использовать прослушиватель для изменений выбора, я обрабатываю только события щелчка мыши в списке. Когда я получаю событие щелчка, я запрашиваю выбранный элемент из ListView. Это не вызывается, когда я удаляю или добавляю элемент. Просто при нажатии на список.

person Franz Deschler    schedule 24.02.2014