错误:使用ChoiceBox选项在第二个ChoiceBox中加载内容

时间:2018-06-10 21:33:37

标签: javafx javafx-8

我有一对ChoiceBoxes和一个Label。

ChoiceBox 2中的更改将标签设置为此选定的值。

ChoiceBox 2有内容或其他内容,如果更改ChoiceBox 1中的选定值(ChoiceBox 2中的值取决于ChoiceBox 1中的选择)。

当我使用ChoiceBox 1时,应用程序抛出类型的异常:

java.lang.ArrayIndexOutOfBoundsException: -1

测试代码:

import java.util.List;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.stage.Stage;

/**
 *
 * @author orici
 */
public class MiDoubleChoiceBoxWithDependency extends Application {

    private final Label label = new Label();
    private final String[] contentsA = new String[] {
        "Words 1",
        "Words 2",
        "Words 3"
    };
    private final String[] extra1 = new String[] {
        "AAA",
        "BBB",
        "CCC"
    };
    private final String[] extra2 = new String[] {
        "LLL",
        "MMM",
        "QQQ"
    };
    private final String[] extra3 = new String[] {
        "XXX",
        "YYY",
        "ZZZ"
    };


    public static void main( String[] args ) {
            launch( args );
    }

    @Override
    public void start( Stage stage ) {

        label.setFont( Font.font( "Arial", 25 ));
        label.setText( extra1[0] );


        ////////////////////////////////////////////////////////////////
        // ChoiceBoxes

        ObservableList<String> options1 =
            FXCollections.observableArrayList( extra1 );
        ObservableList<String> options2 =
            FXCollections.observableArrayList( extra2 );
        ObservableList<String> options3 =
            FXCollections.observableArrayList( extra3 );

        // Create the ChoiceBoxes
        ChoiceBox cb1 = new ChoiceBox(
            FXCollections.observableArrayList( contentsA ));
        final ChoiceBox cb2 = new ChoiceBox();
        cb2.getItems().addAll(options1);

        // Default values for the ChoiceBoxes
        cb1.setValue( contentsA[0] );        // by value
        cb2.getSelectionModel().select( 0 ); // by position


        // Set the ChoiceBox 1 listener
        cb1.getSelectionModel( ).selectedIndexProperty( ).addListener(
            ( ov, oldVal, newVal ) -> {
                trace("cb1 listener");
                cb2.getItems().clear();

                // change second ChoiceBox values
                int optionSelected = newVal.intValue();

                if (optionSelected == 0)
                    cb2.getItems().addAll(options1);
                if (optionSelected == 1)
                    cb2.getItems().addAll(options2);
                if (optionSelected == 2)
                    cb2.getItems().addAll(options3);

                // select the item in position 0
                cb2.getSelectionModel().select( 0 ); // by position
            }
        );

        // Set the ChoiceBox 2 listener
        cb2.getSelectionModel( ).selectedIndexProperty( ).addListener(
            ( ov, oldVal, newVal ) -> {
                trace("cb2 listener");

                // change label
                int optionSelected = newVal.intValue();
                List options  = cb2.getItems();
                String option = options.get(optionSelected).toString();
                label.setText( option );
            }
        );


        ////////////////////////////////////////////////////////////////
        // place GUI elements
        HBox hb = new HBox();
        hb.getChildren( ).addAll( cb1, cb2, label );
        hb.setSpacing( 30 );
        hb.setAlignment( Pos.CENTER );
        hb.setPadding( new Insets( 10, 0, 0, 10 ));

        Scene scene = new Scene( hb, 400, 200 );
        scene.setFill( Color.ALICEBLUE );
        stage.setTitle( "2 ChoiceBoxes with control" );
        stage.setScene( scene );
        stage.show();
    }

    private void trace(String str) {
        System.out.println(str);
    }

} //class

完成异常追踪:

Exception in thread "JavaFX Application Thread" java.lang.ArrayIndexOutOfBoundsException: -1
    at java.util.ArrayList.elementData(ArrayList.java:422)
    at java.util.ArrayList.get(ArrayList.java:435)
    at com.sun.javafx.collections.ObservableListWrapper.get(ObservableListWrapper.java:89)
    at controles.MiDoubleChoiceBoxWithDependency.lambda$start$1(MiDoubleChoiceBoxWithDependency.java:113)
    at com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:361)
    at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
    at javafx.beans.property.ReadOnlyIntegerPropertyBase.fireValueChangedEvent(ReadOnlyIntegerPropertyBase.java:72)
    at javafx.beans.property.ReadOnlyIntegerWrapper.fireValueChangedEvent(ReadOnlyIntegerWrapper.java:102)
    at javafx.beans.property.IntegerPropertyBase.markInvalid(IntegerPropertyBase.java:113)
    at javafx.beans.property.IntegerPropertyBase.set(IntegerPropertyBase.java:147)
    at javafx.scene.control.SelectionModel.setSelectedIndex(SelectionModel.java:68)
    at javafx.scene.control.SingleSelectionModel.updateSelectedIndex(SingleSelectionModel.java:215)
    at javafx.scene.control.SingleSelectionModel.clearSelection(SingleSelectionModel.java:68)
    at javafx.scene.control.ChoiceBox.lambda$new$138(ChoiceBox.java:281)
    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.clear(ObservableListWrapper.java:157)
    at controles.MiDoubleChoiceBoxWithDependency.lambda$start$0(MiDoubleChoiceBoxWithDependency.java:88)
    at com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:361)
    at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
    at javafx.beans.property.ReadOnlyIntegerPropertyBase.fireValueChangedEvent(ReadOnlyIntegerPropertyBase.java:72)
    at javafx.beans.property.ReadOnlyIntegerWrapper.fireValueChangedEvent(ReadOnlyIntegerWrapper.java:102)
    at javafx.beans.property.IntegerPropertyBase.markInvalid(IntegerPropertyBase.java:113)
    at javafx.beans.property.IntegerPropertyBase.set(IntegerPropertyBase.java:147)
    at javafx.scene.control.SelectionModel.setSelectedIndex(SelectionModel.java:68)
    at javafx.scene.control.SingleSelectionModel.updateSelectedIndex(SingleSelectionModel.java:215)
    at javafx.scene.control.SingleSelectionModel.select(SingleSelectionModel.java:149)
    at javafx.scene.control.ChoiceBox$ChoiceBoxSelectionModel.select(ChoiceBox.java:573)
    at com.sun.javafx.scene.control.skin.ChoiceBoxSkin.lambda$addPopupItem$284(ChoiceBoxSkin.java:261)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
    at javafx.event.Event.fireEvent(Event.java:198)
    at javafx.scene.control.MenuItem.fire(MenuItem.java:462)
    at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer.doSelect(ContextMenuContent.java:1405)
    at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer.lambda$createChildren$343(ContextMenuContent.java:1358)
