Playing with Color
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.
<font color="#7f0055"><b>public class </b></font><font color="#000000">RolloverForeground </font><font color="#7f0055"><b>extends </b></font><font color="#000000">JFrame </font><font color="#000000">{</font><br />
<font color="#ffffff"></font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>public </b></font><font color="#000000">RolloverForeground</font><font color="#000000">() {</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>this</b></font><font color="#000000">.setLayout</font><font color="#000000">(</font><font color="#7f0055"><b>new </b></font><font color="#000000">FlowLayout</font><font color="#000000">())</font><font color="#000000">;</font><br />
<font color="#ffffff"></font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>final </b></font><font color="#000000">JButton button = </font><font color="#7f0055"><b>new </b></font><font color="#000000">JButton</font><font color="#000000">(</font><font color="#2a00ff">"sample"</font><font color="#000000">)</font><font color="#000000">;</font><br />
<font color="#ffffff"> </font><font color="#000000">button.setForeground</font><font color="#000000">(</font><font color="#7f0055"><b>new </b></font><font color="#000000">Color</font><font color="#000000">(</font><font color="#990000">0x000000</font><font color="#000000">) {</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>private </b></font><font color="#000000">Color getDelegate</font><font color="#000000">() {</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>return </b></font><font color="#000000">button.getModel</font><font color="#000000">()</font><font color="#000000">.isRollover</font><font color="#000000">() </font><font color="#000000">? Color.red : Color.black;</font><br />
<font color="#ffffff"> </font><font color="#000000">}</font><br />
<font color="#ffffff"></font><br />
<font color="#ffffff"> </font><font color="#646464">@Override</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>public </b></font><font color="#000000">Color brighter</font><font color="#000000">() {</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>return </b></font><font color="#000000">getDelegate</font><font color="#000000">()</font><font color="#000000">.brighter</font><font color="#000000">()</font><font color="#000000">;</font><br />
<font color="#ffffff"> </font><font color="#000000">}</font><br />
<font color="#ffffff"></font><br />
<font color="#ffffff"> </font><font color="#646464">@Override</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>public synchronized </b></font><font color="#000000">PaintContext createContext</font><font color="#000000">(</font><font color="#000000">ColorModel cm,</font><br />
<font color="#ffffff"> </font><font color="#000000">Rectangle r, Rectangle2D r2d, AffineTransform xform,</font><br />
<font color="#ffffff"> </font><font color="#000000">RenderingHints hints</font><font color="#000000">) {</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>return </b></font><font color="#000000">getDelegate</font><font color="#000000">()</font><font color="#000000">.createContext</font><font color="#000000">(</font><font color="#000000">cm, r, r2d, xform, hints</font><font color="#000000">)</font><font color="#000000">;</font><br />
<font color="#ffffff"> </font><font color="#000000">}</font><br />
<font color="#ffffff"></font><br />
<font color="#ffffff"> </font><font color="#646464">@Override</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>public </b></font><font color="#000000">Color darker</font><font color="#000000">() {</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>return </b></font><font color="#000000">getDelegate</font><font color="#000000">()</font><font color="#000000">.darker</font><font color="#000000">()</font><font color="#000000">;</font><br />
<font color="#ffffff"> </font><font color="#000000">}</font><br />
<font color="#ffffff"></font><br />
<font color="#ffffff"> </font><font color="#646464">@Override</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>public </b></font><font color="#7f0055"><b>boolean </b></font><font color="#000000">equals</font><font color="#000000">(</font><font color="#000000">Object obj</font><font color="#000000">) {</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>return </b></font><font color="#000000">getDelegate</font><font color="#000000">()</font><font color="#000000">.equals</font><font color="#000000">(</font><font color="#000000">obj</font><font color="#000000">)</font><font color="#000000">;</font><br />
<font color="#ffffff"> </font><font color="#000000">}</font><br />
<font color="#ffffff"></font><br />
<font color="#ffffff"> </font><font color="#646464">@Override</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>public </b></font><font color="#7f0055"><b>int </b></font><font color="#000000">getAlpha</font><font color="#000000">() {</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>return </b></font><font color="#000000">getDelegate</font><font color="#000000">()</font><font color="#000000">.getAlpha</font><font color="#000000">()</font><font color="#000000">;</font><br />
<font color="#ffffff"> </font><font color="#000000">}</font><br />
<font color="#ffffff"></font><br />
<font color="#ffffff"> </font><font color="#646464">@Override</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>public </b></font><font color="#7f0055"><b>int </b></font><font color="#000000">getBlue</font><font color="#000000">() {</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>return </b></font><font color="#000000">getDelegate</font><font color="#000000">()</font><font color="#000000">.getBlue</font><font color="#000000">()</font><font color="#000000">;</font><br />
<font color="#ffffff"> </font><font color="#000000">}</font><br />
<font color="#ffffff"></font><br />
<font color="#ffffff"> </font><font color="#646464">@Override</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>public </b></font><font color="#7f0055"><b>float</b></font><font color="#000000">[] </font><font color="#000000">getColorComponents</font><font color="#000000">(</font><font color="#000000">ColorSpace cspace,</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>float</b></font><font color="#000000">[] </font><font color="#000000">compArray</font><font color="#000000">) {</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>return </b></font><font color="#000000">getDelegate</font><font color="#000000">()</font><font color="#000000">.getColorComponents</font><font color="#000000">(</font><font color="#000000">cspace, compArray</font><font color="#000000">)</font><font color="#000000">;</font><br />
<font color="#ffffff"> </font><font color="#000000">}</font><br />
<font color="#ffffff"></font><br />
<font color="#ffffff"> </font><font color="#646464">@Override</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>public </b></font><font color="#7f0055"><b>float</b></font><font color="#000000">[] </font><font color="#000000">getColorComponents</font><font color="#000000">(</font><font color="#7f0055"><b>float</b></font><font color="#000000">[] </font><font color="#000000">compArray</font><font color="#000000">) {</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>return </b></font><font color="#000000">getDelegate</font><font color="#000000">()</font><font color="#000000">.getColorComponents</font><font color="#000000">(</font><font color="#000000">compArray</font><font color="#000000">)</font><font color="#000000">;</font><br />
<font color="#ffffff"> </font><font color="#000000">}</font><br />
<font color="#ffffff"></font><br />
<font color="#ffffff"> </font><font color="#646464">@Override</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>public </b></font><font color="#000000">ColorSpace getColorSpace</font><font color="#000000">() {</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>return </b></font><font color="#000000">getDelegate</font><font color="#000000">()</font><font color="#000000">.getColorSpace</font><font color="#000000">()</font><font color="#000000">;</font><br />
<font color="#ffffff"> </font><font color="#000000">}</font><br />
<font color="#ffffff"></font><br />
<font color="#ffffff"> </font><font color="#646464">@Override</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>public </b></font><font color="#7f0055"><b>float</b></font><font color="#000000">[] </font><font color="#000000">getComponents</font><font color="#000000">(</font><font color="#000000">ColorSpace cspace, </font><font color="#7f0055"><b>float</b></font><font color="#000000">[] </font><font color="#000000">compArray</font><font color="#000000">) {</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>return </b></font><font color="#000000">getDelegate</font><font color="#000000">()</font><font color="#000000">.getComponents</font><font color="#000000">(</font><font color="#000000">cspace, compArray</font><font color="#000000">)</font><font color="#000000">;</font><br />
<font color="#ffffff"> </font><font color="#000000">}</font><br />
<font color="#ffffff"></font><br />
<font color="#ffffff"> </font><font color="#646464">@Override</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>public </b></font><font color="#7f0055"><b>float</b></font><font color="#000000">[] </font><font color="#000000">getComponents</font><font color="#000000">(</font><font color="#7f0055"><b>float</b></font><font color="#000000">[] </font><font color="#000000">compArray</font><font color="#000000">) {</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>return </b></font><font color="#000000">getDelegate</font><font color="#000000">()</font><font color="#000000">.getComponents</font><font color="#000000">(</font><font color="#000000">compArray</font><font color="#000000">)</font><font color="#000000">;</font><br />
<font color="#ffffff"> </font><font color="#000000">}</font><br />
<font color="#ffffff"></font><br />
<font color="#ffffff"> </font><font color="#646464">@Override</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>public </b></font><font color="#7f0055"><b>int </b></font><font color="#000000">getGreen</font><font color="#000000">() {</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>return </b></font><font color="#000000">getDelegate</font><font color="#000000">()</font><font color="#000000">.getGreen</font><font color="#000000">()</font><font color="#000000">;</font><br />
<font color="#ffffff"> </font><font color="#000000">}</font><br />
<font color="#ffffff"></font><br />
<font color="#ffffff"> </font><font color="#646464">@Override</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>public </b></font><font color="#7f0055"><b>int </b></font><font color="#000000">getRed</font><font color="#000000">() {</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>return </b></font><font color="#000000">getDelegate</font><font color="#000000">()</font><font color="#000000">.getRed</font><font color="#000000">()</font><font color="#000000">;</font><br />
<font color="#ffffff"> </font><font color="#000000">}</font><br />
<font color="#ffffff"></font><br />
<font color="#ffffff"> </font><font color="#646464">@Override</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>public </b></font><font color="#7f0055"><b>int </b></font><font color="#000000">getRGB</font><font color="#000000">() {</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>return </b></font><font color="#000000">getDelegate</font><font color="#000000">()</font><font color="#000000">.getRGB</font><font color="#000000">()</font><font color="#000000">;</font><br />
<font color="#ffffff"> </font><font color="#000000">}</font><br />
<font color="#ffffff"></font><br />
<font color="#ffffff"> </font><font color="#646464">@Override</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>public </b></font><font color="#7f0055"><b>float</b></font><font color="#000000">[] </font><font color="#000000">getRGBColorComponents</font><font color="#000000">(</font><font color="#7f0055"><b>float</b></font><font color="#000000">[] </font><font color="#000000">compArray</font><font color="#000000">) {</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>return </b></font><font color="#000000">getDelegate</font><font color="#000000">()</font><font color="#000000">.getRGBColorComponents</font><font color="#000000">(</font><font color="#000000">compArray</font><font color="#000000">)</font><font color="#000000">;</font><br />
<font color="#ffffff"> </font><font color="#000000">}</font><br />
<font color="#ffffff"></font><br />
<font color="#ffffff"> </font><font color="#646464">@Override</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>public </b></font><font color="#7f0055"><b>float</b></font><font color="#000000">[] </font><font color="#000000">getRGBComponents</font><font color="#000000">(</font><font color="#7f0055"><b>float</b></font><font color="#000000">[] </font><font color="#000000">compArray</font><font color="#000000">) {</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>return </b></font><font color="#000000">getDelegate</font><font color="#000000">()</font><font color="#000000">.getRGBComponents</font><font color="#000000">(</font><font color="#000000">compArray</font><font color="#000000">)</font><font color="#000000">;</font><br />
<font color="#ffffff"> </font><font color="#000000">}</font><br />
<font color="#ffffff"></font><br />
<font color="#ffffff"> </font><font color="#646464">@Override</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>public </b></font><font color="#7f0055"><b>int </b></font><font color="#000000">getTransparency</font><font color="#000000">() {</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>return </b></font><font color="#000000">getDelegate</font><font color="#000000">()</font><font color="#000000">.getTransparency</font><font color="#000000">()</font><font color="#000000">;</font><br />
<font color="#ffffff"> </font><font color="#000000">}</font><br />
<font color="#ffffff"> </font><font color="#000000">})</font><font color="#000000">;</font><br />
<font color="#ffffff"></font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>this</b></font><font color="#000000">.add</font><font color="#000000">(</font><font color="#000000">button</font><font color="#000000">)</font><font color="#000000">;</font><br />
<font color="#ffffff"> </font><font color="#000000">button.getModel</font><font color="#000000">()</font><font color="#000000">.addChangeListener</font><font color="#000000">(</font><font color="#7f0055"><b>new </b></font><font color="#000000">ChangeListener</font><font color="#000000">() {</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>public </b></font><font color="#7f0055"><b>void </b></font><font color="#000000">stateChanged</font><font color="#000000">(</font><font color="#000000">ChangeEvent e</font><font color="#000000">) {</font><br />
<font color="#ffffff"> </font><font color="#000000">button.repaint</font><font color="#000000">()</font><font color="#000000">;</font><br />
<font color="#ffffff"> </font><font color="#000000">}</font><br />
<font color="#ffffff"> </font><font color="#000000">})</font><font color="#000000">;</font><br />
<font color="#ffffff"></font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>this</b></font><font color="#000000">.setSize</font><font color="#000000">(</font><font color="#990000">200</font><font color="#000000">, </font><font color="#990000">100</font><font color="#000000">)</font><font color="#000000">;</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>this</b></font><font color="#000000">.setLocationRelativeTo</font><font color="#000000">(</font><font color="#7f0055"><b>null</b></font><font color="#000000">)</font><font color="#000000">;</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>this</b></font><font color="#000000">.setDefaultCloseOperation</font><font color="#000000">(</font><font color="#000000">JFrame.EXIT_ON_CLOSE</font><font color="#000000">)</font><font color="#000000">;</font><br />
<font color="#ffffff"> </font><font color="#000000">}</font><br />
<font color="#ffffff"></font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>public static </b></font><font color="#7f0055"><b>void </b></font><font color="#000000">main</font><font color="#000000">(</font><font color="#000000">String</font><font color="#000000">[] </font><font color="#000000">args</font><font color="#000000">) </font><font color="#7f0055"><b>throws </b></font><font color="#000000">Exception </font><font color="#000000">{</font><br />
<font color="#ffffff"> </font><font color="#000000">SwingUtilities.invokeLater</font><font color="#000000">(</font><font color="#7f0055"><b>new </b></font><font color="#000000">Runnable</font><font color="#000000">() {</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>public </b></font><font color="#7f0055"><b>void </b></font><font color="#000000">run</font><font color="#000000">() {</font><br />
<font color="#ffffff"> </font><font color="#7f0055"><b>new </b></font><font color="#000000">RolloverForeground</font><font color="#000000">()</font><font color="#000000">.setVisible</font><font color="#000000">(</font><font color="#7f0055"><b>true</b></font><font color="#000000">)</font><font color="#000000">;</font><br />
<font color="#ffffff"> </font><font color="#000000">}</font><br />
<font color="#ffffff"> </font><font color="#000000">})</font><font color="#000000">;</font><br />
<font color="#ffffff"> </font><font color="#000000">}</font><br />
<font color="#000000">}</font>
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:

Screenshot of the application in rollover state:

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.
- Login or register to post comments
- Printer-friendly version
- kirillcool's blog
- 612 reads





