Search code examples
javaswingnimbus

Reusable Nimbus painting components (Focus ring)


I am creating custom Swing components and want to provide a UI that looks just like Nimbus.

I know how to access the UIDefaults colors, but can I reuse more code, particularly, is there a way to get an object that paints the focus rings (rectangular or oval, or even better, along any outline Shape) exactly like the other Nimbus components do? (without reinventing the wheel)


Solution

  • As I didn't see any design decision in Nimbus to allow the reuse of painters for new components, and also I'm stuck on OS X with Java 6 and Nimbus being a moving (namespace) target, here is my solution which basically recreates what the Synth style is using:

    import javax.swing.*;
    import java.awt.*;
    import java.awt.geom.*;
    
    public class NimbusFocusBorder implements javax.swing.border.Border {
        private static final RoundRectangle2D rect = new RoundRectangle2D.Float();
        private static final Area area = new Area();
    
        private final float arcIn;
        private final float arcOut;
    
        public NimbusFocusBorder() {
            arcIn = arcOut = 0f;
        }
    
        public NimbusFocusBorder( float rounded ) {
            arcIn  = rounded * 2;
            arcOut = arcIn + 2.8f;
        }
    
        public void paintBorder( Component c, Graphics _g, int x, int y, int w, int h ) {
            if( !c.hasFocus() ) return;
            final Graphics2D g = (Graphics2D) _g;
            g.setRenderingHint( RenderingHints.KEY_ANTIALIASING,
                                RenderingHints.VALUE_ANTIALIAS_ON );
            g.setColor( /* NimbusHelper. */ getFocusColor() );
            rect.setRoundRect( x + 0.6, y + 0.6, w - 1.2, h - 1.2, arcOut, arcOut );
            area.reset();
            area.add( new Area( rect ));
            rect.setRoundRect( x + 2, y + 2, w - 4, h - 4, arcIn, arcIn );
            area.subtract( new Area( rect ));
            g.fill( area );
    
        }
    
        public Insets getBorderInsets( Component c ) {
            return new Insets( 2, 2, 2, 2 );
        }
    
        public boolean isBorderOpaque() { return false; }
    
        // this actually looks up the color in UIDefaults
        // in the real implementation
        private Color getFocusColor() { return new Color( 115, 164, 209, 255 );}
    }