Событие нежелательного изменения JavaFX при удалении элементов из Combobox - PullRequest
0 голосов
/ 07 марта 2019

У меня есть JavaFX ComboBox, и мне нужно удалить из него элемент, но как только элемент будет удален, он вызовет 3-4 нежелательных события изменения. Кто-нибудь может помочь мне избежать этих нежелательных событий?

Мой код такой:

import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.ComboBox;

public class ComboboxTest
{
private Boolean comboBoxRemovingMode = false;

public ComboBox<String> createCombo()
{

    final ComboBox<String> myComboBox = new ComboBox<>();
    myComboBox.getItems().addAll("prompt_txt", "A", "B", "C");
    myComboBox.getSelectionModel().selectedIndexProperty().addListener(new ChangeListener<Number>() {
        @Override
        public void changed(final ObservableValue<? extends Number> ov, final Number oldvalue, final Number newvalue)
        {

            if (comboBoxRemovingMode) {
                return;
            }
            if ((newvalue == null) || (newvalue.intValue() < 0) || (myComboBox.getItems().get(newvalue.intValue()).equalsIgnoreCase("prompt_txt"))) {
                return;
            }

            synchronized (comboBoxRemovingMode) {
                comboBoxRemovingMode = myComboBox.getItems().remove("prompt_txt");
                // .... some actions
                myComboBox.getSelectionModel().select(newvalue.intValue() - 1);
                comboBoxRemovingMode = false;

            }
        }

    });

    return myComboBox;
}

public static void main(final String args[])
{
    final ComboboxTest t = new ComboboxTest();
    final ComboBox<String> box = t.createCombo();

    box.getSelectionModel().select(1); // select A

    System.out.println(box.getSelectionModel().getSelectedItem()); // it should be select "A", but it's B
}

}

1 Ответ

0 голосов
/ 09 марта 2019

Из вашего кода похоже, что у вас есть элемент, функционирующий как текст подсказки ComboBox.При выборе нового элемента вы хотите удалить текстовый элемент приглашения, оставив выбранным новый элемент выбранным 1 .Для этого вам нужно всего лишь удалить текст подсказки;нет необходимости пытаться вручную вызвать select для модели выбора - новый элемент уже выбран к этому моменту.

comboBox.getSelectionModel().selectedIndexProperty((obs, oldVal, newVal) -> {
    int oldIndex = oldVal.intValue();
    var items = comboBox.getItems();
    if (oldIndex >= 0 && oldIndex < items.size() && items.get(oldIndex).equalsIgnoreCase("prompt_txt")) {
        items.remove(oldIndex);
    }
});

Здесь я использую старый индекс, предполагая, что элемент "prompt_txt"первоначально выбранный элемент.

Этот код все равно приведет к двум изменениям, поскольку удаление элемента "prompt_txt" изменит индексы всех оставшихся элементов.Это не имеет значения.Слушатель не будет ничего делать для любых последующих уведомлений, и вновь выбранный элемент остается прежним.Поскольку кажется, что единственной задачей слушателя является удаление "prompt_txt", тем не менее, может быть разумно удалить слушателя после первого уведомления.Один из способов сделать это заключается в следующем:

comboBox.getSelectionModel().selectedIndexProperty().addListener(new ChangeListener<>() {

    @Override
    public void changed(ObservableValue<? extends Number> obs, Number oldVal, Number newVal) {
        int oldIndex = oldVal.intValue();
        var items = comboBox.getItems();
        if (oldIndex >= 0 && oldIndex < items.size() && items.get(oldIndex).equalsIgnoreCase("prompt_txt")) {
            obs.removeListener(this); // Needed anonymous class to reference "this"
            items.remove(oldIndex);
        }
    }

});

В этом случае, поскольку я удаляю слушателя перед вызовом remove(oldIndex), слушатель уведомляется только один раз.

Однако

Все это говорит о том, что нет необходимости добавлять специальный элемент для представления текста подсказки.Класс ComboBoxBase, от которого наследуется ComboBox, обладает свойством promptText.Вот документация:

Текст подсказки ComboBox для отображения или ноль, если текст подсказки не отображается.Текст подсказки отображается не во всех случаях, он зависит от подклассов ComboBoxBase, чтобы уточнить, когда будет отображаться подсказка.Например, в большинстве случаев текст подсказки никогда не будет отображаться, когда поле со списком недоступно для редактирования (то есть текст подсказки отображается только тогда, когда пользовательский ввод разрешен посредством ввода текста).

Некоторые быстрыетестирование показывает, что ComboBox отображает текст приглашения, даже если не editable (при условии, что элементы не выбраны).


1.У вас есть // some actions... между remove("prompt_text") и select(newvalue.intValue() - 1).То, что эти действия могут полностью аннулировать мой ответ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...