I'm creating a custom component with its own custom UI. The question How to create a custom Swing Component provided a great start in developing the component, but I haven't been able to find a good way to connect the custom component with its UI.
The code in How to Write a Custom Swing Component is good, but the implementation of JFlexiSlider.updateUI
hard codes the UI to use BasicFlexiSliderUI
:
public void updateUI() {
if (UIManager.get(getUIClassID()) != null) {
setUI((FlexiSliderUI) UIManager.getUI(this));
} else {
setUI(new BasicFlexiSliderUI());
}
}
The standard Swing components implement updateUI
to simply set the UI directly from UIManager.get(this)
. The mapping from the UIClassID
to the actual implementation is in BasicLookAndFeel
and subclasses.
In my case, where I don't want to create a new look and feel, where would I set the default mapping from my UIClassID
to the actual implementation? It seems like it should be outside the component class, but it needs to be added to the UIDefaults
object prior to the first use of the custom component.
The essential collaborators:
In code something like:
/**
* The custom component
*/
public class Block extends JComponent {
private final static String ID = "BlockUI";
public Block(Color color) {
// configure
setBackground(color);
// install ui
updateUI();
}
@Override
public void updateUI() {
// ask the ui manager for an appropriate ui and set it
setUI(UIManager.getUI(this));
}
/**
* Implemented to return a unique component class identifier
*/
@Override
public String getUIClassID() {
return ID;
}
}
/**
* For each supported LAF, a laf-specific implementation
*/
public class BasicBlockUI extends ComponentUI {
public static ComponentUI createUI(JComponent c) {
return new BasicBlockUI();
}
@Override
public void paint(Graphics g, JComponent c) {
g.setColor(c.getBackground());
g.fillRect(10,10, c.getWidth()- 20, c.getHeight()-20);
}
}
// usage
//let the ui manager know of our component
// the value must be the fully qualified classname
UIManager.put("BlockUI", "org.jdesktop.swingx.plaf.BasicBlockUI");
JXFrame frame = new JXFrame("custom box", true);
Block block = new Block(Color.RED);
frame.add(block);
frame.setSize(200, 200);
frame.setVisible(true);
If you want to support several LAFs, you might have a look into a recent QA which illustrates the SwingX mechanism to plug-in custom components.