文档



JavaFX:使用JavaFX UI组件

16 组合框

本章介绍如何在JavaFX应用程序中使用组合框。它讨论了可编辑和不可编辑的组合框,教你如何跟踪可编辑组合框的更改并处理其上的事件,并解释了如何使用单元格工厂来修改组合框的默认实现。

组合框是用户界面的典型元素,它使用户可以选择多个选项之一。当要显示的项目数量超过某个限制时,组合框非常有用,因为它可以在下拉列表中添加滚动条,而不像选择框。如果项目数量不超过某个限制,开发人员可以决定组合框还是选择框更适合他们的需求。

您可以使用JavaFX API的ComboBox类在JavaFX应用程序中创建组合框。 图16-1显示了一个带有两个组合框的应用程序。

图16-1 带有两个组合框的应用程序

图16-1的描述
"图16-1 带有两个组合框的应用程序"的描述

创建组合框

创建组合框时,您必须实例化ComboBox类,并将项目定义为可观察列表,就像其他UI控件(如ChoiceBoxListViewTableView)一样。在示例16-1中,将项目设置在构造函数中。

示例16-1 使用可观察列表创建组合框

ObservableList<String> options = 
    FXCollections.observableArrayList(
        "选项1",
        "选项2",
        "选项3"
    );
final ComboBox comboBox = new ComboBox(options);

另一种可能性是使用空构造函数创建组合框,并在其上调用setItems方法,如下所示:comboBox.setItems(options);

当将组合框添加到应用程序场景中时,它会显示在用户界面中,如图16-2所示。

图16-2 有三个项目的组合框

图16-2的描述
"图16-2 有三个项目的组合框"的描述

您可以随时使用新值补充项目列表。通过示例16-2,可以通过向comboBox控件添加三个项目来实现此任务。

示例16-2 向组合框添加项目

comboBox.getItems().addAll(
    "选项4",
    "选项5",
    "选项6"
);

ComboBox类提供了方便的属性和方法与组合框一起使用。

您可以使用setValue方法指定组合框中选定的项目。当您在ComboBox对象上调用setValue方法时,selectionModel属性的选定项目将更改为此值,即使该值不在组合框项目列表中。如果项目列表随后更改以包括此值,则相应的项目将被选中。

类似地,您可以通过调用getValue方法获取所选项目的值。当用户选择项目时,selectionModel属性的选定项目和组合框的value属性都会更新为新值。

当显示ComboBox下拉列表时,您还可以限制可见行数。以下代码行启用comboBox控件的显示三个项目:comboBox.setVisibleRowCount(3) 调用此方法后,可见行数限制为三行,并出现滚动条(如图16-3所示)。

图16-3 设置ComboBox的可见行数

图16-3的描述
"图16-3 设置ComboBox的可见行数"的描述

尽管ComboBox类具有通用的表示法,并允许用户使用各种类型的项目填充它,但不要将Node(或任何子类)作为类型。因为场景图概念意味着应用场景中只能有一个Node对象,所以选择的项目将从ComboBox项目列表中移除。当选择更改时,先前选择的项目返回到列表中,新选择被移除。为了防止这种情况发生,使用单元格工厂机制和API文档中描述的解决方案。当您需要更改ComboBox对象的初始行为或外观时,单元格工厂机制特别有用。

ComboBoxSample应用程序旨在演示如何在典型的电子邮件界面中使用组合框。 示例16-3创建了这样一个界面,其中使用了两个组合框来选择电子邮件的收件人和消息的优先级。

示例 16-3 创建组合框并将其添加到场景中

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
 
public class ComboBoxSample extends Application {
    public static void main(String[] args) {
        launch(args);
    }
        
    final Button button = new Button ("发送");
    final Label notification = new Label ();
    final TextField subject = new TextField("");
    final TextArea text = new TextArea ("");
    
    String address = " ";
    
    @Override public void start(Stage stage) {
        stage.setTitle("ComboBoxSample");
        Scene scene = new Scene(new Group(), 500, 270);
        
        final ComboBox emailComboBox = new ComboBox();
        emailComboBox.getItems().addAll(
            "jacob.smith@example.com",
            "isabella.johnson@example.com",
            "ethan.williams@example.com",
            "emma.jones@example.com",
            "michael.brown@example.com"  
        );
        
        final ComboBox priorityComboBox = new ComboBox();
        priorityComboBox.getItems().addAll(
            "最高",
            "高",
            "普通",
            "低",
            "最低" 
        );   

        priorityComboBox.setValue("普通");
        
        GridPane grid = new GridPane();
        grid.setVgap(4);
        grid.setHgap(10);
        grid.setPadding(new Insets(5, 5, 5, 5));
        grid.add(new Label("收件人: "), 0, 0);
        grid.add(emailComboBox, 1, 0);
        grid.add(new Label("优先级: "), 2, 0);
        grid.add(priorityComboBox, 3, 0);
        grid.add(new Label("主题: "), 0, 1);
        grid.add(subject, 1, 1, 3, 1);            
        grid.add(text, 0, 2, 4, 1);
        grid.add(button, 0, 3);
        grid.add (notification, 1, 3, 3, 1);
        
        Group root = (Group)scene.getRoot();
        root.getChildren().add(grid);
        stage.setScene(scene);
        stage.show();
    }    
}

示例 16-3中,两个组合框都使用getItemsaddAll方法来添加项目。当您编译和运行此代码时,它会产生图 16-4中显示的应用程序窗口。

图 16-4 电子邮件收件人和优先级组合框

