将皮肤应用于所有JavaFX子控件

时间:2017-09-12 06:56:30

标签: java javafx-8

我正在使用两个自定义皮肤实现一些JavaFX控件。我有一些基本的控件,每个都有两个不同的皮肤,一个控件将其中两个组合在一起。我现在想知道当我想以相同的方式对两个嵌入式控件进行换肤时如何实现复合控件的外观,即复合控件应该有两个外观,当我应用其中一个嵌入式控件时也被剥皮了。基本上,我想在控制图上递归应用皮肤。

class Control1 extends Control {}
class Control1Skin1 extends SkinBase<Control1> {}
class Control1Skin2 extends SkinBase<Control1> {}

class Control2 extends Control {}
class Control2Skin1 extends SkinBase<Control1> {}
class Control2Skin2 extends SkinBase<Control1> {}

class CompositeControl extend Control {
    private final Control1 ctrl1 = new Control1();
    private final Control2 ctrl2 = new Control2();
}

class CompositeControlSkin1 extends SkinBase<Control1> {}
class CompositeControlSkin2 extends SkinBase<Control1> {}
  1. 制作皮肤的控件成员。这导致代码重复并将逻辑移入不属于那里的皮肤。
  2. CompositeControl添加访问者以访问嵌入式控件。这破坏了封装。
  3. 将成员包设为私有,以便皮肤可以访问它们并适当地设置皮肤。封装中的轻微漏洞,但皮肤和控制类无论如何形成一个有凝聚力的集群。
  4. 定义一个自定义CompositeControlSkin接口,该接口具有返回子控件外观的方法。然后,我必须将CompositeControl.setSkin(Skin skin)to cast the skin`参数覆盖到新界面中,获取皮肤并设置它们。这需要像3中那样访问成员,但另外还需要进行下击。我认为这取消了这种方法的资格。
  5. 我想知道JavaFX中是否有更好的方法,例如复合皮肤。我找到的关于自定义skinnable控件的文档有点稀疏,所以我会很感激任何链接或提示。

1 个答案:

答案 0 :(得分:2)

首先,确保你真的需要额外的皮肤。只有在希望控件的外观和行为与默认控件完全不同时才需要外观。 通常,使用CSS设置应用程序样式就足够了。

如果您得出结论,您确实需要额外的皮肤,请检查以下步骤:

  1. 每个skinnable自定义控件都应具有特定的样式类
  2. private static final String DEFAULT_STYLE_CLASS = "my-control";
    
        [...]
    
        public MyControl(){
            getStyleClass().setAll(DEFAULT_STYLE_CLASS);
        }
    
    1. 识别实际需要额外皮肤的控件。对于所有控件可能都不是这样(例如,可能不需要复合控件的其他外观)

    2. 覆盖您要在自定义CSS中使用的外观:

    3. .my-control { 
          -fx-skin: "somepackage.skin.MyControlSkin2";
      }
      

      请注意,如果您确实需要高度可自定义且高度可重复使用的控件,则只需要扩展Control并提供外观。

      对于应用程序开发人员,大多数情况下您可以使用fx:root FXML构造创建可重用控件。例如。您的复合控件可能是此的候选对象。

      自定义skinnable控件通常不包含其他控件,因为这会将控件绑定到特定的外观。如果需要可换肤复合控件,嵌套控件应该在皮肤中,而不是在控件中。