Reputation: 8708
I'm writing a custom JComponent
, that should look differently for different look and feels. I intend to have different ComponentUi
classes at least for the WindowsLookAndFeel
, the MetalLookAndFeel
and for the MotifLookAndFeel
.
Now, while this task seems easy enough, I couldn't find out how to easily extend an existing look and feel with my custom ComponentUi
classes.
How would I go about registering the correct ComponentUi
for the different look and feels? Is this possible at all? If not, what is the preferred way to write a custom component for different look and feels?
To be a bit more specific, at the moment I'm overriding JComponent#updateUI
in my custom component to set the different ComponentUi
instances:
@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));
}
}
But this approach seems to entirely defeat the purpose and usefulness of look and feels. I'd like to be able to change this to the following:
public void updateUI() {
setUI((MyCustomUi)UIManager.getUI(this));
}
And this should set the correct subclass of MyCustomUi
for the current look and feel.
I know, that I could easily achieve this by creating custom subclasses of each supported LookAndFeel
, that register the corresponding ComponentUi
during e.g. BasicLookAndFeel#initComponentDefaults(UIDefaults)
- but this is not what I want to do.
Upvotes: 3
Views: 1337
Reputation: 51524
If you want it or not - you have to register your custom UIs somehow with the UIManager, how else could it know about them ;-)
What you don't need, though, is a custom subclass of the supported LAFs: you can register them manually (and update the registration when the LAF is changed, that is you'll need a propertyChangeListener on the UIManager to be notified in such a case).
Assuming a JCustom with a classID of "CustomUI" and ui implementations following the usual conventions (that is BasicCustomUI, WindowsCustomUI ... ) the registration would be something like:
String prefix = UIManager.getLookAndFeel().getID();
UIManager.getLookAndFeelDefaults().put("CustomUI", myUIPackage + "." + prefix + CustomUI);
Note that the custom ui needs a static createUI which returns an instance of the ui:
public static ComponentUI createUI(JComponent comp) {
return new BasicCustomUI();
}
and the component needs to publish its uiClassID, lookup and set its ui:
@Override
public String getUIClassID() {
return "CustomUI";
}
@Override
public void updateUI() {
setUI(UIManager.getUI(this));
}
The benefit of using SwingX is to provide the infrastructure to automagically register custom components. You'll need an additional class - CustomAddon - which provides the per-LAF configuration and the custom component has to contribute that addon:
// 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
Upvotes: 5