文档



JavaFX:使用JavaFX UI组件

29 UI控件的自定义

本章介绍了UI控件的自定义方面,并总结了Oracle提供的一些技巧和窍门,帮助您修改UI控件的外观和行为。

您可以通过应用层叠样式表(CSS)、重新定义默认行为和使用单元格工厂来学习如何自定义控件。对于更特定的情况,当您的应用程序的任务需要使用javafx.scene.control包中的类无法实现的独特功能时,可以扩展Control类来创建自己的控件。

应用CSS

您可以通过重新定义JavaFX modena样式表的样式定义来改变UI控件的外观。 使用CSS为JavaFX应用程序设置外观解释了修改样式和在JavaFX应用程序中启用样式的一般概念和方法。

考虑一些在JavaFX论坛上经常被开发人员请求的特定任务。

尽管Tooltip类没有任何属性或方法来更改工具提示的默认颜色,但您可以修改.tooltip CSS类的-fx-background-color属性,如示例29-1所示。

示例29-1 改变工具提示的背景颜色

.tooltip {    
    -fx-background-color: linear-gradient(#e2ecfe, #99bcfd);
}
.page-corner {
    -fx-background-color: linear-gradient(from 0% 0% to 50% 50%,#3278fa,#99bcfd);
}

.page-corner CSS类定义了工具提示右下角的颜色。当您将示例29-1中的代码添加到TooltipSample的样式表中,并将样式表应用于场景时,工具提示的颜色将变为蓝色。请参见图29-1以评估效果。

图29-1 带有蓝色背景的工具提示

图29-1的描述如下
"图29-1 带有蓝色背景的工具提示"的描述

请注意,当您修改工具提示的默认样式时,新的外观将应用于应用程序中的所有工具提示。

另一个常见的设计任务是更改控件的默认标记。例如,CheckBox类的默认样式定义了选中状态的传统勾选标记。您可以重新定义标记的形状以及其颜色,如示例29-2所示。

示例29-2 复选框的替代标记

.check-box .mark {
    -fx-shape:
"M2,0L5,4L8,0L10,0L10,2L6,5L10,8L10,10L8,10L5,6L2,10L0,10L0,8L4,5L0,2L0,0Z";
}
.check-box:selected .mark {
    -fx-background-color: #0181e2;
}

-fx-shape属性设置了标记的新SVG路径,-fx-background-color属性定义了其颜色。当在CheckBoxSample应用程序中启用修改后的样式表时,选中的复选框中包含X标记而不是勾选标记,如图29-2所示。

图29-2 修改后的ComboBoxSample复选框样式

图29-2的描述如下
"图29-2 修改后的ComboBoxSample复选框样式"的描述

许多开发人员询问如何克服TableViewListView控件在视觉样式上的限制。默认情况下,这些控件中的所有行都会显示,无论它们是否为空。通过适当的CSS设置,您可以为所有空行设置特定的颜色。示例29-3实现了对TableView控件中空行的颜色设置。

示例29-3 设置表格视图中空行的颜色

.table-row-cell:empty {
    -fx-background-color: lightyellow;
}
 
.table-row-cell:empty .table-cell {
    -fx-border-width: 0px;
}

第一个CSS样式确定所有空行,无论是偶数行还是奇数行,都应具有浅黄色背景。当table-row-cell为空时,第二个CSS语句会移除所有表格单元格右侧绘制的垂直边框。

当在TableViewSample应用程序中启用来自示例29-3的CSS样式时,通讯录表格如图29-3所示。

图29-3 添加颜色到空行的TableViewSample

图29-3的描述如下
"图29-3 添加颜色到空行的TableViewSample"的描述

您甚至可以将空单元格的背景颜色设置为null。在这种情况下,样式表将使用表格视图的默认背景颜色。请参见图29-4以评估效果。

图29-4:在空行中添加空背景颜色的TableViewSample

图29-4的描述
"图29-4:在空行中添加空背景颜色的TableViewSample"的描述

您可以为UI控件设置更多的CSS属性,以改变它们的形状、颜色方案和应用的效果。有关可用的CSS属性和类的更多信息,请参阅JavaFX CSS参考指南

修改默认行为

许多开发人员要求提供一个特定的API来限制文本字段中的输入,例如,只允许数字值。 示例 29-4 提供了一个带有数字文本字段的简单应用程序。

示例 29-4 禁止文本字段中的字母

import javafx.application.Application;
import javafx.event.ActionEvent;
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 CustomTextFieldSample extends Application {
    
    final static Label label = new Label();
 
    @Override
    public void start(Stage stage) {
        Group root = new Group();
        Scene scene = new Scene(root, 300, 150);
        stage.setScene(scene);
        stage.setTitle("文本字段示例");
 
        GridPane grid = new GridPane();
        grid.setPadding(new Insets(10, 10, 10, 10));
        grid.setVgap(5);
        grid.setHgap(5);
 
        scene.setRoot(grid);
        final Label dollar = new Label("$");
        GridPane.setConstraints(dollar, 0, 0);
        grid.getChildren().add(dollar);
        
        final TextField sum = new TextField() {
            @Override
            public void replaceText(int start, int end, String text) {
                if (!text.matches("[a-z, A-Z]")) {
                    super.replaceText(start, end, text);   
                }
                label.setText("请输入一个数字值");
            }
 
            @Override
            public void replaceSelection(String text) {
                if (!text.matches("[a-z, A-Z]")) {
                    super.replaceSelection(text);
                }
            }
        };
 
        sum.setPrefColumnCount(10);
        GridPane.setConstraints(sum, 1, 0);
        grid.getChildren().add(sum);
        
        Button submit = new Button("提交");
        GridPane.setConstraints(submit, 2, 0);
        grid.getChildren().add(submit);
        
        submit.setOnAction((ActionEvent e) -> {
            label.setText(null);
        });
        
        GridPane.setConstraints(label, 0, 1);
        GridPane.setColumnSpan(label, 3);
        grid.getChildren().add(label);
        
        scene.setRoot(grid);
        stage.show();
    }
 
    public static void main(String[] args) {
        launch(args);
    }
}

要重新定义TextField类的默认实现,您必须覆盖从TextInputControl类继承的replaceTextreplaceSelection方法。

当用户尝试在Sum文本字段中输入任何字母时,不会显示任何符号,并显示警告消息。 图29-5说明了这种情况。

图29-5 尝试输入字母符号

图29-5的描述如下
"图29-5 尝试输入字母符号"的描述

然而,当用户尝试输入数字值时,它们会显示在字段中,如图29-6所示。

图29-6 输入数字值

图29-6的描述如下
"图29-6 输入数字值"的描述

实现单元格工厂

通过使用单元格工厂的机制,可以完全自定义四个UI控件的外观甚至行为。您可以将单元格工厂应用于TableViewListViewTreeViewComboBox。单元格工厂用于生成单元格实例,这些实例用于表示这些控件的任何单个项目。

Cell类扩展了Labeled类,该类提供了实现最典型用例(显示和编辑文本)所需的所有属性和方法。然而,当您的应用程序的任务要求在列表或表格中显示图形对象时,您可以使用graphic属性并在单元格中放置任何Node(有关自定义单元格的更多信息,请参见Cell类的API规范)。

例如,示例29-5中的代码片段为列表视图创建了一个单元格工厂,并在updateItem方法中重新定义了单元格的内容,以便列表显示不同颜色的矩形。

示例29-5 为ListView控件实现单元格工厂

list.setCellFactory((ListView<String> l) -> new ColorRectCell());
...
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));
            setGraphic(rect);
        } else {
            setGraphic(null);
        }
    }
}

