Java 从addListener中的ListView中删除项

Java 从addListener中的ListView中删除项,java,listview,javafx,javafx-8,Java,Listview,Javafx,Javafx 8,我对下面的Java程序有问题。我在Ubuntu系统上使用JavaFX和JDK-1.8u25。我想显示一个ListView并从列表中删除突出显示的条目。我创建了一个列表,并将其与一个ObservableList配对,以通知侦听器事件。但是,通过删除下面的项目“orderOvList.remove(i,i+1)”来更改列表似乎会生成另一个侦听器事件。因此,我似乎在侦听器代码体中递归。我曾考虑过将列表元素从非有序列表“orderList.remove(I)”中移除,但后来ListView没有更新 有人

我对下面的Java程序有问题。我在Ubuntu系统上使用JavaFX和JDK-1.8u25。我想显示一个ListView并从列表中删除突出显示的条目。我创建了一个列表,并将其与一个ObservableList配对,以通知侦听器事件。但是,通过删除下面的项目“orderOvList.remove(i,i+1)”来更改列表似乎会生成另一个侦听器事件。因此,我似乎在侦听器代码体中递归。我曾考虑过将列表元素从非有序列表“orderList.remove(I)”中移除,但后来ListView没有更新

有人有什么想法吗

下面的代码在我运行后崩溃

堆栈跟踪:

