本文内容转载自JavaFXChina,部分内容或代码有修改。本文我只列举了部分较为常用的组件,完整的组件文档可以去JavaFXChina学习。本站其余组件相关的知识我也会在整个javafx基础都涉及一遍后再新开文章更新。本文使用到的图片等资源可以去这里下载,完整项目点击这里下载。如果运行失败,检查编译之后的目录中是否存在对应静态资源。本文的重点是了解各种组件,与布局相关的知识暂时只需要了解,后面会单独学习布局相关内容。

  1. 标签(label)
    label可以用来展示文字,图片等信息。具体用法参考下方代码和注释。
public class TestUI extends Application {
    Label label3 = new Label("A label that needs to be wrapped");

    @Override
    public void start(Stage stage) {
        stage.setTitle("Label Sample");
        stage.setWidth(420);
        stage.setHeight(180);

        Image image = new Image(getClass().getResourceAsStream("/labels.jpg"));

        Label label1 = new Label("Search");//参数为文字内容
        label1.setGraphic(new ImageView(image));//显示图片
        label1.setFont(new Font("Arial", 30));//设置字体
        label1.setTextFill(Color.web("#0076a3"));//文字颜色
        label1.setTextAlignment(TextAlignment.JUSTIFY);//对齐方向

        Label label2 = new Label("Values");
        label2.setFont(Font.font("Cambria", 32));
        label2.setRotate(270);//顺时针旋转270度
        label2.setTranslateY(50);//Y轴移动

        label3.setWrapText(true);//启用文本折叠换行
        label3.setTranslateY(50);
        label3.setPrefWidth(100);

        label3.setOnMouseEntered((MouseEvent e) -> {//鼠标移入事件
            label3.setScaleX(1.5);//X方向缩放倍数
            label3.setScaleY(1.5);//Y方向缩放倍数
        });

        label3.setOnMouseExited((MouseEvent e) -> {//鼠标移出事件
            label3.setScaleX(1);
            label3.setScaleY(1);
        });

        HBox hbox = new HBox();
        hbox.setSpacing(10);//内部组件之间的距离
        hbox.getChildren().add((label1));
        hbox.getChildren().add(label2);
        hbox.getChildren().add(label3);

        Scene scene = new Scene(new Group());
        ((Group) scene.getRoot()).getChildren().add(hbox);
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}
  1. 按钮(button)
    按钮可以有文字和图标。
public class TestButton extends Application {

    private static final Color color = Color.web("#464646");
    Button button3 = new Button("Decline");
    DropShadow shadow = new DropShadow();
    Label label = new Label();


    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) {
        Scene scene = new Scene(new Group());
        stage.setTitle("Button Sample");
        stage.setWidth(300);//设置宽度
        stage.setHeight(190);//设置高度
        scene.getStylesheets().add("/button.css");//使用css

        label.setFont(Font.font("Times New Roman", 22));//字体
        label.setTextFill(color);//颜色

        Image imageDecline = new Image(getClass().getResourceAsStream("/not.png"));
        Image imageAccept = new Image(getClass().getResourceAsStream("/ok.png"));

        VBox vbox = new VBox();
        vbox.setLayoutX(20);
        vbox.setLayoutY(20);
        HBox hbox1 = new HBox();
        HBox hbox2 = new HBox();

        Button button1 = new Button("Accept", new ImageView(imageAccept));//创建有图标和文字的按钮
        button1.getStyleClass().add("button1");//新增class叫button1,类似html的class="button1"
        button1.setOnAction((ActionEvent e) -> {
            label.setText("Accepted");
        });


        Button button2 = new Button("Accept");
        button2.setOnAction((ActionEvent e) -> {//按钮点击触发
            label.setText("Accepted");
        });

        button3.setOnAction((ActionEvent e) -> {
            label.setText("Declined");
        });

        button3.addEventHandler(MouseEvent.MOUSE_ENTERED, (MouseEvent e) -> {//鼠标移入触发
            button3.setEffect(shadow);
        });

        button3.addEventHandler(MouseEvent.MOUSE_EXITED, (MouseEvent e) -> {//鼠标移除触发
            button3.setEffect(null);
        });

        hbox1.getChildren().add(button2);
        hbox1.getChildren().add(button3);
        hbox1.getChildren().add(label);
        hbox1.setSpacing(10);
        hbox1.setAlignment(Pos.BOTTOM_CENTER);

        Button button4 = new Button();
        button4.setGraphic(new ImageView(imageAccept));
        button4.setOnAction((ActionEvent e) -> {
            label.setText("Accepted");
        });


        Button button5 = new Button();
        button5.setGraphic(new ImageView(imageDecline));
        button5.setOnAction((ActionEvent e) -> {
            label.setText("Declined");
        });

        hbox2.getChildren().add(button4);
        hbox2.getChildren().add(button5);
        hbox2.setSpacing(25);

        vbox.getChildren().add(button1);
        vbox.getChildren().add(hbox1);
        vbox.getChildren().add(hbox2);
        vbox.setSpacing(10);
        ((Group)scene.getRoot()).getChildren().add(vbox);

        stage.setScene(scene);
        stage.show();
    }
}
  1. 单选按钮(RadioButton)
public class TestRadioButton extends Application {

