The Source for Java Technology Collaboration
User: Password:
Register | Login help    

Search

Online Books:
java.net on MarkMail:


Playing with Color

Posted by kirillcool on January 17, 2007 at 9:40 AM PST

Seeing that this subject has popped up twice over the last two days (here and here), i decided to share a little trick to make a Color object mutable.

In general, the Color class doesn't allow changing the existing object. However, since it's not final, we can use the Delegate pattern and direct all methods to a single "master" color that is computed dynamically. The master color computation can depend, for example, on rollover state (illustrated below) which will allow creating rollover effects without triggering the property change events (on the "foregroundColor" property).

Here is how it's done.

public class RolloverForeground extends JFrame {

  public RolloverForeground() {
    this.setLayout(new FlowLayout());

    final JButton button = new JButton("sample");
    button.setForeground(new Color(0x000000) {
      private Color getDelegate() {
        return button.getModel().isRollover() ? Color.red : Color.black;
      }

      @Override
      public Color brighter() {
        return getDelegate().brighter();
      }

      @Override
      public synchronized PaintContext createContext(ColorModel cm,
          Rectangle r, Rectangle2D r2d, AffineTransform xform,
          RenderingHints hints) {
        return getDelegate().createContext(cm, r, r2d, xform, hints);
      }

      @Override
      public Color darker() {
        return getDelegate().darker();
      }

      @Override
      public boolean equals(Object obj) {
        return getDelegate().equals(obj);
      }

      @Override
      public int getAlpha() {
        return getDelegate().getAlpha();
      }

      @Override
      public int getBlue() {
        return getDelegate().getBlue();
      }

      @Override
      public float[] getColorComponents(ColorSpace cspace,
          float[] compArray) {
        return getDelegate().getColorComponents(cspace, compArray);
      }

      @Override
      public float[] getColorComponents(float[] compArray) {
        return getDelegate().getColorComponents(compArray);
      }

      @Override
      public ColorSpace getColorSpace() {
        return getDelegate().getColorSpace();
      }

      @Override
      public float[] getComponents(ColorSpace cspace, float[] compArray) {
        return getDelegate().getComponents(cspace, compArray);
      }

      @Override
      public float[] getComponents(float[] compArray) {
        return getDelegate().getComponents(compArray);
      }

      @Override
      public int getGreen() {
        return getDelegate().getGreen();
      }

      @Override
      public int getRed() {
        return getDelegate().getRed();
      }

      @Override
      public int getRGB() {
        return getDelegate().getRGB();
      }

      @Override
      public float[] getRGBColorComponents(float[] compArray) {
        return getDelegate().getRGBColorComponents(compArray);
      }

      @Override
      public float[] getRGBComponents(float[] compArray) {
        return getDelegate().getRGBComponents(compArray);
      }

      @Override
      public int getTransparency() {
        return getDelegate().getTransparency();
      }
    });

    this.add(button);
    button.getModel().addChangeListener(new ChangeListener() {
      public void stateChanged(ChangeEvent e) {
        button.repaint();
      }
    });

    this.setSize(200100);
    this.setLocationRelativeTo(null);
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  }

  public static void main(String[] argsthrows Exception {
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        new RolloverForeground().setVisible(true);
      }
    });
  }
}

The most interesting part is the getDelegate method in our foreground color. It returns black or red depending on the rollover state of the model. All the Color methods use this color, delegating the real implementation to it. Screenshot of the application in default state:

default.png

Screenshot of the application in rollover state:

rollover.png

Note that this technique can be easily extended to smoothly animate the foreground color from black to red without triggering property change events along the way.

Related Topics >> Java Desktop      
Comments
Comments are listed in date ascending order (oldest first)