JavaFX组合框更改值会导致IndexOutOfBoundsException [英] JavaFX ComboBox change value causes IndexOutOfBoundsException

查看:2803
本文介绍了JavaFX组合框更改值会导致IndexOutOfBoundsException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想包含对我的组合框的检查,以限制访问某些值。我可以从列表中删除那些不可访问的项目,是的,但我想用户看到其他选项,即使他不能选择它们(尚)。



问题:在changelistener中选择另一个值会导致IndexOutOfBoundsException,我不知道为什么。



这里是一个SSCCE。它创建一个带有Integer值的ComboBox,默认情况下选择第一个。然后我试图保持它很容易:每次更改的值被认为是错误,我将选择改回第一个元素。但仍然,IndexOutOfBounds:

  import javafx.application.Application; 
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.stage.Stage;

public class Tester extends Application {
public static void main(String [] args){
launch(args);
}

@Override
public void start(Stage Stage)throws Exception {
ComboBox< Integer> box = new ComboBox< Integer>();
ObservableList< Integer> vals = FXCollections.observableArrayList(0,1,2,3);

box.setItems(vals);
box.getSelectionModel()。select(0);
/*box.valueProperty().addListener((observable,oldValue,newValue) - > {
box.getSelectionModel()。select(0);
}); * /
/*box.getSelectionModel()。selectedItemProperty()。addListener((observable,oldValue,newValue) - > {
System.out.println(oldValue +,+ newValue);
box.getSelectionModel()。select(0);
}); * /

box.getSelectionModel()。selectedIndexProperty()。addListener((observable,oldValue,newValue) {
System.out.println(oldValue +,+ newValue);
box.getSelectionModel()。select(0);
});
场景场景=新场景(新组(框),500,500);
stage.setScene(scene);
stage.show();
}
}



我使用valueProperty,selectedItemProperty和selectedIndexProperty测试了以及所有这些:

  box.getSelectionModel()。select(0); 

box.getSelectionModel()。selectFirst();

box.getSelectionModel()。selectPrevious();

box.setValue(0);

if(oldValue.intValue()< newValue.intValue())
box.getSelectionModel()。select(oldValue.intValue());

唯一的想法是设置值本身:

  box.getSelectionModel()。select(box.getSelectionModel()。getSelectedIndex()); 
box.setValue(box.getValue));

以下是例外:

 线程JavaFX应用程序线程中的异常java.lang.IndexOutOfBoundsException 
at com.sun.javafx.scene.control.ReadOnlyUnbackedObservableList.subList(未知源)
at javafx。 collections.ListChangeListener $ Change.getAddedSubList(未知源)
at com.sun.javafx.scene.control.behavior.ListViewBehavior.lambda $ new $ 178(未知源)
at com.sun.javafx.scene .control.behavior.ListViewBehavior $$ Lambda $ 126 / 644961012.onChanged(未知源)
at javafx.collections.WeakListChangeListener.onChanged(未知源)
at com.sun.javafx.collections.ListListenerHelper $ Generic .fireValueChangedEvent(未知源)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(未知源)
at com.sun.javafx.scene.control.ReadOnlyUnbackedObservableList.callObservers(未知源)
at javafx.scene.control.MultipleSelectionModelBase.clearAndSelect(未知源)
at javafx.scene.control.ListView $ ListViewBitSetSelectionModel.clearAndSelect(未知源)
at com.sun.javafx.scene.control .behavior.CellBehaviorBase.simpleSelect(未知源)
at com.sun.javafx.scene.control.behavior.CellBehaviorBase.doSelect(未知源)
at com.sun.javafx.scene.control.behavior .CellBehaviorBase.mousePressed(未知源)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase $ 1.handle(未知源)
at com.sun.javafx.scene.control.skin。 BehaviorSkinBase $ 1.handle(未知源)
at com.sun.javafx.event.CompositeEventHandler $ NormalEventHandlerRecord.handleBubblingEvent(未知源)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(未知源)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(未知源)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(未知源)
at com.sun.javafx .event.CompositeEventDispatcher.dispatchBubblingEvent(未知源)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(未知源)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(未知源)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(未知源)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(未知源)
at com.sun.javafx .event.BasicEventDispatcher.dispatchEvent(未知源)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(未知源)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(未知源)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(未知源)
at com.sun.javafx.event.EventUtil.fireEventImpl(未知源)
at com.sun.javafx .event.EventUtil.fireEvent(未知源)
在javafx.event.Event.fireEvent(未知源)
在javafx.scene.Scene $ MouseHandler.process(未知源)
在javafx .scene.Scene $ MouseHandler.access $ 1500(未知源)
at javafx.scene.Scene.impl_processMouseEvent(未知源)
at javafx.scene.Scene $ ScenePeerListener.mouseEvent(未知源)
at com.sun.javafx.tk.quantum.GlassViewEventHandler $ MouseEventNotification.run(未知源)
at com.sun.javafx.tk.quantum.GlassViewEventHandler $ MouseEventNotification.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda $ handleMouseEvent $ 350(未知来源)
at com.sun.javafx.tk.quantum .GlassViewEventHandler $$ Lambda $ 172 / 2037973250.get(未知来源)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(未知来源)
at com.sun.javafx.tk.quantum .GlassViewEventHandler.handleMouseEvent(未知源)
at com.sun.glass.ui.View.handleMouseEvent(未知源)
at com.sun.glass.ui.View.notifyMouse(未知源)
at com.sun.glass.ui.win.WinApplication._runLoop(Native方法)
at com.sun.glass.ui.win.WinApplication.lambda $ null $ 145(未知来源)
at com.sun.glass.ui.win.WinApplication $$ Lambda $ 36 / 2117255219.run(未知来源)
at java.lang.Thread.run(未知来源)



我做错了什么?

解决方案

JavaFX,当更改已在进行时,您不能更改 ObservableList 的内容。这里发生的是,你的监听器(你尝试的任何一个)被触发作为 box.getSelctionModel()的一部分。getSelectedItems() ObservableList 更改。因此,基本上,在处理选择更改时,您无法更改选择。



您的解决方案有点难以操作。如果您对所选项目(或组合框值)有另一个侦听器,即使您的方法工作,它将暂时看到带有非法选择的组合框。例如,在上面的示例中,如果用户尝试选择1,另一个收听者将看到选择改变为不允许的值1,然后返回到0。处理不应该允许在此侦听器中的值可能会使您的程序逻辑非常复杂。



更好的方法是防止用户选择不允许的值。您可以通过设置单元的 disable 属性的单元格工厂执行此操作:

  box.setCellFactory(lv  - > new ListCell< Integer>(){
@Override
public void updateItem(Integer item,boolean empty){
super.updateItem ,空);
if(empty){
setText(null);
} else {
setText(item.toString());
setDisable intValue()!= 0);
}
}
});

在外部样式表中包含以下内容会给用户提供常见的视觉提示,可选择:

  .combo-box-popup .list-cell:disabled {
-fx-opacity:0.4;
}


I want to include checks for my combobox to restrict "access" to some of the values. I could just remove those unaccessible items from the list, yes, but I'd like the user to see the other options, even if he can't select them (yet).

Problem: Selecting another value inside a changelistener causes an IndexOutOfBoundsException, and I have no idea why.

Here is a SSCCE. It creates a ComboBox with Integer values, and the first one is selected on default. Then I tried to keep it very easy: Every change of the value is considered as "wrong" and I change the selection back to the first element. But still, IndexOutOfBounds:

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.stage.Stage;

public class Tester extends Application{
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) throws Exception {
        ComboBox<Integer> box = new ComboBox<Integer>();
        ObservableList<Integer> vals= FXCollections.observableArrayList(0,1,2,3);

        box.setItems(vals);
        box.getSelectionModel().select(0);
        /*box.valueProperty().addListener((observable, oldValue, newValue) -> {
            box.getSelectionModel().select(0);
        });*/
        /*box.getSelectionModel().selectedItemProperty().addListener((observable,oldValue,newValue)->{
            System.out.println(oldValue+","+newValue);
            box.getSelectionModel().select(0);
        });*/

        box.getSelectionModel().selectedIndexProperty().addListener((observable,oldValue,newValue)->{
            System.out.println(oldValue+","+newValue);
            box.getSelectionModel().select(0);
        });
        Scene scene = new Scene(new Group(box),500,500);
        stage.setScene(scene);
        stage.show();
    }
}

