2014-12-08 153 views
1

我遇到以下Java程序的问题。我在Ubuntu系统上使用JavaFX和JDK-1.8u25。我想显示一个ListView并从列表中删除突出显示的条目。我创建了一个列表,并将其与ObservableList进行配对,以通知监听器事件。但是,看起来通过删除一个项目“orderOvList.remove(i,i + 1)”来更改列表会生成另一个侦听器事件。所以,我似乎在侦听器代码的主体中递归。我想过移动列表元素或从有序列表“orderList.remove(i)”,但然后ListView不更新。在addListener中从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(); 
    } 
} 

回答

1

只要用户选择它删除选定的项目似乎是一个奇怪的用户体验要代码。我不太确定是什么导致了你所看到的异常,但确实是你在监听器中执行的代码会改变选定的值,导致在选择模型上引发新的更改事件。 (我预计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 ; 
}); 
+0

谢谢。这工作。 – 2014-12-08 04:07:40

+1

好的解决方案:-)只是一个关于异常原因的说明:selectedItems列表中的递归也是我的第一个猜测,但不是。实际上,它是orderList在更改时发生的修改。 selectedItem - > remove item - > selectionModel的客户端通知正在监听列表更改并更新自身 - > selectedItem再次触发 - >再次发出客户端通知:这里我们仍然处于第一次删除的通知中,因此违反了无列表修改同时被通知的规则 – kleopatra 2014-12-08 12:28:05