JavaFX 8不可能使用Generic Type ComboBox?

时间:2017-07-12 13:01:38

标签: generics javafx types combobox

我在JavaFX 8中做了一个GUI。

我的输入经过

TextFields - 大小相同&造型

ComboBoxes - 所有相同的尺寸和尺寸样式与TextFields上的样式相同

滑块 - 这些是两个TextField的替代输入方法,用户可能希望快速查看最终图形上不同的2个角度的效果。 A"滑块开/关"按钮允许用户允许滑块输入。

为我的所有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作为我的ComboBox中的对象类型 - 我希望每个框具有不同的枚举类型的安全性。 如果我写这段代码:

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

我没有错误。 但我认为无法将ComboBox of Objects转换为枚举的ComboBox。 。

到目前为止,我能够解决的唯一方法是拥有5个独立的内部类 - 每个ComboBox一个,每个代码中95%的代码完全相同。 这显然违反了&#34;写了一次&#34; 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是原始类型。应该对泛型类型Enum的引用进行参数化。

我抛出了所有尺寸,接近和着色到CSS文件中,因此内部类只允许我避免为我使用的每个ComboBox实例引用 sm-combo-box (目前为止为5个)。

尽管有警告,所有人似乎都运作良好。

1 个答案:

答案 0 :(得分:1)

误解

ComboBox<Object>不是泛型类型参数声明的好定义。按照惯例,泛型类型参数声明是单个字母,但更重要的是,它与已定义的类(例如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;");
    }
}

示例代码

sample output

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类型选择器来定义样式,并且需要选择器来设置组合框弹出窗口的样式(据我所知)。因此通常首选使用样式表。

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

术语背景

来自Java generics tutorial

  

类型参数和类型参数术语:许多开发人员使用   术语&#34;类型参数&#34;和&#34;输入参数&#34;可以互换,但这些   条款不一样。编码时,一个提供类型参数   以创建参数化类型。因此,T中的Foo<T>是一个   type参数和String中的Foo<String> f是一个类型参数。   本课程在使用这些术语时会遵循此定义。