I tested it with valueProperty, selectedItemProperty and selectedIndexProperty, as well as all of these:

box.getSelectionModel().select(0);

box.getSelectionModel().selectFirst();

box.getSelectionModel().selectPrevious();

box.setValue(0);

if (oldValue.intValue() < newValue.intValue())
            box.getSelectionModel().select(oldValue.intValue());

The only think that works is setting the value itself:

box.getSelectionModel().select(box.getSelectionModel().getSelectedIndex());
box.setValue(box.getValue));

Here is the exception:

Exception in thread "JavaFX Application Thread" java.lang.IndexOutOfBoundsException
    at com.sun.javafx.scene.control.ReadOnlyUnbackedObservableList.subList(Unknown Source)
    at javafx.collections.ListChangeListener$Change.getAddedSubList(Unknown Source)
    at com.sun.javafx.scene.control.behavior.ListViewBehavior.lambda$new$178(Unknown Source)
    at com.sun.javafx.scene.control.behavior.ListViewBehavior$$Lambda$126/644961012.onChanged(Unknown Source)
    at javafx.collections.WeakListChangeListener.onChanged(Unknown Source)
    at com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(Unknown Source)
    at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(Unknown Source)
    at com.sun.javafx.scene.control.ReadOnlyUnbackedObservableList.callObservers(Unknown Source)
    at javafx.scene.control.MultipleSelectionModelBase.clearAndSelect(Unknown Source)
    at javafx.scene.control.ListView$ListViewBitSetSelectionModel.clearAndSelect(Unknown Source)
    at com.sun.javafx.scene.control.behavior.CellBehaviorBase.simpleSelect(Unknown Source)
    at com.sun.javafx.scene.control.behavior.CellBehaviorBase.doSelect(Unknown Source)
    at com.sun.javafx.scene.control.behavior.CellBehaviorBase.mousePressed(Unknown Source)
    at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(Unknown Source)
    at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(Unknown Source)
    at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(Unknown Source)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(Unknown Source)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source)
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(Unknown Source)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
    at com.sun.javafx.event.EventUtil.fireEventImpl(Unknown Source)
    at com.sun.javafx.event.EventUtil.fireEvent(Unknown Source)
    at javafx.event.Event.fireEvent(Unknown Source)
    at javafx.scene.Scene$MouseHandler.process(Unknown Source)
    at javafx.scene.Scene$MouseHandler.access$1500(Unknown Source)
    at javafx.scene.Scene.impl_processMouseEvent(Unknown Source)
    at javafx.scene.Scene$ScenePeerListener.mouseEvent(Unknown Source)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(Unknown Source)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$350(Unknown Source)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$$Lambda$172/2037973250.get(Unknown Source)
    at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(Unknown Source)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(Unknown Source)
    at com.sun.glass.ui.View.handleMouseEvent(Unknown Source)
    at com.sun.glass.ui.View.notifyMouse(Unknown Source)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$145(Unknown Source)
    at com.sun.glass.ui.win.WinApplication$$Lambda$36/2117255219.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)