    final ImageView icon = new ImageView();
    
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) {
        Scene scene = new Scene(new Group());
        stage.setTitle("Radio Button Sample");
        stage.setWidth(250);
        stage.setHeight(150);

        final ToggleGroup group = new ToggleGroup();

        RadioButton rb1 = new RadioButton("Home");//创建一个文字内容为Home的单选按钮
        rb1.setToggleGroup(group);//放入同一个group中的单选按钮不能同时选中
        rb1.setUserData("Home");//设置该单选按钮绑定的值,值可以和显示内容不一样

        RadioButton rb2 = new RadioButton("Calendar");
        rb2.setToggleGroup(group);
        rb2.setUserData("Calendar");

        RadioButton rb3 = new RadioButton("Contacts");
        rb3.setToggleGroup(group);
        rb3.setUserData("Contacts");

        group.selectedToggleProperty().addListener(//单选按钮选择之后触发
            (ObservableValue<? extends Toggle> ov, Toggle old_toggle, 
            Toggle new_toggle) -> {
                if (group.getSelectedToggle() != null) {
                    final Image image = new Image(//根据选择的不同按钮获取对应的值,计算出不同图片路径,用以展示。
                            Objects.requireNonNull(getClass().getClassLoader().getResourceAsStream(
                                    group.getSelectedToggle().getUserData().toString() +
                                            ".jpg"
                            ))
                        );
                icon.setImage(image);
            }
        });
        
        HBox hbox = new HBox();
        VBox vbox = new VBox();

        vbox.getChildren().add(rb1);
        vbox.getChildren().add(rb2);
        vbox.getChildren().add(rb3);
        vbox.setSpacing(10);

        hbox.getChildren().add(vbox);
        hbox.getChildren().add(icon);
        hbox.setSpacing(50);
        hbox.setPadding(new Insets(20, 10, 10, 20));

        ((Group) scene.getRoot()).getChildren().add(hbox);
        stage.setScene(scene);
        stage.show(); 
    }
}
  1. 开关按钮(ToggleButton)
    开关按钮和单选按钮区别:在点击已经被选中的开关按钮时可以取消选中,而单选按钮不行。
public class TestToggleButton extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) {
        stage.setTitle("Toggle Button Sample");
        stage.setWidth(250);
        stage.setHeight(180);

        Rectangle rect = new Rectangle();//矩形框
        rect.setHeight(50);//高度
        rect.setFill(Color.WHITE);//内部填充颜色
        rect.setStroke(Color.DARKGRAY);//边框颜色
        rect.setStrokeWidth(2);//边框宽度
        rect.setArcHeight(10);//边角变圆
        rect.setArcWidth(10);//边角变圆

        final ToggleGroup group = new ToggleGroup();

        //点击开关按钮时触发,每次点击都会触发
        group.selectedToggleProperty().addListener(
                //oldToggle之前被选中的,newToggle之后被选中的
                (observableValue, oldToggle, newToggle) -> {
                    if (newToggle == null) {
                        rect.setFill(Color.WHITE);
                    } else {
                        rect.setFill((Color) group.getSelectedToggle().getUserData());
                    }
                });

        ToggleButton tb1 = new ToggleButton("Minor");
        tb1.setToggleGroup(group);
        tb1.setUserData(Color.LIGHTGREEN);
        tb1.setSelected(true);
        tb1.getStyleClass().add("toggle-button1");

        ToggleButton tb2 = new ToggleButton("Major");
        tb2.setToggleGroup(group);
        tb2.setUserData(Color.LIGHTBLUE);
        tb2.getStyleClass().add("toggle-button2");

        ToggleButton tb3 = new ToggleButton("Critical");
        tb3.setToggleGroup(group);
        tb3.setUserData(Color.SALMON);
        tb3.getStyleClass().add("toggle-button3");

        HBox hbox = new HBox();
        hbox.getChildren().addAll(tb1, tb2, tb3);
        VBox vbox = new VBox();
        vbox.getChildren().add(new Label("Priority:"));
        vbox.getChildren().add(hbox);
        vbox.getChildren().add(rect);
        vbox.setPadding(new Insets(20, 10, 10, 20));

        Scene scene = new Scene(new Group(vbox));
        stage.setScene(scene);
        scene.getStylesheets().add("/ToggleButton.css");
        stage.show();
        rect.setWidth(hbox.getWidth());
    }
}
  1. 复选框(Checkbox)
public class TestCheckbox extends Application {

    Rectangle rect = new Rectangle(90, 30);
    final String[] names = new String[]{"Security", "Project", "Chart"};
    final Image[] images = new Image[names.length];
    final ImageView[] icons = new ImageView[names.length];
    final CheckBox[] cbs = new CheckBox[names.length];

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) {
        Scene scene = new Scene(new Group());
        stage.setTitle("Checkbox Sample");
        stage.setWidth(250);
        stage.setHeight(150);

        rect.setArcHeight(10);
        rect.setArcWidth(10);
        rect.setFill(Color.rgb(41, 41, 41));

        for (int i = 0; i < names.length; i++) {
            final Image image = images[i] = new Image(Objects.requireNonNull(getClass().getClassLoader().getResourceAsStream(names[i] + ".png")));
            final ImageView icon = icons[i] = new ImageView();
            final CheckBox cb = cbs[i] = new CheckBox(names[i]);
            //每次勾选或取消勾选触发
            cb.selectedProperty().addListener((observableValue, old_val, new_val) -> icon.setImage(new_val ? image : null));
        }

        VBox vbox = new VBox();
        vbox.getChildren().addAll(cbs);
        vbox.setSpacing(5);

        HBox hbox = new HBox();
        hbox.getChildren().addAll(icons);
        hbox.setPadding(new Insets(0, 0, 0, 5));

        StackPane stack = new StackPane();

        stack.getChildren().add(rect);
        stack.getChildren().add(hbox);
        StackPane.setAlignment(rect, Pos.TOP_CENTER);

        HBox root = new HBox();
        root.getChildren().add(vbox);
        root.getChildren().add(stack);
        root.setSpacing(40);
        root.setPadding(new Insets(20, 10, 10, 20));

        ((Group) scene.getRoot()).getChildren().add(root);

        stage.setScene(scene);
        stage.show();
    }
}
  1. 选择框(ChoiceBox)
    类似html中的下拉框
public class TestChoiceBox extends Application {

