Ошибка: используйте выбор ChoiceBox для загрузки содержимого во второй ChoiceBox - PullRequest
0 голосов
/ 11 июня 2018

У меня есть пара ChoiceBoxes и метка.

Изменение в ChoiceBox 2 устанавливает метку с выбранным значением в этом.

ChoiceBox 2 имеет содержимое или другое,if изменить выбранное значение в 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 голосов
/ 11 июня 2018

Я немного переработал ваш код.

1-я вещь: Всегда устанавливайте типы на Nodes.

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

2-я вещь: Это ужасная идея, если вы хотите, чтобы 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 );
 });

3-я вещь: Если вы знаете, что вы будете менять 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
...