What am I doing wrong?

解决方案

In JavaFX, you cannot change the contents of an ObservableList while a change is already in progress. What is happening here is that your listeners (any of the ones you try) are being fired as part of the box.getSelctionModel().getSelectedItems() ObservableList changing. So basically, you cannot change the selection while a selection change is being processed.

Your solution is a bit unwieldy anyway. If you had another listener on the selected item (or combo box value), even if your method worked it would temporarily see the combo box with an "illegal" selection. E.g in the example above, if the user tries to select "1", another listener would see the selection change to the disallowed value "1", then back to "0". Dealing with values that are not supposed to be allowed in this listener would likely make your program logic pretty complex.

A better approach, imho, is to prevent the user from selecting the disallowed values. You can do this with a cell factory that sets the disable property of the cell:

    box.setCellFactory(lv -> new ListCell<Integer>() {
        @Override
        public void updateItem(Integer item, boolean empty) {
            super.updateItem(item, empty);
            if (empty) {
                setText(null);
            } else {
                setText(item.toString());
                setDisable(item.intValue() != 0);
            }
        }
    });

Including the following in an external style sheet will give the user the usual visual hint that the items are not selectable:

.combo-box-popup .list-cell:disabled  {
    -fx-opacity: 0.4 ;
}

这篇关于JavaFX组合框更改值会导致IndexOutOfBoundsException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