    Rectangle rect = new Rectangle(150, 30);
    final Label label = new Label("Hello");

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) {
        Scene scene = new Scene(new Group());
        scene.setFill(Color.ALICEBLUE);
        stage.setScene(scene);
        stage.show();

        stage.setTitle("ChoiceBox Sample");
        stage.setWidth(300);
        stage.setHeight(200);

        label.setFont(Font.font("Arial", 25));
        label.setLayoutX(40);

        final String[] greetings = new String[]{"Hello", "Hola", "Привет", "你好",
                "こんにちは"};
        final ChoiceBox<String> choiceBox = new ChoiceBox<>(FXCollections.observableArrayList(
                "English", "Español", "Русский", "简体中文", "日本語")
        );

        choiceBox.getSelectionModel().selectedIndexProperty().addListener(//选择的内容变化时触发
                (ObservableValue<? extends Number> observableValue, Number old_val, Number new_val) -> {
                    label.setText(greetings[new_val.intValue()]);
                });

        choiceBox.setTooltip(new Tooltip("Select the language"));//鼠标移动到下拉框上会显示该提示
        choiceBox.setValue("English");//设置初始值
        HBox hb = new HBox();
        hb.getChildren().addAll(choiceBox, label);
        hb.setSpacing(30);
        hb.setAlignment(Pos.CENTER);
        hb.setPadding(new Insets(10, 0, 0, 10));

        ((Group) scene.getRoot()).getChildren().add(hb);
    }
}
  1. 文本框(TextField)
public class TestTextField extends Application {