0
0
Exception in thread "JavaFX Application Thread" java.lang.UnsupportedOperationException
    at java.util.Collections$UnmodifiableCollection.add(Collections.java:1055)
    at javafx.collections.ListChangeBuilder.nextRemove(ListChangeBuilder.java:204)
    at javafx.collections.ObservableListBase.nextRemove(ObservableListBase.java:150)
    at javafx.collections.ModifiableObservableListBase.remove(ModifiableObservableListBase.java:181)
    at com.sun.javafx.collections.ObservableListWrapper.remove(ObservableListWrapper.java:165)
    at TestListView.lambda$start$0(TestListView.java:32)
    at TestListView$$Lambda$82/921981528.invalidated(Unknown Source)
    at com.sun.javafx.binding.ExpressionHelper$SingleInvalidation.fireValueChangedEvent(ExpressionHelper.java:137)
    at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
    at javafx.beans.property.ReadOnlyObjectWrapper$ReadOnlyPropertyImpl.fireValueChangedEvent(ReadOnlyObjectWrapper.java:176)
    at javafx.beans.property.ReadOnlyObjectWrapper.fireValueChangedEvent(ReadOnlyObjectWrapper.java:142)
    at javafx.beans.property.ObjectPropertyBase.markInvalid(ObjectPropertyBase.java:112)
    at javafx.beans.property.ObjectPropertyBase.set(ObjectPropertyBase.java:145)
    at javafx.scene.control.SelectionModel.setSelectedItem(SelectionModel.java:102)
    at javafx.scene.control.ListView$ListViewBitSetSelectionModel$1.onChanged(ListView.java:1245)
    at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88)
    at com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(ListListenerHelper.java:329)
    at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
    at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
    at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
    at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
    at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
    at com.sun.javafx.collections.ObservableListWrapper.remove(ObservableListWrapper.java:167)
    at TestListView.lambda$start$0(TestListView.java:32)
    at TestListView$$Lambda$82/921981528.invalidated(Unknown Source)
    at com.sun.javafx.binding.ExpressionHelper$SingleInvalidation.fireValueChangedEvent(ExpressionHelper.java:137)
    at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
    at javafx.beans.property.ReadOnlyObjectWrapper$ReadOnlyPropertyImpl.fireValueChangedEvent(ReadOnlyObjectWrapper.java:176)
    at javafx.beans.property.ReadOnlyObjectWrapper.fireValueChangedEvent(ReadOnlyObjectWrapper.java:142)
    at javafx.beans.property.ObjectPropertyBase.markInvalid(ObjectPropertyBase.java:112)
    at javafx.beans.property.ObjectPropertyBase.set(ObjectPropertyBase.java:145)
    at javafx.scene.control.SelectionModel.setSelectedItem(SelectionModel.java:102)
    at javafx.scene.control.MultipleSelectionModelBase.lambda$new$34(MultipleSelectionModelBase.java:67)
    at javafx.scene.control.MultipleSelectionModelBase$$Lambda$75/1274395902.invalidated(Unknown Source)
    at com.sun.javafx.binding.ExpressionHelper$SingleInvalidation.fireValueChangedEvent(ExpressionHelper.java:137)
    at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
    at javafx.beans.property.ReadOnlyIntegerWrapper$ReadOnlyPropertyImpl.fireValueChangedEvent(ReadOnlyIntegerWrapper.java:176)
    at javafx.beans.property.ReadOnlyIntegerWrapper.fireValueChangedEvent(ReadOnlyIntegerWrapper.java:142)
    at javafx.beans.property.IntegerPropertyBase.markInvalid(IntegerPropertyBase.java:113)

    at javafx.beans.property.IntegerPropertyBase.set(IntegerPropertyBase.java:146)
    at javafx.scene.control.SelectionModel.setSelectedIndex(SelectionModel.java:68)
    at javafx.scene.control.MultipleSelectionModelBase.select(MultipleSelectionModelBase.java:357)
    at javafx.scene.control.ListView.lambda$new$156(ListView.java:374)
    at javafx.scene.control.ListView$$Lambda$74/963851926.invalidated(Unknown Source)
    at com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:349)
    at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
    at javafx.beans.property.ReadOnlyBooleanPropertyBase.fireValueChangedEvent(ReadOnlyBooleanPropertyBase.java:72)
    at javafx.scene.Node$FocusedProperty.notifyListeners(Node.java:7526)
    at javafx.scene.Scene$13.invalidated(Scene.java:2046)
    at javafx.beans.property.ObjectPropertyBase.markInvalid(ObjectPropertyBase.java:111)
    at javafx.beans.property.ObjectPropertyBase.set(ObjectPropertyBase.java:145)
    at javafx.scene.Scene$KeyHandler.setFocusOwner(Scene.java:3891)
    at javafx.scene.Scene$KeyHandler.requestFocus(Scene.java:3938)
    at javafx.scene.Scene$KeyHandler.access$1900(Scene.java:3877)
    at javafx.scene.Scene.requestFocus(Scene.java:2010)
    at javafx.scene.Node.requestFocus(Node.java:7687)
    at com.sun.javafx.scene.traversal.TopMostTraversalEngine.focusAndNotify(TopMostTraversalEngine.java:92)
    at com.sun.javafx.scene.traversal.TopMostTraversalEngine.traverseToFirst(TopMostTraversalEngine.java:110)
    at javafx.scene.Scene.focusInitial(Scene.java:1980)
    at javafx.scene.Scene.access$3200(Scene.java:144)
    at javafx.scene.Scene$ScenePulseListener.focusCleanup(Scene.java:2330)
    at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2351)
    at com.sun.javafx.tk.Toolkit.lambda$runPulse$28(Toolkit.java:314)
    at com.sun.javafx.tk.Toolkit$$Lambda$154/326451107.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:313)
    at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:340)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:451)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:431)
    at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$363(QuantumToolkit.java:298)
    at com.sun.javafx.tk.quantum.QuantumToolkit$$Lambda$46/1868350875.run(Unknown Source)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
    at com.sun.glass.ui.gtk.GtkApplication.lambda$null$45(GtkApplication.java:126)
    at com.sun.glass.ui.gtk.GtkApplication$$Lambda$42/584634336.run(Unknown Source)
    at java.lang.Thread.run(Thread.java:745)
示例代码:

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import java.util.ArrayList;
import java.util.List;