cb2 listener
    at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
    at javafx.event.Event.fireEvent(Event.java:198)
    at javafx.scene.Scene$MouseHandler.process(Scene.java:3757)
    at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485)
    at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
    at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:394)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:295)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$353(GlassViewEventHandler.java:432)
    at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:431)
    at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
    at com.sun.glass.ui.View.notifyMouse(View.java:937)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$147(WinApplication.java:177)
    at java.lang.Thread.run(Thread.java:748)

1 个答案:

答案 0 :(得分:1)

我稍微重构了你的代码。

第一件事:始终在Nodes上设置类型。

final ChoiceBox<String> cb1 = new ChoiceBox();
final ChoiceBox<String> cb2 = new ChoiceBox();

第二件事:如果你想要String回来,这是一个糟糕的主意。

cb2.getSelectionModel( ).selectedIndexProperty( ).addListener(
( ov, oldVal, newVal ) -> {
    trace("cb2 listener");

    // change label
    int optionSelected = newVal.intValue();
    List options  = cb2.getItems();
    String option = options.get(optionSelected).toString();
    label.setText( option );
});

你应该这样做:

// Set the ChoiceBox 2 listener
cb2.getSelectionModel().selectedItemProperty().addListener(
( ov, oldVal, newVal ) -> {
    trace("cb2 listener");
    // change label                
    label.setText( newVal );
 });

第三件事:如果您知道自己将更改Collection上的Node,请使用setAll()代替addAll()

  

完整代码:

import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.stage.Stage;

/**
 *
 * @author orici
 */
public class MiDoubleChoiceBoxWithDependency extends Application {

    private final Label label = new Label();
    private final String[] contentsA = new String[] {
        "Words 1",
        "Words 2",
        "Words 3"
    };
    private final String[] extra1 = new String[] {
        "AAA",
        "BBB",
        "CCC"
    };
    private final String[] extra2 = new String[] {
        "LLL",
        "MMM",
        "QQQ"
    };
    private final String[] extra3 = new String[] {
        "XXX",
        "YYY",
        "ZZZ"
    };


    public static void main( String[] args ) {
            launch( args );
    }

    @Override
    public void start( Stage stage ) {

        label.setFont( Font.font( "Arial", 25 ));
        label.setText( extra1[0] );


        ////////////////////////////////////////////////////////////////
        // ChoiceBoxes

        ObservableList<String> options1 =
            FXCollections.observableArrayList( extra1 );
        ObservableList<String> options2 =
            FXCollections.observableArrayList( extra2 );
        ObservableList<String> options3 =
            FXCollections.observableArrayList( extra3 );

        // Create the ChoiceBoxes
        final ChoiceBox<String> cb1 = new ChoiceBox(
            FXCollections.observableArrayList( contentsA ));
        final ChoiceBox<String> cb2 = new ChoiceBox();
        cb2.getItems().addAll(options1);

        // Default values for the ChoiceBoxes
        cb1.setValue(contentsA[0]);        // by value
        cb2.getSelectionModel().select( 0 ); // by position


        // Set the ChoiceBox 1 listener
        cb1.getSelectionModel( ).selectedIndexProperty( ).addListener(
            ( ov, oldVal, newVal ) -> {
                trace("cb1 listener");

                // change second ChoiceBox values
                int optionSelected = newVal.intValue();

                if (optionSelected == 0)
                    cb2.getItems().setAll(options1);
                if (optionSelected == 1)
                    cb2.getItems().setAll(options2);
                if (optionSelected == 2)
                    cb2.getItems().setAll(options3);

                // select the item in position 0
                cb2.getSelectionModel().select( 0 ); // by position
            }
        );

        // Set the ChoiceBox 2 listener
        cb2.getSelectionModel().selectedItemProperty().addListener(
            ( ov, oldVal, newVal ) -> {
                trace("cb2 listener");

                // change label                
                label.setText( newVal );
            }
        );


        ////////////////////////////////////////////////////////////////
        // place GUI elements
        HBox hb = new HBox();
        hb.getChildren( ).addAll( cb1, cb2, label );
        hb.setSpacing( 30 );
        hb.setAlignment( Pos.CENTER );
        hb.setPadding( new Insets( 10, 0, 0, 10 ));

        Scene scene = new Scene( hb, 400, 200 );
        scene.setFill( Color.ALICEBLUE );
        stage.setTitle( "2 ChoiceBoxes with control" );
        stage.setScene( scene );
        stage.show();
    }

    private void trace(String str) {
        System.out.println(str);
    }

} //class