    @Override
    public void start(Stage stage) {
        Scene scene = new Scene(new Group(), 300, 150);
        stage.setScene(scene);
        stage.setTitle("Text Field Sample");
        //创建GridPane容器
        GridPane grid = new GridPane();
        grid.setPadding(new Insets(10, 10, 10, 10));
        grid.setVgap(5);
        grid.setHgap(5);

        scene.setRoot(grid);

        //定义Name Text Field
        final TextField name = new TextField();
        name.setPromptText("Enter your first name.");
        GridPane.setConstraints(name, 0, 0);
        grid.getChildren().add(name);

        //定义Last Name Text Field
        final TextField lastName = new TextField();
        lastName.setPromptText("Enter your last name.");
        GridPane.setConstraints(lastName, 0, 1);
        grid.getChildren().add(lastName);

        //定义Comment Text Field
        final TextField comment = new TextField();
        comment.setPromptText("Enter your comment.");
        GridPane.setConstraints(comment, 0, 2);
        grid.getChildren().add(comment);

        //定义Submit Button
        Button submit = new Button("Submit");
        GridPane.setConstraints(submit, 1, 0);
        grid.getChildren().add(submit);

        //定义Reset Button
        Button clear = new Button("Reset");
        GridPane.setConstraints(clear, 1, 1);
        grid.getChildren().add(clear);

        final Label label = new Label();
        GridPane.setConstraints(label, 0, 3);
        GridPane.setColumnSpan(label, 2);
        grid.getChildren().add(label);

        submit.setOnAction((ActionEvent e) -> {
            if ((comment.getText() != null && !comment.getText().isEmpty())) {
                label.setText(name.getText() + " " +
                        lastName.getText() + ", "
                        + "thank you for your comment!");
            } else {
                label.setText("You have not left a comment.");
            }
        });

        clear.setOnAction((ActionEvent e) -> {
            name.clear();
            lastName.clear();
            comment.clear();
            label.setText(null);
        });

        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

  1. 密码框(PasswordField)
    和文本框类似,可以通过getText()获取输入的内容。
public class TestPasswordFiled extends Application {

    final Label message = new Label("");

    @Override
    public void start(Stage stage) {
        Group root = new Group();
        Scene scene = new Scene(root, 260, 80);
        stage.setScene(scene);
        stage.setTitle("Password Field Sample");

        VBox vb = new VBox();
        vb.setPadding(new Insets(10, 0, 0, 10));
        vb.setSpacing(10);
        HBox hb = new HBox();
        hb.setSpacing(10);
        hb.setAlignment(Pos.CENTER_LEFT);

        Label label = new Label("Password");
        final PasswordField passwordField = new PasswordField();  
        passwordField.setText("Your password");

        passwordField.setOnAction((ActionEvent e) -> {
            if (!passwordField.getText().equals("T2f$Ay!")) {
                message.setText("Your password is incorrect!");
                message.setTextFill(Color.rgb(210, 39, 30));
            } else {
                message.setText("Your password has been confirmed");
                message.setTextFill(Color.rgb(21, 117, 84));
            }
            passwordField.clear();
        });

        hb.getChildren().addAll(label, passwordField);
        vb.getChildren().addAll(hb, message);

        scene.setRoot(vb);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}
  1. 滚动条(ScrollBar)
public class TestScrollBar extends Application {

    final ScrollBar scrollBar = new ScrollBar();
    final Image[] images = new Image[5];
    final ImageView[] pics = new ImageView[5];
    final VBox vb = new VBox();
    DropShadow shadow = new DropShadow();

    @Override
    public void start(Stage stage) {
        Group root = new Group();
        Scene scene = new Scene(root, 180, 180);
        scene.setFill(Color.BLACK);
        stage.setScene(scene);
        stage.setTitle("Scrollbar");
        root.getChildren().addAll(vb, scrollBar);

        shadow.setColor(Color.GREY);
        shadow.setOffsetX(2);
        shadow.setOffsetY(2);

        vb.setLayoutX(5);
        vb.setSpacing(10);

        scrollBar.setLayoutX(scene.getWidth() - scrollBar.getWidth());
        scrollBar.setMin(0);
        scrollBar.setOrientation(Orientation.VERTICAL);
        scrollBar.setPrefHeight(180);
        scrollBar.setMax(360);

        for (int i = 0; i < 5; i++) {
            images[i] = new Image(Objects.requireNonNull(getClass().getClassLoader().getResourceAsStream("fw" + (i + 1) + ".jpg")));
            final ImageView pic = pics[i] = new ImageView(images[i]);
            pic.setEffect(shadow);
            vb.getChildren().add(pics[i]);
        }

        scrollBar.valueProperty().addListener(
                //滚动时触发
                (ObservableValue<? extends Number> observableValue, Number old_val, Number new_val) -> {
                    vb.setLayoutY(-new_val.doubleValue());
                });
        stage.setResizable(false);//不可修改窗口大小
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}
  1. 滚动面板(ScrollPane)
public class TestScrollPane extends Application {

    final ScrollPane scrollPane = new ScrollPane();
    final Image[] images = new Image[5];
    final ImageView[] pics = new ImageView[5];
    final VBox vb = new VBox();
    final Label fileName = new Label();
    final String[] imageNames = new String[]{"fw1.jpg", "fw2.jpg", "fw3.jpg", "fw4.jpg", "fw5.jpg"};

    @Override
    public void start(Stage stage) {
        VBox box = new VBox();
        Scene scene = new Scene(box, 180, 180);
        stage.setScene(scene);
        stage.setTitle("ScrollPaneSample");
        box.getChildren().addAll(scrollPane, fileName);
        VBox.setVgrow(scrollPane, Priority.ALWAYS);

        fileName.setLayoutX(30);
        fileName.setLayoutY(160);

        Image roses = new Image(getClass().getResourceAsStream("/roses.jpg"));
        scrollPane.setContent(new ImageView(roses));
        scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);//禁止横向滚动
        scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.ALWAYS);//允许纵向滚动
        for (int i = 0; i < 5; i++) {
            images[i] = new Image(getClass().getResourceAsStream("/" + imageNames[i]));
            pics[i] = new ImageView(images[i]);
            pics[i].setFitWidth(100);
            pics[i].setPreserveRatio(true);
            vb.getChildren().add(pics[i]);
        }

        scrollPane.setVmax(440);
        scrollPane.setPrefSize(115, 150);
        scrollPane.setContent(vb);
        scrollPane.vvalueProperty().addListener((ObservableValue<? extends Number> ov,
                                                 Number old_val, Number new_val) -> {
            fileName.setText(imageNames[(new_val.intValue() - 1) / 100]);
        });
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}
  1. 列表视图(ListView)
public class TestListView extends Application {

    ListView<String> listView = new ListView<>();
    ObservableList<String> data = FXCollections.observableArrayList(
            "chocolate", "salmon", "gold", "coral", "darkorchid",
            "darkgoldenrod", "lightsalmon", "black", "rosybrown", "blue",
            "blueviolet", "brown");
    final Label label = new Label();

    @Override
    public void start(Stage stage) {
        VBox box = new VBox();
        Scene scene = new Scene(box, 200, 200);
        stage.setScene(scene);
        stage.setTitle("ListViewSample");
        box.getChildren().addAll(listView, label);
        VBox.setVgrow(listView, Priority.ALWAYS);

        label.setLayoutX(10);
        label.setLayoutY(115);
        label.setFont(Font.font("Verdana", 20));

        listView.setItems(data);

        //自定义列表单元的实现类
        listView.setCellFactory(stringListView -> new ColorRectCell());

        listView.getSelectionModel().selectedItemProperty().addListener(//选项改变时触发
                (ObservableValue<? extends String> observableValue, String old_val, String new_val) -> {
                    label.setText(new_val);
                    label.setTextFill(Color.web(new_val));
                });
        stage.show();
    }

    static class ColorRectCell extends ListCell<String> {
        @Override
        public void updateItem(String item, boolean empty) {
            super.updateItem(item, empty);
            Rectangle rect = new Rectangle(100, 20);
            if (item != null) {
                rect.setFill(Color.web(item));
                //Cell Factory产生ListCell对象。每个Cell与一个单独的数据项(Data Item)关联,
                // 并且会展示List View中的一行。通过setGraphic方法展现的Cell内容可以是其它的控件,文本、形状或图片。
                // 在本例中,List Cell展现了矩形。
                setGraphic(rect);
            } else {
                setGraphic(null);
            }
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}
  1. 表格视图(TableView)
public class TestTableView extends Application {

    private final TableView<Person> table = new TableView<>();
    private final ObservableList<Person> data =
            FXCollections.observableArrayList(
                    new Person("Jacob", "Smith", "jacob.smith@example.com"),
                    new Person("Isabella", "Johnson", "isabella.johnson@example.com"),
                    new Person("Ethan", "Williams", "ethan.williams@example.com"),
                    new Person("Emma", "Jones", "emma.jones@example.com"),
                    new Person("Michael", "Brown", "michael.brown@example.com"));
    final HBox hb = new HBox();

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) throws IOException {
        Scene scene = new Scene(new Group());
        stage.setTitle("Table View Sample");
        stage.setWidth(450);
        stage.setHeight(550);

        final Label label = new Label("Address Book");
        label.setFont(new Font("Arial", 20));

        table.setEditable(true);

        TableColumn<Person, String> firstNameCol = new TableColumn<>("First Name");
        firstNameCol.setMinWidth(100);
        firstNameCol.setCellValueFactory(new PropertyValueFactory<>("firstName"));

        firstNameCol.setCellFactory(TextFieldTableCell.<Person>forTableColumn());
        firstNameCol.setOnEditCommit(//编辑提交后会触发,修改内容后按回车键可提交
                (CellEditEvent<Person, String> t) -> {
                    ((Person) t.getTableView().getItems().get(t.getTablePosition().getRow())).setFirstName(t.getNewValue());
                });


        TableColumn<Person, String> lastNameCol =
                new TableColumn<>("Last Name");
        lastNameCol.setMinWidth(100);
        lastNameCol.setCellValueFactory(
                new PropertyValueFactory<>("lastName"));
        lastNameCol.setCellFactory(TextFieldTableCell.<Person>forTableColumn());
        lastNameCol.setOnEditCommit(
                (CellEditEvent<Person, String> t) -> {
                    ((Person) t.getTableView().getItems().get(
                            t.getTablePosition().getRow())
                    ).setLastName(t.getNewValue());
                });

        TableColumn<Person, String> emailCol = new TableColumn<>("Email");
        emailCol.setMinWidth(200);
        emailCol.setCellValueFactory(
                new PropertyValueFactory<>("email"));
        emailCol.setCellFactory(TextFieldTableCell.<Person>forTableColumn());
        emailCol.setOnEditCommit(
                (CellEditEvent<Person, String> t) -> {
                    ((Person) t.getTableView().getItems().get(
                            t.getTablePosition().getRow())
                    ).setEmail(t.getNewValue());
                });

        table.setItems(data);

        //把firstName和lastName字段合并为一个字段
        TableColumn<Person, String> nameCol = new TableColumn<>("Name");
        nameCol.getColumns().addAll(firstNameCol, lastNameCol);

        table.getColumns().addAll(nameCol, emailCol);

        final TextField addFirstName = new TextField();
        addFirstName.setPromptText("First Name");
        addFirstName.setMaxWidth(firstNameCol.getPrefWidth());
        final TextField addLastName = new TextField();
        addLastName.setMaxWidth(lastNameCol.getPrefWidth());
        addLastName.setPromptText("Last Name");
        final TextField addEmail = new TextField();
        addEmail.setMaxWidth(emailCol.getPrefWidth());
        addEmail.setPromptText("Email");

        final Button addButton = new Button("Add");
        addButton.setOnAction((ActionEvent e) -> {//点击按钮触发
            data.add(new Person(addFirstName.getText(), addLastName.getText(), addEmail.getText()));
            addFirstName.clear();
            addLastName.clear();
            addEmail.clear();
        });

        hb.getChildren().addAll(addFirstName, addLastName, addEmail, addButton);
        hb.setSpacing(3);

        final VBox vbox = new VBox();
        vbox.setSpacing(5);
        vbox.setPadding(new Insets(10, 0, 0, 10));
        vbox.getChildren().addAll(label, table, hb);

        ((Group) scene.getRoot()).getChildren().addAll(vbox);

        stage.setScene(scene);
        stage.show();
    }

    public static class Person {

        private final SimpleStringProperty firstName;
        private final SimpleStringProperty lastName;
        private final SimpleStringProperty email;

        private Person(String fName, String lName, String email) {
            this.firstName = new SimpleStringProperty(fName);
            this.lastName = new SimpleStringProperty(lName);
            this.email = new SimpleStringProperty(email);
        }

        public String getFirstName() {
            return firstName.get();
        }

        public void setFirstName(String fName) {
            firstName.set(fName);
        }

        public String getLastName() {
            return lastName.get();
        }

        public void setLastName(String fName) {
            lastName.set(fName);
        }

        public String getEmail() {
            return email.get();
        }

        public void setEmail(String fName) {
            email.set(fName);
        }
    }
}
  1. 组合框(ComboBox)
public class TestComboBox extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    final Button button = new Button("Send");
    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("Email address");
        emailComboBox.setEditable(true);
        emailComboBox.setOnAction((Event ev) -> {
            address = emailComboBox.getSelectionModel().getSelectedItem().toString();
        });


        final ComboBox priorityComboBox = new ComboBox();
        priorityComboBox.getItems().addAll(
                "Highest",
                "High",
                "Normal",
                "Low",
                "Lowest"
        );
        priorityComboBox.setValue("Normal");
        priorityComboBox.setCellFactory(
                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;
                    }

                });


        button.setOnAction((ActionEvent e) -> {
            if (emailComboBox.getValue() != null && !emailComboBox.getValue().toString().isEmpty()) {
                notification.setText("Your message was successfully sent" + " to " + address);
                emailComboBox.setValue("");
                if (priorityComboBox.getValue() != null && !priorityComboBox.getValue().toString().isEmpty()) {
                    priorityComboBox.setValue(null);
                }
                subject.clear();
                text.clear();
            } else {
                notification.setText("You have not selected a recipient!");
            }
        });

        GridPane grid = new GridPane();
        grid.setVgap(4);
        grid.setHgap(10);
        grid.setPadding(new Insets(5, 5, 5, 5));
        grid.add(new Label("To: "), 0, 0);
        grid.add(emailComboBox, 1, 0);
        grid.add(new Label("Priority: "), 2, 0);
        grid.add(priorityComboBox, 3, 0);
        grid.add(new Label("Subject: "), 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();

    }
}
  1. 分隔符(Separator)
public class TestSeparator extends Application {

