Skip to content

Latest commit

 

History

History
178 lines (131 loc) · 6.85 KB

组合框.md

File metadata and controls

178 lines (131 loc) · 6.85 KB

组合框

ComboBox 是一个混合控件,它显示一个值列表和一个编辑控件。本文演示了ComboBox 的一种基本形式,它是基于复杂数据结构构建的不可编辑的项列表。

这个截图显示了一个包含费用账户列表的 ComboBoxApp。帐户存储在一个键/值JavaFX类Pair中。在用户选择 “Auto Expense” 后,控制台显示保存操作的结果。

combobox

这段代码向 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);
    }
}