翻译自  Customization of UI Controls

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

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


应用CSS

您可以通过重新定义JavaFX caspian样式表的样式定义来更改UI控件的外观。使用CSS为JavaFX应用程序设置外观说明了在JavaFX应用程序中修改样式并启用它们的一般概念和方法。

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

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

示例27-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-cornerCSS类定义了提示的右下角的颜色。将示例27-1中的代码添加到TooltipSample的样式表并将样式表应用于场景时,工具提示将其颜色更改为蓝色。请参见图27-1以评估效果。

图27-1具有蓝色背景颜色的工具提示

javafx控制器怎么连接数据库 javafx 自定义控件_控件

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

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

示例27-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标记而不是复选标记,如图27-2所示。

图27-2带有修改的复选框样式的ComboBoxSample

javafx控制器怎么连接数据库 javafx 自定义控件_javafx控制器怎么连接数据库_02

许多开发人员询问如何克服视觉风格TableViewListView控件的限制。默认情况下,将显示这些控件中的所有行,无论它们是否为空。使用适当的CSS设置,您可以为所有空行设置特定颜色。例27-3为TableView控件实现此任务。

示例27-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应用程序中启用示例27-3中的CSS样式时,Address Book表如图27-3所示。

图27-3将ColorView添加到空行的TableViewSample

javafx控制器怎么连接数据库 javafx 自定义控件_javafx控制器怎么连接数据库_03

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

图27-4将空背景颜色添加到空行的TableViewSample

javafx控制器怎么连接数据库 javafx 自定义控件_CSS_04

您可以为UI控件设置更多CSS属性,以更改其形状,颜色方案和应用的效果。


改变默认行为

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

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

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
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("Text Field Sample");
 
        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("Enter a numeric value");
            }
 
            @Override
            public void replaceSelection(String text) {
                if (!text.matches("[a-z, A-Z]")) {
                    super.replaceSelection(text);
                }
            }
        };
 
        sum.setPromptText("Enter the total");
        sum.setPrefColumnCount(10);
        GridPane.setConstraints(sum, 1, 0);
        grid.getChildren().add(sum);
        
        Button submit = new Button("Submit");
        GridPane.setConstraints(submit, 2, 0);
        grid.getChildren().add(submit);
        
        submit.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(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,必须覆盖从类继承的replaceTextreplaceSelection方法TextInputControl

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

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

javafx控制器怎么连接数据库 javafx 自定义控件_javafx控制器怎么连接数据库_05

但是,当用户尝试输入数值时,它们会出现在字段中,如图27-6所示。

图27-6输入数字值

javafx控制器怎么连接数据库 javafx 自定义控件_应用程序_06

 


实施细胞工厂

通过使用单元工厂的机制,可以完全定制四个UI控件的外观甚至行为。您可以将电池工厂TableViewListViewTreeView,和ComboBox。单元工厂用于生成单元实例,用于表示这些控件的任何单个项。

Cell类扩展了Labeled类,它提供了所有必需的属性和方法,实行最典型的使用情况-显示和编辑文本。但是,当应用程序的任务需要在列表或表中显示图形对象时,您可以使用该graphic属性并将其放置Node在单元格中

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

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

list.setCellFactory(new Callback<ListView<String>, ListCell<String>>() {
    Override public ListCell<String> call(ListView<String> list) {
        return 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);
        }
    }
}

图27-7显示了此自定义列表在UIControlSamples项目的ListViewSample中的外观。

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

javafx控制器怎么连接数据库 javafx 自定义控件_CSS_07

本教程广泛使用单元工厂机制来自定义UI控件。表27-1总结了可用于在应用程序上实现单元工厂的编码模板。

表27-1单元工厂编码模式

控制

编码模式

ListView, ComboBox

list.setCellFactory(new Callback<ListView<String>,
ListCell<String>>() {    
            @Override 
            public ListCell<String> call(ListView<String> list) {
               //cell implementation            
            }
});

TableView

column.setCellFactory(new Callback<TableColumn,
    TableCell>() {
        public TableCell call(TableColumn p) {
                    //cell implementation                
                }        
});

TreeView

   tree.setCellFactory(new Callback<TreeView<String>, 

    TreeCell<String>>(){

            @Override

            public TreeCell<String> call(TreeView<String> p) {

                //cell implementation

            }

});

 

您可以使用单元工厂机制自定义这些控件,也可以使用预提供的单元编辑器实现来提供可视化底层的特定数据模型。表27-2列出了JavafX API中可用的相应类。

表27-2列表视图,树视图和表视图控件的单元编辑器类

控制

单元格编辑器类

列表显示

  • CheckBoxListCell
  • ChoiceBoxListCell
  • ComboBoxListCell
  • TextFieldListCell

树视图

  • CheckBoxTreeCell
  • ChoiceBoxTreeCell
  • ComboBoxTreeCell
  • TextFieldTreeCell

表视图

  • CheckBoxTableCell
  • ChoiceBoxTableCell
  • ComboBoxTableCell
  • ProgressBarTableCell
  • TextFieldTableCell

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