    Label caption = new Label("Weather Forecast");
    Label friday = new Label("Friday");
    Label saturday = new Label("Saturday");
    Label sunday = new Label("Sunday");

    @Override
    public void start(Stage stage) {
        Group root = new Group();
        Scene scene = new Scene(root, 350, 150);
        stage.setScene(scene);
        stage.setTitle("Separator Sample");

        GridPane grid = new GridPane();
        grid.setPadding(new Insets(10, 10, 10, 10));
        grid.setVgap(2);
        grid.setHgap(5);

        scene.setRoot(grid);
        scene.getStylesheets().add("Separator.css");

        Image cloudImage = new Image(getClass().getResourceAsStream("/cloud.jpg"));
        Image sunImage = new Image(getClass().getResourceAsStream("/sun.jpg"));

        caption.setFont(Font.font("Verdana", 20));

        GridPane.setConstraints(caption, 0, 0);
        GridPane.setColumnSpan(caption, 8);
        grid.getChildren().add(caption);

        final Separator sepHor = new Separator();
        sepHor.setValignment(VPos.CENTER);//纵向对齐方式
        GridPane.setConstraints(sepHor, 0, 1);
        GridPane.setColumnSpan(sepHor, 7);
        grid.getChildren().add(sepHor);

        friday.setFont(Font.font("Verdana", 18));
        GridPane.setConstraints(friday, 0, 2);
        GridPane.setColumnSpan(friday, 2);
        grid.getChildren().add(friday);

        final Separator sepVert1 = new Separator();
        sepVert1.setOrientation(Orientation.VERTICAL);
        sepVert1.setValignment(VPos.CENTER);
        sepVert1.setPrefHeight(80);
        GridPane.setConstraints(sepVert1, 2, 2);
        GridPane.setRowSpan(sepVert1, 2);
        grid.getChildren().add(sepVert1);

        saturday.setFont(Font.font("Verdana", 18));
        GridPane.setConstraints(saturday, 3, 2);
        GridPane.setColumnSpan(saturday, 2);
        grid.getChildren().add(saturday);

        final Separator sepVert2 = new Separator();
        sepVert2.setOrientation(Orientation.VERTICAL);
        sepVert2.setValignment(VPos.CENTER);
        sepVert2.setPrefHeight(80);
        GridPane.setConstraints(sepVert2, 5, 2);
        GridPane.setRowSpan(sepVert2, 2);
        grid.getChildren().add(sepVert2);

        sunday.setFont(Font.font("Verdana", 18));
        GridPane.setConstraints(sunday, 6, 2);
        GridPane.setColumnSpan(sunday, 2);
        grid.getChildren().add(sunday);

        final ImageView cloud = new ImageView(cloudImage);
        GridPane.setConstraints(cloud, 0, 3);
        grid.getChildren().add(cloud);

        final Label t1 = new Label("16");
        t1.setFont(Font.font("Verdana", 20));
        GridPane.setConstraints(t1, 1, 3);
        grid.getChildren().add(t1);

        final ImageView sun1 = new ImageView(sunImage);
        GridPane.setConstraints(sun1, 3, 3);
        grid.getChildren().add(sun1);

        final Label t2 = new Label("18");
        t2.setFont(Font.font("Verdana", 20));
        GridPane.setConstraints(t2, 4, 3);
        grid.getChildren().add(t2);

        final ImageView sun2 = new ImageView(sunImage);
        GridPane.setConstraints(sun2, 6, 3);
        grid.getChildren().add(sun2);

        final Label t3 = new Label("20");
        t3.setFont(Font.font("Verdana", 20));
        GridPane.setConstraints(t3, 7, 3);
        grid.getChildren().add(t3);

        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}
  1. 超链接(Hyperlink)
    显示效果和web的a标签类似,在点击之后的和未点击时都有不同的显示效果,用法和按钮类似。
public class TestHyperlink extends Application {

