ComboBox 是一个混合控件,它显示一个值列表和一个编辑控件。本文演示了ComboBox 的一种基本形式,它是基于复杂数据结构构建的不可编辑的项列表。
这个截图显示了一个包含费用账户列表的 ComboBoxApp。帐户存储在一个键/值JavaFX类Pair中。在用户选择 “Auto Expense” 后,控制台显示保存操作的结果。
这段代码向 HBox 添加了一个标签、一个组合框和一个按钮。ComboBox 被实例化为一个字段,并在稍后的 initCombo()方法中初始化。在 Save Button 上放置一个处理程序,如果选择了项,则输出一个值,如果没有选择项,则输出一个特殊消息。
CombosApp.class
public class CombosApp extends Application {
private final ComboBox<Pair<String, String>> account = new ComboBox<>();
private final static Pair<String, String> EMPTY_PAIR = new Pair<>("", "");
@Override
public void start(Stage primaryStage) throws Exception {
Label accountsLabel = new Label("Account:");
account.setPrefWidth(200);
Button saveButton = new Button("Save");
HBox hbox = new HBox(
accountsLabel,
account,
saveButton);
hbox.setSpacing( 10.0d );
hbox.setAlignment(Pos.CENTER );
hbox.setPadding( new Insets(40) );
Scene scene = new Scene(hbox);
initCombo();
saveButton.setOnAction( (evt) -> {
if( account.getValue().equals(EMPTY_PAIR) ) {
System.out.println("no save needed; no item selected");
} else {
System.out.println("saving " + account.getValue());
}
});
primaryStage.setTitle("CombosApp");
primaryStage.setScene( scene );
primaryStage.show();
}
initCombo() 方法将几个费用帐户添加到 List 中。在添加空 Pair 对象后,此列表将添加到组合框项中。初始值设置为EMPTY_PAIR,这是一个常量。
如果没有指定,则 ComboBox 将使用对象(在本文中是 Pair )的 toString() 方法来呈现后备对象。对于字符串,例如 “Yes” 或 “No” 选择,不需要额外的代码。然而,Pair 的 toString() 将输出人类可读的键和机器首选的值。这个 ComboBox 的要求是在显示中只使用人类可读的键。
为此,提供了一个 cellFactory,它将配置一个 ListCell 对象,并将 Pair 键作为内容。Callback 类型是冗长的,但是工厂的要点是在匿名内部类的 updateItem() 方法中设置 ListCell 的文本。注意,必须调用超类方法。
private void initCombo() {
List<Pair<String,String>> accounts = new ArrayList<>();
accounts.add( new Pair<>("Auto Expense", "60000") );
accounts.add( new Pair<>("Interest Expense", "61000") );
accounts.add( new Pair<>("Office Expense", "62000") );
accounts.add( new Pair<>("Salaries Expense", "63000") );
account.getItems().add( EMPTY_PAIR );
account.getItems().addAll( accounts );
account.setValue( EMPTY_PAIR );
Callback<ListView<Pair<String,String>>, ListCell<Pair<String,String>>> factory =
(lv) ->
new ListCell<Pair<String,String>>() {
@Override
protected void updateItem(Pair<String, String> item, boolean empty) {
super.updateItem(item, empty);
if( empty ) {
setText("");
} else {
setText( item.getKey() );
}
}
};
account.setCellFactory( factory );
account.setButtonCell( factory.call( null ) );
}
Callback 在 setButtonCell() 方法中使用,为编辑控件提供单元格。请注意,这个程序是不可编辑的,这是默认的。然而,factory.call (null) 是必需的,否则只有弹出菜单的内容将被正确格式化,而静态控件的视图将回退到 toString()。
本文介绍了 ComboBox 的一个简单用法。由于此控件不可编辑,因此可以替换为 ChoiceBox。对于不可编辑的图形呈现(例如状态值的颜色编码形状),仍然需要 ComboBox 来定义控件中使用的特定 Node。
代码可以在单个.java文件中进行测试。
CombosApp.class
public class CombosApp extends Application {
private final ComboBox<Pair<String, String>> account = new ComboBox<>();
private final static Pair<String, String> EMPTY_PAIR = new Pair<>("", "");
@Override
public void start(Stage primaryStage) throws Exception {
Label accountsLabel = new Label("Account:");
account.setPrefWidth(200);
Button saveButton = new Button("Save");
HBox hbox = new HBox(
accountsLabel,
account,
saveButton);
hbox.setSpacing( 10.0d );
hbox.setAlignment(Pos.CENTER );
hbox.setPadding( new Insets(40) );
Scene scene = new Scene(hbox);
initCombo();
saveButton.setOnAction( (evt) -> {
if( account.getValue().equals(EMPTY_PAIR ) ) {
System.out.println("no save needed; no item selected");
} else {
System.out.println("saving " + account.getValue());
}
});
primaryStage.setTitle("CombosApp");
primaryStage.setScene( scene );
primaryStage.show();
}
private void initCombo() {
List<Pair<String,String>> accounts = new ArrayList<>();
accounts.add( new Pair<>("Auto Expense", "60000") );
accounts.add( new Pair<>("Interest Expense", "61000") );
accounts.add( new Pair<>("Office Expense", "62000") );
accounts.add( new Pair<>("Salaries Expense", "63000") );
account.getItems().add( EMPTY_PAIR );
account.getItems().addAll( accounts );
account.setValue( EMPTY_PAIR );
Callback<ListView<Pair<String,String>>, ListCell<Pair<String,String>>> factory =
(lv) ->
new ListCell<Pair<String,String>>() {
@Override
protected void updateItem(Pair<String, String> item, boolean empty) {
super.updateItem(item, empty);
if( empty ) {
setText("");
} else {
setText( item.getKey() );
}
}
};
account.setCellFactory( factory );
account.setButtonCell( factory.call( null ) );
}
public static void main(String[] args) {
launch(args);
}
}