图 16-4 的描述
"图 16-4 电子邮件收件人和优先级组合框"的描述

可编辑的组合框

通常,电子邮件客户端应用程序允许用户从通讯录中选择收件人并输入新的地址。可编辑的组合框非常适合这个任务。使用ComboBox类的setEditable(true)方法使组合框可编辑。使用setPromptText方法,您可以指定在未进行选择时出现在组合框编辑区域的文本。查看示例16-4中应用程序的修改代码。粗体行是对示例16-3进行的添加。

示例16-4:处理可编辑组合框中新输入的值

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
 
public class ComboBoxSample extends Application {
        public static void main(String[] args) {
        launch(args);
    }
    
    final Button button = new Button ("发送");
    final Label notification = new Label ();
    final TextField subject = new TextField("");
    final TextArea text = new TextArea ("");
    
    String address = " ";
    
    @Override public void start(Stage stage) {
        stage.setTitle("ComboBoxSample");
        Scene scene = new Scene(new Group(), 500, 270);
        
        final ComboBox emailComboBox = new ComboBox();
        emailComboBox.getItems().addAll(
            "jacob.smith@example.com",
            "isabella.johnson@example.com",
            "ethan.williams@example.com",
            "emma.jones@example.com",
            "michael.brown@example.com"  
        );
        emailComboBox.setPromptText("电子邮件地址");
        emailComboBox.setEditable(true);        
        emailComboBox.setOnAction((Event ev) -> {
            address = 
                emailComboBox.getSelectionModel().getSelectedItem().toString();    
        });
        
        final ComboBox priorityComboBox = new ComboBox();
        priorityComboBox.getItems().addAll(
            "最高",
            "高",
            "普通",
            "低",
            "最低" 
        );   

        priorityComboBox.setValue("普通");
     
        button.setOnAction((ActionEvent e) -> {
            if (emailComboBox.getValue() != null && 
                    !emailComboBox.getValue().toString().isEmpty()){
                notification.setText("您的消息已成功发送"
                        + "给" + address);
                emailComboBox.setValue(null);
                if (priorityComboBox.getValue() != null &&
                        !priorityComboBox.getValue().toString().isEmpty()){
                    priorityComboBox.setValue(null);
                }
                subject.clear();
                text.clear();
            }
            else {
                notification.setText("您尚未选择收件人!");
            }
        });

        GridPane grid = new GridPane();
        grid.setVgap(4);
        grid.setHgap(10);
        grid.setPadding(new Insets(5, 5, 5, 5));
        grid.add(new Label("收件人:"), 0, 0);
        grid.add(emailComboBox, 1, 0);
        grid.add(new Label("优先级:"), 2, 0);
        grid.add(priorityComboBox, 3, 0);
        grid.add(new Label("主题:"), 0, 1);
        grid.add(subject, 1, 1, 3, 1);            
        grid.add(text, 0, 2, 4, 1);
        grid.add(button, 0, 3);
        grid.add (notification, 1, 3, 3, 1);
        
        Group root = (Group)scene.getRoot();
        root.getChildren().add(grid);
        stage.setScene(scene);
        stage.show();
    }
}

除了能够编辑emailComboBox之外,这段代码片段还实现了对该控件的事件处理。新输入或选择的值存储在address变量中。当用户按下发送按钮时,将显示包含电子邮件地址的通知。

图16-5捕捉了用户正在编辑Jacob Smith的电子邮件地址并将其更改为greg.smith@example.com的时刻。

图16-5 编辑电子邮件地址

图16-5的描述如下
"图16-5 编辑电子邮件地址"的描述

当按下发送按钮时,所有控件都返回到默认状态。在TextFieldTextArea对象上调用clear方法,并为组合框的选定项设置null值。 图16-6显示了按下发送按钮后的时刻。

图16-6 发送按钮按下后的用户界面

图16-6的描述如下
"图16-6 发送按钮按下后的用户界面"的描述

将单元格工厂应用于组合框

您可以使用单元格工厂机制来更改组合框的默认行为或外观。 示例16-5 创建一个单元格工厂,并将其应用于优先级组合框,以突出显示具有特殊颜色的优先级类型。

示例16-5:为优先级下拉框实现一个单元格工厂

import javafx.scene.paint.Color;
import javafx.util.Callback;
new Callback<ListView<String>, ListCell<String>>() {
@Override public ListCell<String> call(ListView<String> param) {
final ListCell<String> cell = new ListCell<String>() {
{
super.setPrefWidth(100);
}
@Override public void updateItem(String item,
boolean empty) {
super.updateItem(item, empty);
if (item != null) {
setText(item);
if (item.contains("High")) {
setTextFill(Color.RED);
}
else if (item.contains("Low")){
setTextFill(Color.GREEN);
}
else {
setTextFill(Color.BLACK);
}
}
else {
 setText(null);
}
}
};
return cell;
}
});

单元格工厂生成ListCell对象。每个单元格与一个组合框项目关联。通过setPrefWidth方法设置每个组合框项目的宽度。updateItem方法为高优先级和最高优先级的项目设置红色,为低优先级和最低优先级的项目设置绿色,而将普通项目保持为黑色。

图16-7显示了在示例16-5中应用单元格工厂后的优先级组合框项目。

图16-7 修改后的优先级组合框

图16-7的描述
"图16-7 修改后的优先级组合框"的描述

您可以通过应用CSS样式或视觉效果进一步增强ComboBox控件的外观。

相关API文档 

关闭窗口

目录

JavaFX:使用JavaFX UI组件

展开 折叠