    final static String[] imageFiles = new String[]{
            "product.png",
            "education.png",
            "partners.png",
            "support.png"
    };
    final static String[] captions = new String[]{
            "Products",
            "Education",
            "Partners",
            "Support"
    };
    final ImageView selectedImage = new ImageView();
    final Hyperlink[] hpls = new Hyperlink[captions.length];
    final Image[] images = new Image[imageFiles.length];

    public static void main(String[] args) {
        launch(TestHyperlink.class, args);
    }

    @Override
    public void start(Stage stage) {
        Scene scene = new Scene(new Group());
        stage.setTitle("Hyperlink Sample");
        stage.setWidth(300);
        stage.setHeight(200);

        selectedImage.setLayoutX(100);
        selectedImage.setLayoutY(10);

        for (int i = 0; i < captions.length; i++) {
            final Hyperlink hpl = hpls[i] = new Hyperlink(captions[i]);
            final Image image = images[i] = new Image(Objects.requireNonNull(getClass().getClassLoader().getResourceAsStream(imageFiles[i])));
            hpl.setOnAction((ActionEvent e) -> {//链接点击之后触发
                selectedImage.setImage(image);
            });
        }

        final Button button = new Button("Refresh links");
        button.setOnAction((ActionEvent e) -> {
            for (int i = 0; i < captions.length; i++) {
                hpls[i].setVisited(false);
                selectedImage.setImage(null);
            }
        });

        VBox vbox = new VBox();
        vbox.getChildren().addAll(hpls);
        vbox.getChildren().add(button);
        vbox.setSpacing(5);

        ((Group) scene.getRoot()).getChildren().addAll(vbox, selectedImage);
        stage.setScene(scene);
        stage.show();
    }
}
  1. 提示信息(Tooltip)
    鼠标移动到加了提示信息的组件上会有提示。
public class TestTooltip extends Application {

