2014-12-08 115 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