Skip to content

JEP 253: Prepare JavaFX UI Controls & CSS APIs for Modularization | 为 JavaFX UI 控件和 CSS API 进行模块化准备

摘要

定义 公共 API,用于 JavaFX UI 控件和 CSS 功能,这些功能目前只能通过内部 API 使用,由于模块化的原因将变得无法访问。

目标

许多使用 JavaFX UI 控件和 CSS 功能的开发人员在历史上忽略了避免使用内部 com.sun.* API 的警告。在许多情况下,为了实现期望的结果,开发人员别无选择,只能使用这些内部 API。随着 Java 9 即将发布,特别是随着 Project Jigsaw 中模块之间强制边界的引入,开发人员将发现他们的代码将不再编译或运行,因为 com.sun.* 包将不再可访问。这个 JEP 的目标是为目前由内部 API 提供的功能定义公共 API。

非目标

鉴于模块化的影响,即即将无法访问 com.sun.* 包,没有办法以保留任何程度的向后兼容性的方式完成此操作。因此,本 JEP 的目标不是保持向后兼容性。这并不意味着我们可以打破任何我们喜欢的东西;我们的意图只是引入新的 API(和演变现有的私有 API),直接通过实施模块边界打破它们。所有其他不受模块化影响的现有 API 将保持不变。

成功度量

成功可以通过以下两种方式衡量:

  • 依赖于 JavaFX 内部 API(特别是 Scene Builder、ControlsFX 和 JFXtras)的项目在更新到新 API 后继续工作,而没有丢失任何功能。这三个项目都是开源的,它们将提供一个优秀的测试平台,以确保提供了所有必要的 API。

  • 围绕新 API 的讨论的结果,例如控制行为所需的输入映射工作,导致开发人员长期请求的功能得到改进。如果一切按计划进行,第三方控件应该可以构建,而无需依赖于内部 API。

动机

如果不进行这项工作,许多项目将需要显著减少它们提供的功能,对某些项目来说,这可能会导致灾难性的后果。例如,如果无法访问 Scene Builder 当前具有的内部 API,则可能无法正常运行 -- 肯定其提供 CSS 样式和控件属性操作等功能的能力将受到严重削弱,而这些也是 Scene Builder 的核心功能之一。对于大多数其他基于 JavaFX 的具有任何自定义控件或 CSS 实现程度的项目,同样适用这个论点。

描述

这个 JEP 被分成两个半相关的子项目,每个子项目都对达到最终目标很重要。这些项目必须进行的顺序没有特定的规定。

第一个项目:将 UI 控件皮肤变为公共 API

目前所有皮肤都位于 com.sun.javafx.scene.control.skin 中。这意味着扩展了皮肤(例如 TextFieldSkin)以添加额外功能、覆盖现有方法或以其他方式修改控件皮肤的可视化效果或行为的第三方将在 JDK 9 中无法正常使用。当然,这是用户依赖非公共 API 的错,但我们长期讨论使此 API 公共以更好地启用第三方修改 UI 控件。

意图是将许多 JavaFX 控件皮肤移动到适当的公共包中,最可能是 javafx.scene.control.skin。没有意图也移动相关的行为类。

这项工作的绝大部分工作是审查每个现有的皮肤类,确保以下内容:

  • 在皮肤之间存在 API 一致性,

  • 存在高质量的 Javadoc 和单元测试,以及

  • 通过将公共方法更改为私有来将每个类中的 API 最少化。

这项研究已经在另一个沙箱存储库中相当远,虽然耗费时间,但只有几个类值得关注,例如实用程序类、重复类和真正的仅限实现类需要进一步分析。除此之外,还有一些课程可能符合被带入 javafx.scene.control 包或者至少需要进一步考虑,因为它们不是真正的皮肤。这些包括 FXVK(虚拟键盘)、ColorPaletteCustomColorDialogDatePickerContentInputField。最后,有一些类,理想情况下,方法将被设为私有,除了事实上其他仅限实现类依赖于此 API。将针对所有这些问题调查解决方案,没有主要问题存在。