    final static String[] rooms = new String[]{
            "Accommodation (BB)",
            "Half Board",
            "Late Check-out",
            "Extra Bed"
    };
    final static Integer[] rates = new Integer[]{
            100, 20, 10, 30
    };
    final CheckBox[] cbs = new CheckBox[rooms.length];
    final Label total = new Label("Total: $0");
    Integer sum = 0;

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) {
        Scene scene = new Scene(new Group());
        stage.setTitle("Tooltip Sample");
        stage.setWidth(330);
        stage.setHeight(150);

        total.setFont(new Font("Arial", 20));

        for (int i = 0; i < rooms.length; i++) {
            final CheckBox cb = cbs[i] = new CheckBox(rooms[i]);
            final Integer rate = rates[i];
            final Tooltip tooltip = new Tooltip("$" + rates[i].toString());
            tooltip.setFont(new Font("Arial", 16));
            cb.setTooltip(tooltip);
            cb.selectedProperty().addListener(
                    (ObservableValue<? extends Boolean> ov, Boolean old_val, Boolean new_val) -> {
                        if (cb.isSelected()) {
                            sum = sum + rate;
                        } else {
                            sum = sum - rate;
                        }
                        total.setText("Total: $" + sum.toString());
                    }
            );
        }

        VBox vbox = new VBox();
        vbox.getChildren().addAll(cbs);
        vbox.setSpacing(5);
        HBox root = new HBox();
        root.getChildren().add(vbox);
        root.getChildren().add(total);
        root.setSpacing(40);
        root.setPadding(new Insets(20, 10, 10, 20));

        ((Group) scene.getRoot()).getChildren().add(root);

        stage.setScene(scene);
        stage.show();
    }
}
  1. 带有标题的面板(TitledPane)和可折叠面板(Accordion)
    TitledPane创建的面板是可以折叠和打开的,把多个TitledPane放在同一个Accordion中时,最多只能展开其中一个,展开其中一个会关闭其余展开的。
public class TestTitledPane extends Application {
    final String[] imageNames = new String[]{"Apples", "Flowers", "Leaves"};
    final Image[] images = new Image[imageNames.length];
    final ImageView[] pics = new ImageView[imageNames.length];
    final TitledPane[] tps = new TitledPane[imageNames.length];
    final Label label = new Label("N/A");

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) {
        stage.setTitle("TitledPane");
        Scene scene = new Scene(new Group(), 450, 250);

        TitledPane gridTitlePane = new TitledPane();
        GridPane grid = new GridPane();
        grid.setVgap(4);
        grid.setPadding(new Insets(5, 5, 5, 5));
        grid.add(new Label("First Name: "), 0, 0);
        grid.add(new TextField(), 1, 0);
        grid.add(new Label("Last Name: "), 0, 1);
        grid.add(new TextField(), 1, 1);
        grid.add(new Label("Email: "), 0, 2);
        grid.add(new TextField(), 1, 2);
        grid.add(new Label("Attachment: "), 0, 3);
        grid.add(label, 1, 3);
        gridTitlePane.setText("Grid");
        gridTitlePane.setContent(grid);

        final Accordion accordion = new Accordion();

        for (int i = 0; i < imageNames.length; i++) {
            images[i] = new Image(getClass().getResourceAsStream("/" + imageNames[i] + ".jpg"));
            pics[i] = new ImageView(images[i]);
            tps[i] = new TitledPane(imageNames[i], pics[i]);
        }
        accordion.getPanes().addAll(tps);

        //折叠面板,折叠和展开时触发
        accordion.expandedPaneProperty().addListener(
                (ObservableValue<? extends TitledPane> ov, TitledPane old_val, TitledPane new_val) -> {
                    if (new_val != null) {
                        label.setText(accordion.getExpandedPane().getText()
                                + ".jpg");
                    }
                });

        HBox hbox = new HBox(10);
        hbox.setPadding(new Insets(20, 0, 0, 20));
        hbox.getChildren().setAll(gridTitlePane, accordion);

        Group root = (Group) scene.getRoot();
        root.getChildren().add(hbox);
        stage.setScene(scene);
        stage.show();
    }
}
  1. 菜单(Menu)
public class TestMenu extends Application {

    final PageData[] pages = new PageData[]{
            new PageData("Apple",
                    "The apple is the pomaceous fruit of the apple tree, species Malus "
                            + "domestica in the rose family (Rosaceae). It is one of the most "
                            + "widely cultivated tree fruits, and the most widely known of "
                            + "the many members of genus Malus that are used by humans. "
                            + "The tree originated in Western Asia, where its wild ancestor, "
                            + "the Alma, is still found today.",
                    "Malus domestica"),
            new PageData("Hawthorn",
                    "The hawthorn is a large genus of shrubs and trees in the rose family,"
                            + "Rosaceae, native to temperate regions of the Northern Hemisphere "
                            + "in Europe, Asia and North America. The name hawthorn was "
                            + "originally applied to the species native to northern Europe, "
                            + "especially the Common Hawthorn C. monogyna, and the unmodified "
                            + "name is often so used in Britain and Ireland.",
                    "Crataegus monogyna"),
            new PageData("Ivy",
                    "The ivy is a flowering plant in the grape family (Vitaceae) native to "
                            + " eastern Asia in Japan, Korea, and northern and eastern China. "
                            + "It is a deciduous woody vine growing to 30 m tall or more given "
                            + "suitable support,  attaching itself by means of numerous small "
                            + "branched tendrils tipped with sticky disks.",
                    "Parthenocissus tricuspidata"),
            new PageData("Quince",
                    "The quince is the sole member of the genus Cydonia and is native to "
                            + "warm-temperate southwest Asia in the Caucasus region. The "
                            + "immature fruit is green with dense grey-white pubescence, most "
                            + "of which rubs off before maturity in late autumn when the fruit "
                            + "changes color to yellow with hard, strongly perfumed flesh.",
                    "Cydonia oblonga")
    };

    final String[] viewOptions = new String[]{
            "Title",
            "Binomial name",
            "Picture",
            "Description"
    };

    final Entry<String, Effect>[] effects = new Entry[]{
            new SimpleEntry<>("Sepia Tone", new SepiaTone()),
            new SimpleEntry<>("Glow", new Glow()),
            new SimpleEntry<>("Shadow", new DropShadow())
    };