图29-7显示了在UI控件示例项目的ListViewSample中,这个自定义列表是什么样子。

图29-7 带有颜色矩形的列表视图

图29-7的描述如下
"图29-7 带有颜色矩形的列表视图"的描述

本教程广泛使用单元格工厂机制来自定义UI控件。您可以通过使用单元格工厂机制来自定义这些控件,或者使用提供特定数据模型的预制单元格编辑器实现可视化效果。JavaFX API中提供了相应的类,表29-1列出了这些类。

表29-1 列表视图、树视图和表格视图控件的单元格编辑器类

控件 单元格编辑器类

列表视图

  • CheckBoxListCell

  • ChoiceBoxListCell

  • ComboBoxListCell

  • TextFieldListCell

树视图

  • CheckBoxTreeCell

  • ChoiceBoxTreeCell

  • ComboBoxTreeCell

  • TextFieldTreeCell

表格视图

  • CheckBoxTableCell

  • ChoiceBoxTableCell

  • ComboBoxTableCell

  • ProgressBarTableCell

  • TextFieldTableCell

树表视图

  • CheckBoxTreeTableCell

  • ChoiceBoxTreeTableCell

  • ComboBoxTreeTableCell

  • ProgressBarTreeTableCell

  • TextFieldTreeTableCell


每个单元格编辑器类在单元格内绘制特定的节点。例如,CheckBoxListCell类在列表单元格内绘制一个CheckBox节点。

要评估更多的单元格工厂和单元格编辑器用例,请参阅表格视图树视图组合框章节。

相关文档和资源 

关闭窗口

目录

JavaFX:使用JavaFX UI组件

展开 折叠