我有一对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)
答案 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