    final ImageView pic = new ImageView();
    final Label name = new Label();
    final Label binName = new Label();
    final Label description = new Label();
    private int currentIndex = -1;

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) {
        stage.setTitle("Menu Sample");
        Scene scene = new Scene(new VBox(), 400, 350);
        scene.setFill(Color.OLDLACE);

        name.setFont(new Font("Verdana Bold", 22));
        binName.setFont(new Font("Arial Italic", 10));
        pic.setFitHeight(150);
        pic.setPreserveRatio(true);
        description.setWrapText(true);
        description.setTextAlignment(TextAlignment.JUSTIFY);

        shuffle();

        MenuBar menuBar = new MenuBar();

        // --- Graphical elements
        final VBox vbox = new VBox();
        vbox.setAlignment(Pos.CENTER);
        vbox.setSpacing(10);
        vbox.setPadding(new Insets(0, 10, 0, 10));
        vbox.getChildren().addAll(name, binName, pic, description);

        // --- Menu File
        Menu menuFile = new Menu("File");
        MenuItem add = new MenuItem("Shuffle", new ImageView(new Image("/new.png")));
        add.setOnAction((ActionEvent t) -> {
            shuffle();
            vbox.setVisible(true);
        });

        MenuItem clear = new MenuItem("Clear");
        clear.setAccelerator(KeyCombination.keyCombination("Ctrl+X"));
        clear.setOnAction((ActionEvent t) -> {
            vbox.setVisible(false);
        });

        MenuItem exit = new MenuItem("Exit");
        exit.setOnAction((ActionEvent t) -> {
            System.exit(0);
        });

        menuFile.getItems().addAll(add, clear, new SeparatorMenuItem(), exit);

        // --- Menu Edit
        Menu menuEdit = new Menu("Edit");
        Menu menuEffect = new Menu("Picture Effect");

        final ToggleGroup groupEffect = new ToggleGroup();
        for (Entry<String, Effect> effect : effects) {
            RadioMenuItem itemEffect = new RadioMenuItem(effect.getKey());
            itemEffect.setUserData(effect.getValue());
            itemEffect.setToggleGroup(groupEffect);
            menuEffect.getItems().add(itemEffect);
        }

        final MenuItem noEffects = new MenuItem("No Effects");
        noEffects.setDisable(true);
        noEffects.setOnAction((ActionEvent t) -> {
            pic.setEffect(null);
            groupEffect.getSelectedToggle().setSelected(false);
            noEffects.setDisable(true);
        });

        groupEffect.selectedToggleProperty().addListener(
                (ObservableValue<? extends Toggle> ov, Toggle old_toggle,
                 Toggle new_toggle) -> {
                    if (groupEffect.getSelectedToggle() != null) {
                        Effect effect =
                                (Effect) groupEffect.getSelectedToggle().getUserData();
                        pic.setEffect(effect);
                        noEffects.setDisable(false);
                    } else {
                        noEffects.setDisable(true);
                    }
                });

        menuEdit.getItems().addAll(menuEffect, noEffects);

        // --- Menu View
        Menu menuView = new Menu("View");
        CheckMenuItem titleView = createMenuItem("Title", name);
        CheckMenuItem binNameView = createMenuItem("Binomial name", binName);
        CheckMenuItem picView = createMenuItem("Picture", pic);
        CheckMenuItem descriptionView = createMenuItem(
                "Decsription", description);

        menuView.getItems().addAll(titleView, binNameView, picView,
                descriptionView);
        menuBar.getMenus().addAll(menuFile, menuEdit, menuView);


        // --- Context Menu
        final ContextMenu cm = new ContextMenu();
        MenuItem cmItem1 = new MenuItem("Copy Image");
        cmItem1.setOnAction((ActionEvent e) -> {
            Clipboard clipboard = Clipboard.getSystemClipboard();
            ClipboardContent content = new ClipboardContent();
            content.putImage(pic.getImage());
            clipboard.setContent(content);
        });

        cm.getItems().add(cmItem1);
        pic.addEventHandler(MouseEvent.MOUSE_CLICKED, (MouseEvent e) -> {
            if (e.getButton() == MouseButton.SECONDARY)
                cm.show(pic, e.getScreenX(), e.getScreenY());
        });

        ((VBox) scene.getRoot()).getChildren().addAll(menuBar, vbox);

        stage.setScene(scene);
        stage.show();
    }

    private void shuffle() {
        int i = currentIndex;
        while (i == currentIndex) {
            i = (int) (Math.random() * pages.length);
        }
        pic.setImage(pages[i].image);
        name.setText(pages[i].name);
        binName.setText("(" + pages[i].binNames + ")");
        description.setText(pages[i].description);
        currentIndex = i;
    }

    private static CheckMenuItem createMenuItem(String title, final Node node) {
        CheckMenuItem cmi = new CheckMenuItem(title);
        cmi.setSelected(true);
        cmi.selectedProperty().addListener(
                (ObservableValue<? extends Boolean> ov, Boolean old_val,
                 Boolean new_val) -> {
                    node.setVisible(new_val);
                });
        return cmi;
    }

    private class PageData {
        public String name;
        public String description;
        public String binNames;
        public Image image;

        public PageData(String name, String description, String binNames) {
            this.name = name;
            this.description = description;
            this.binNames = binNames;
            image = new Image(Objects.requireNonNull(getClass().getClassLoader().getResourceAsStream(name + ".jpg")));
        }
    }
} 

暂时学习上面的组件即可,下面的UI组件用到再学习,我最后会再另开文章更新:

  1. 树视图(TreeView)
  2. 树表视图(TreeTableView)
  3. 滑块(Slider)
  4. 进度条和进度指示器(ProgressBarandProgressIndicator)
  5. HTML编辑器(HTMLEditor)
  6. 颜色选择器(ColorPicker)
  7. 日期选择器(DatePicker)
  8. 分页控件(PaginationControl)
  9. 文件选择框(FileChooser)
  10. 自定义UI控件(CustomizationofUIControls)
  11. 嵌入式平台的UI控件(UIControlsontheEmbeddedPlatforms)

Q.E.D.


擅长前端的Java程序员