【问题标题】:Generic Type ComboBox Impossible For JavaFX 8?JavaFX 8 不可能的通用类型组合框?
【发布时间】:2017-07-12 13:01:38
【问题描述】:

我在 JavaFX 8 中做一个 GUI。

我的输入通过任何一个

TextFields - 大小和样式都相同

ComboBoxes - 大小和样式都与 TextFields 上的相同

滑块 - 这些是 2 个 TextFields 的替代输入方法,用户可能希望在其中快速查看不同 2 个角度对最终图形的影响。 “滑块开/关”按钮允许用户允许滑块输入。

为我的所有 TextField 输入定义一个内部类并在其中应用所有样式、大小等都没有问题,例如

// Inner Class To Configure GUI TextField Nodes:
class SMTextField extends TextField
{
    public SMTextField()
    {
        super();
        super.setPrefWidth(150);
        super.setPrefHeight(40);
        super.setBackground(new Background(new BackgroundFill(Color.rgb(255,140,0),
                CornerRadii.EMPTY, Insets.EMPTY)));                         // Orange background                        
        super.setBorder(new Border(new BorderStroke(Color.rgb(255, 255, 0), // Yellow border
                BorderStrokeStyle.SOLID, CornerRadii.EMPTY, new BorderWidths(2.0))));
        super.setStyle("-fx-text-fill: blue;"
                     + "-fx-prompt-text-fill: white;"
                     + "-fx-font-family: 'Calibri';"
                     + "-fx-font-size: 11pt;"
                     + "-fx-alignment: center");    
    }
}

但是当我尝试为 ComboBox 输入做类似的事情时,它不允许我按照我想要的方式这样做。 我想避免将 String 作为我的 ComboBoxes 中的对象类型 - 我希望每个框都有不同的枚举类型的安全性。 如果我写这段代码:

// Inner class for generic ComboBox
class IComboBox extends ComboBox<Object>
{
    .....
    // Sizing & styling code
    .....
}

我没有错误。 但是我看不到将 Objects 的 ComboBox 转换为 enums 的 ComboBox 的方法。 . .

到目前为止,我唯一能做到这一点的方法是拥有 5 个独立的内部类 - 每个 ComboBox 一个,每个 ComboBox 中 95% 的代码完全相同。 这显然违反了 OOP 的“一次编写”原则。

谁能展示一个更好的方法来做一系列具有相同样式代码的枚举组合框而不需要重复?

编辑

好的,对于定义我的 GUI ComboBox 的内部类,我正在做类似的事情:

// Inner class to define combo box layout:
    class SMComboBox<T extends Enum> extends ComboBox<T>
    {
        public SMComboBox()
        {
            super();
            super.getStyleClass().add("sm-combo-box");                      
        }
    }

样式 sm-combo-box 位于 start 方法开头引用的 CSS 文件中。

上面的内部类显示了一个我不明白的警告:-

  • 类型参数 T 隐藏了类型 T。
  • 枚举是原始类型。应该对泛型类型 Enum 的引用进行参数化。

我已将所有尺寸、边框和颜色都放入 CSS 文件中,因此内部类仅允许我避免为我使用的每个 ComboBox 实例引用 sm-combo-box (5到目前为止)。

尽管有警告,但一切似乎都运行良好。

【问题讨论】:

  • 您真的不需要为了应用样式而对控件进行子类化(或扩展)!您可以设置样式类并通过 CSS 进行样式设置,或者使用工厂方法创建具有正确样式的控件。在这种情况下,创建一个新课程完全是矫枉过正。
  • 关于样式,可以应用CSS。 (您建议,CSS 类的开销小于 JavaFX 内部类的开销?)但是关于具有枚举类型的 ComboBoxes 的主要问题。 . . ?继续定义一些 ComboBox box1 = ComboBox();然后添加 CSS 样式类?
  • 是的,SillyFly - 将样式与代码分离的想法是合理的。谢谢。

标签: generics javafx types combobox


【解决方案1】:

误解

ComboBox&lt;Object&gt; 不是泛型类型参数声明的好定义。按照惯例,泛型类型参数声明是单个字母,但更重要的是,它与已定义的类(例如 Object)不同,因为这样做确实令人困惑。

示例类型定义

所以,而不是:

class IComboBox extends ComboBox<Object>

这表示IComboBox中放置的项目类型必须是Object(并且只有Object而不是object的子类),所以不是特别有用,

写下下面的语句来说明你的 ComboBox 扩展类可以有一个泛型类型参数:

class IComboBox<T> extends ComboBox<T>

其中 T 是类型参数名称,根据 standard type parameter naming conventions 定义。

如果您想限制自定义组合框的类型,则可以使用 extends 子句对类型进行绑定,例如以下仅允许 Enum 类型作为具体类型参数的语句。

class EnumComboBox<T extends Enum> extends ComboBox<T> {
}

如果你想在运行时根据类型做一些事情(比如用可能的枚举值填充组合框),那么你还需要pass the type class at runtime(因为 Java 使用类型擦除并且在运行时不具体化类型):

class EnumComboBox<T extends Enum> extends ComboBox<T> {
    EnumComboBox(Class<T> type) {
        super(FXCollections.observableArrayList(type.getEnumConstants()));

        setStyle("-fx-text-base-color: forestgreen;");
    }
}

示例代码

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class EnumCombos extends Application {
    class EnumComboBox<T extends Enum> extends ComboBox<T> {
        EnumComboBox(Class<T> type) {
            super(FXCollections.observableArrayList(type.getEnumConstants()));

            setStyle("-fx-text-base-color: forestgreen;");
        }
    }

    @Override
    public void start(Stage stage) throws Exception {
        EnumComboBox<Heavenly> heavenlyCombo = new EnumComboBox<>(Heavenly.class);
        EnumComboBox<Earthly>  earthlyCombo  = new EnumComboBox<>(Earthly.class);

        VBox layout = new VBox(10, heavenlyCombo, earthlyCombo);
        layout.setPadding(new Insets(10));

        stage.setScene(new Scene(layout));
        stage.show();
    }

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

    enum Heavenly {
        SUN,
        MOON,
        STARS
    }

    enum Earthly {
        EARTH,
        WIND,
        FIRE
    }
}

在代码中定义组合框样式的注意事项

尝试在组合框的代码中设置样式不如尝试通过样式表中的样式来实现灵活。 setStyle 方法不能使用 css 类型选择器来定义样式,并且需要选择器来设置组合框弹出窗口的样式(据我所知)。因此,通常首选使用样式表。

如果您愿意,您可以将样式表与此答案中定义的子类化机制结合使用(将 setStyle 调用替换为 getStyleClass().add() 调用来执行此操作),因此样式表和子类化的使用并不相互排斥(事实上,大多数内置 JavaFX 控件都是这样定义的)。

术语背景

来自Java generics tutorial

类型参数和类型参数术语: 许多开发人员使用 术语“类型参数”和“类型参数”可互换,但这些 条款不一样。编码时,提供类型参数 为了创建参数化类型。因此,Foo&lt;T&gt; 中的 T 是 类型参数和Foo&lt;String&gt; f 中的String 是一个类型参数。 本课在使用这些术语时遵守此定义。

【讨论】:

  • 综合回答。谢谢,jewelsea。
猜你喜欢
  • 1970-01-01
  • 2014-11-26
  • 2014-07-21
  • 2015-02-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多