在 9 中将皮肤变为公共 API 的意图是确保它们的持续可用性。API 将有意保持到最少并尽量减少,这意味着我们打算在随后的发布中按照开发人员请求添加更有用的 API。众所周知,API(大多)永远不会改变,因此允许公共皮肤 API 在几个更新发布中成熟似乎是最好的行动方针。

截至 6 月中旬,该项目已经完成了几乎所有代码的移动和清理工作。意图是在 7 月中旬至 8 月初的 JDK 9 版本中将其公开。以下是移至 javafx.scene.control.skin 作为公共 API 的所有类列表:

  • AccordionSkin
  • ButtonBarSkin
  • ButtonSkin
  • CellSkinBase
  • CheckBoxSkin
  • ChoiceBoxSkin
  • ColorPickerSkin
  • ComboBoxBaseSkin
  • ComboBoxListViewSkin
  • ComboBoxPopupControl
  • ContextMenuSkin
  • DateCellSkin
  • DatePickerSkin
  • HyperlinkSkin
  • LabelSkin
  • LabeledSkinBase
  • ListCellSkin
  • ListViewSkin
  • MenuBarSkin
  • MenuButtonSkin
  • MenuButtonSkinBase
  • NestedTableColumnHeader
  • PaginationSkin
  • ProgressBarSkin
  • ProgressIndicatorSkin
  • RadioButtonSkin
  • ScrollBarSkin
  • ScrollPaneSkin
  • SeparatorSkin
  • SliderSkin
  • SpinnerSkin
  • SplitMenuButtonSkin
  • SplitPaneSkin
  • TabPaneSkin
  • TableCellSkin
  • TableCellSkinBase
  • TableColumnHeader
  • TableHeaderRow
  • TableRowSkin
  • TableRowSkinBase
  • TableViewSkin
  • TableViewSkinBase
  • TextAreaSkin
  • TextFieldSkin
  • TextInputControlSkin
  • TitledPaneSkin
  • ToggleButtonSkin
  • ToolBarSkin
  • TooltipSkin
  • TreeCellSkin
  • TreeTableCellSkin
  • TreeTableRowSkin
  • TreeTableViewSkin
  • TreeViewSkin
  • VirtualContainerBase
  • VirtualFlow

截至 6 月中旬,这些类已经剥离了几乎所有未从 SkinBase 继承的 API。前进时,意图是在根据早期访问构建收到反馈的情况下添加有用的 API。一些类,例如文本输入控件和虚拟化控件,已经具有支持其功能的其他 API。

第二个项目:审查并使有关 CSS 的 API 公共

与第一个项目一样,此项目涉及公开目前位于 com.sun.* 包中的 API。同样,这将需要代码审查以最小化 API,以及额外的单元测试和更多的文档。

这项工作的驱动程序将是继续允许 Scene Builder 在 JDK 9 中编译,采取适当的修改。

截至 6 月中旬,该项目已经完成了几乎所有代码的移动和清理工作。意图是在 7 月中旬至 8 月初的 JDK 9 版本中将其公开。以下是移至 javafx.css 作为公共 API 的所有类列表:

java
CascadingStyle.java:public class CascadingStyle implements Comparable<CascadingStyle> {
CascadingStyle.java:    public Style getStyle() {
CascadingStyle.java:    public CascadingStyle(final Style style, Set<PseudoClass> pseudoClasses,
CascadingStyle.java:    public String getProperty() {
CascadingStyle.java:    public Selector getSelector() {
CascadingStyle.java:    public Rule getRule() {
CascadingStyle.java:    public StyleOrigin getOrigin() {
CascadingStyle.java:    public ParsedValueImpl getParsedValueImpl() {

CompoundSelector.java:final public class CompoundSelector extends Selector {
CompoundSelector.java:    public List<SimpleSelector> getSelectors() {
CompoundSelector.java:    public CompoundSelector(List<SimpleSelector> selectors, List<Combinator> relationships)
CompoundSelector.java:    public Match createMatch() {

CssError.java:public class CssError {
CssError.java:    public static void setCurrentScene(Scene scene) {
CssError.java:    public final String getMessage() {
CssError.java:    public CssError(String message) {
CssError.java:    public final static class PropertySetError extends CssError {
CssError.java:        public PropertySetError(CssMetaData styleableProperty,

Declaration.java:final public class Declaration {
Declaration.java:    public ParsedValue getParsedValue() {
Declaration.java:    public String getProperty() {
Declaration.java:    public Rule getRule() {

Rule.java:final public class Rule {
Rule.java:    public final ObservableList<Declaration> getDeclarations() {
Rule.java:    public final ObservableList<Selector> getSelectors() {
Rule.java:    public Stylesheet getStylesheet() {
Rule.java:    public StyleOrigin getOrigin() {

Selector.java:abstract public class Selector {
Selector.java:    public Rule getRule() {
Selector.java:    public void setOrdinal(int ordinal) {
Selector.java:    public int getOrdinal() {
Selector.java:    public abstract Match createMatch();
Selector.java:    public abstract boolean applies(Styleable styleable);
Selector.java:    public abstract boolean applies(Styleable styleable, Set<PseudoClass>[] triggerStates, int bit);
Selector.java:    public abstract boolean stateMatches(Styleable styleable, Set<PseudoClass> state);
Selector.java:    public static Selector createSelector(final String cssSelector) {
Selector.java:    protected void writeBinary(DataOutputStream os, StringStore stringStore)

SimpleSelector.java:final public class SimpleSelector extends Selector {
SimpleSelector.java:    public String getName() {
SimpleSelector.java:    public List<String> getStyleClasses() {
SimpleSelector.java:    public Set<StyleClass> getStyleClassSet() {
SimpleSelector.java:    public String getId() {
SimpleSelector.java:    public NodeOrientation getNodeOrientation() {

Size.java:final public class Size {
Size.java:    public Size(double value, SizeUnits units) {
Size.java:    public double getValue() {
Size.java:    public SizeUnits getUnits() {
Size.java:    public boolean isAbsolute() {
Size.java:    public double pixels(double multiplier, Font font) {
Size.java:    public double pixels(Font font) {
Size.java:    public double pixels() {

Style.java:final public class Style {
Style.java:    public Selector getSelector() {
Style.java:    public Declaration getDeclaration() {
Style.java:    public Style(Selector selector, Declaration declaration) {

Stylesheet.java:public class Stylesheet {
Stylesheet.java:    public String getUrl() {
Stylesheet.java:    public StyleOrigin getOrigin() {
Stylesheet.java:    public void setOrigin(StyleOrigin origin) {
Stylesheet.java:    public List<Rule> getRules() {
Stylesheet.java:    public List<FontFace> getFontFaces() {
Stylesheet.java:    public static Stylesheet loadBinary(URL url) throws IOException {
Stylesheet.java:    public static void convertToBinary(File source, File destination) throws IOException {

CssParser.java:final public class CssParser {
CssParser.java:    public CssParser() {
CssParser.java:    public Stylesheet parse(final String stylesheetText) {
CssParser.java:    public Stylesheet parse(final URL url) throws IOException {
CssParser.java:    public Stylesheet parseInlineStyle(final Styleable node) {
CssParser.java:    public ParsedValueImpl parseExpr(String property, String expr) {
CssParser.java:    public static ObservableList<CssError> errorsProperty() {

概述

这两个项目的最终结果是创建:

  • 一个新的 javafx.scene.control.skin 包,用于 UI 控件皮肤,在经过审查、文档化和测试后;

  • 移动并审查、文档化和测试必要的与 CSS 相关的类。

测试

测试将限于没有特殊平台或硬件要求的额外单元测试。

风险和假设

主要风险是工作范围超出预期。已经进行了一些研究,以更好地理解要求,但不可否认的是,编写良好的 API 需要相当多的时间投入。