public class TestListView extends Application {
  @Override
  public void start (Stage stage) {
    List<String> orderList = new ArrayList<String> ();
    ObservableList<String> orderOvList =
      FXCollections.observableList (orderList);
    ListView<String> order = new ListView<String> (orderOvList);

    orderOvList.add ("abc");
    orderOvList.add ("def");
    orderOvList.add ("ghi");
    orderOvList.add ("jkl");

    VBox orderBoxPane = new VBox (6);
    order.getSelectionModel().selectedItemProperty().addListener (
      ov -> {
        int i = order.getSelectionModel ().getSelectedIndex ();

        if (orderOvList.size () >= 0) {
          System.out.println (i);
          orderOvList.remove (i, i + 1);
        }
      });
    orderBoxPane.getChildren ().add (order);

    Scene scene = new Scene (orderBoxPane);
    stage.setTitle ("TestListView");
    stage.setScene (scene);
    stage.show ();
  }
}
导入javafx.application.application;
导入javafx.collections.FXCollections;
导入javafx.collections.ObservableList;
导入javafx.scene.scene;
导入javafx.scene.control.ListView;
导入javafx.scene.layout.VBox;
导入javafx.stage.stage;
导入java.util.ArrayList;
导入java.util.List;
公共类TestListView扩展了应用程序{
@凌驾
公众假期开始(阶段){
List orderList=newarraylist();
可观察列表=
FXCollections.observableList(订单列表);
ListView顺序=新建ListView(orderOvList);
orderOvList.add(“abc”);
orderOvList.add(“def”);
orderOvList.add(“ghi”);
orderOvList.add(“jkl”);
VBox orderBoxPane=新的VBox(6);
order.getSelectionModel().SelectEditeProperty().addListener(
ov->{
int i=order.getSelectionModel().getSelectedIndex();
if(orderOvList.size()>=0){
System.out.println(i);
orderOvList.remove(i,i+1);
}
});
orderBoxPane.getChildren().add(order);
场景=新场景(orderBoxPane);
stage.setTitle(“TestListView”);
舞台场景(场景);
stage.show();
}
}

一旦用户选择删除所选项目,想要编写代码似乎是一种奇怪的用户体验。我不太确定是什么导致了您看到的异常,但您在侦听器中执行的代码确实会更改所选的值,从而在选择模型上引发新的更改事件。(我本以为是
StackOverflowException
而不是
UnsupportedOperationException
。我猜对选择模型中所选项目列表的“嵌套”更改会导致尝试更改不可修改的列表。)

如果这真的是您想要的行为,我会更多地从鼠标按下动作的角度来考虑——当用户单击该项时,将其从列表中删除。您可以通过创建单元格工厂并在所创建的单元格中注册鼠标侦听器来完成此操作:

order.setCellFactory(lv -> {
    ListCell<String> cell = new ListCell<String>() {
        @Override
        public void updateItem(String item, boolean empty) {
            super.updateItem(item, empty);
            setText(item);
        }
    };
    cell.setOnMouseClicked(event -> {
        String item = cell.getItem();
        if (item != null) {
            orderOvList.remove(item);

            // ensure nothing selected after removal:
            order.getSelectionModel().clearSelection();
        }
    });
    return cell ;
});
order.setCellFactory(lv->{
ListCell=新ListCell(){
@凌驾
public void updateItem(字符串项,布尔值为空){
super.updateItem(项,空);
setText(项目);
}
};
cell.setOnMouseClicked(事件->{
String item=cell.getItem();
如果(项!=null){
orderOvList.remove(项目);
//确保删除后未选择任何内容:
order.getSelectionModel().clearSelection();
}
});
返回单元;
});
good solution:-)请注意异常的原因:selectedItems列表中的递归也是我的第一个猜测,但事实并非如此。实际上,这是在触发更改期间对orderList的修改。selectedItem->remove item->selectionModel的客户端通知正在侦听列表更改并更新自身->selectedItem再次触发->客户端通知:这里我们仍然处于第一次删除的通知中,因此在收到通知时违反了无列表修改规则