Java 使用自定义JComponents扩展现有Swing外观

Java 使用自定义JComponents扩展现有Swing外观,java,swing,custom-component,look-and-feel,uimanager,Java,Swing,Custom Component,Look And Feel,Uimanager,我正在编写一个定制的JComponent,它的外观和感觉应该有所不同。我打算至少为WindowsLookAndFeel、MetalLookAndFeel和motif lookandfeel提供不同的ComponentUi类 现在,虽然这项任务似乎很简单,但我无法找到如何使用自定义的ComponentUi类轻松扩展现有的外观 如何注册正确的组件ui,以获得不同的外观和感觉?这可能吗?如果没有,为不同的外观编写自定义组件的首选方法是什么 更具体地说,目前我正在覆盖自定义组件中的JComponent

我正在编写一个定制的
JComponent
,它的外观和感觉应该有所不同。我打算至少为
WindowsLookAndFeel
MetalLookAndFeel
motif lookandfeel
提供不同的
ComponentUi

现在,虽然这项任务似乎很简单,但我无法找到如何使用自定义的
ComponentUi
类轻松扩展现有的外观

如何注册正确的
组件ui
,以获得不同的外观和感觉?这可能吗?如果没有,为不同的外观编写自定义组件的首选方法是什么


更具体地说,目前我正在覆盖自定义组件中的
JComponent#updateUI
,以设置不同的
ComponentUi
实例:

@Override
public void updateUI() {
    LookAndFeel feel = UIManager.getLookAndFeel();
    if (feel instanceof WindowsLookAndFeel) {
        setUI(MyWindowsCustomUi.createUI(this));
    } else if (feel instanceof MotifLookAndFeel) {
        setUI(MyMotivCustomUi.createUI(this));
    } else if (feel instanceof MetalLookAndFeel) {
        setUI(MyMetalCustomUi.createUI(this));
    } else{
        setUI(MyBasicCustomUi.createUI(this));
    }
}
但这种方法似乎完全违背了外观的目的和用途。我希望能够将此更改为以下内容:

public void updateUI() {
    setUI((MyCustomUi)UIManager.getUI(this));
}
这应该为当前的外观设置正确的
MyCustomUi
子类


我知道,我可以通过创建每个受支持的
LookAndFeel
的自定义子类轻松实现这一点,这些子类在
BasicLookAndFeel#initComponentDefaults(UIDefaults)期间注册相应的
ComponentUi
-但这不是我想做的。

如果你想不想-你必须以某种方式向UIManager注册你的自定义UI,否则它怎么知道它们;-)

不过,您不需要的是受支持的LAF的自定义子类:您可以手动注册它们(并在LAF更改时更新注册,也就是说,在这种情况下,您需要UIManager上的propertyChangeListener得到通知)

假设JCustom的classID为“CustomUI”,ui实现遵循通常的约定(即BasicCustomMUI、WindowsCustomUI…),注册如下:

 String prefix = UIManager.getLookAndFeel().getID();
 UIManager.getLookAndFeelDefaults().put("CustomUI", myUIPackage + "." + prefix + CustomUI);
请注意,自定义ui需要返回ui实例的静态createUI:

 public static ComponentUI createUI(JComponent comp) {
     return new BasicCustomUI(); 
 }
组件需要发布其uiClassID,查找并设置其ui:

@Override
public String getUIClassID() {
    return "CustomUI";
}

@Override
public void updateUI() {
    setUI(UIManager.getUI(this));
}
使用SwingX的好处是提供自动注册自定义组件的基础结构。您将需要一个额外的类CustomAddon,它提供每个LAF配置,并且自定义组件必须提供该插件:

// in JCustom

static {
    LookAndFeelAddons.contribute(new CustomAddon());
}

// in CustomAddon

@Override
protected void addBasicDefaults(LookAndFeelAddons addon, DefaultsList defaults) {
    super.addBasicDefaults(addon, defaults);
    defaults.add("CustomUI",
            "mypackage.BasicCustomUI");
}

@Override
protected void addMacDefaults(LookAndFeelAddons addon, DefaultsList defaults) {
    super.addMacDefaults(addon, defaults);
    defaults.add("CustomUI",
            "mypackage.MacCustomUI");
}

//... similar methods for all supported LAFs

非常感谢您-我使用SwingX中的
lookandfeeladons.contribution()
注册了自定义组件,它工作起来很有魅力。