<?xml version="1.0" encoding="utf-8"?>
<feed version="0.3" xmlns="http://purl.org/atom/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="en">
<title>Alexander Potochkin&apos;s Blog</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/alexfromsun/" />
<modified>2008-07-19T13:11:47Z</modified>
<tagline></tagline>
<id>tag:weblogs.java.net,2008:/blog/alexfromsun/284</id>
<generator url="http://www.movabletype.org/" version="3.01D">Movable Type</generator>
<copyright>Copyright (c) 2008, alexfromsun</copyright>
<entry>
<title>JXLayer 3.0 - Painting implementation</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/alexfromsun/archive/2008/07/jxlayer_30_how.html" />
<modified>2008-07-19T13:11:47Z</modified>
<issued>2008-07-17T12:26:52Z</issued>
<id>tag:weblogs.java.net,2008:/blog/alexfromsun/284.10109</id>
<created>2008-07-17T12:26:52Z</created>
<summary type="text/plain">JXLayer painting implementation details</summary>
<author>
<name>alexfromsun</name>

<email>Alexander.Potochkin@Sun.COM</email>
</author>
<dc:subject>Swing</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/alexfromsun/">
<![CDATA[The <a href="https://jxlayer.dev.java.net/">JXLayer's</a> functionality consists of two parts: painting issues and input event processing.
<br/>In this entry I'll describe painting in details, the second part will come shortly.
<h2>Painting issues</h2>

With the JXLayer you can easily customize the visual appearance of your component and the most trivial example is painting on top of a component. However you should know some details to implement it properly.
<p/>Imagine that you need to implement a custom panel with a red line goes from one corner to another, like this:

<p/>
<blockquote>
<img src="https://swinghelper.dev.java.net/bin/blog/painting/1.PNG" alt="demo screenshot"></img></blockquote>

<p/>
Since the panel may contain child components we need to make sure that this line will paint over them. For this reason, overridden JComponent.paintComponent() will not work for us, because it is called before child components are painted. The only solution in this case is to override JComponent.paint() method and do our custom painting after the entire component is painted.

<blockquote><code>
<pre style="line-height: 120%;font-family:monospace;background-color:#ffffff; border-width:0mm; border-color:#000000; border-style:solid; padding:4px;"><span style="color:#000080;background-color:#ffffff;font-weight:bold;">class</span><span style="background-color:#ffffff;"> MyPanel </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">extends</span><span style="background-color:#ffffff;"> JPanel {

    </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// Note that we override paint(), not paintComponent()
</span><span style="background-color:#ffffff;">    </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// because we want to paint over panel's children   
</span><span style="background-color:#ffffff;">    </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">public</span><span style="background-color:#ffffff;"> </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">void</span><span style="background-color:#ffffff;"> paint(Graphics g) {
        </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">super</span><span style="background-color:#ffffff;">.paint(g);
        g.setColor(Color.</span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;font-style:italic;">RED)</span><span style="background-color:#ffffff;">;
        g.drawLine(</span><span style="color:#0000ff;background-color:#ffffff;">0</span><span style="background-color:#ffffff;">,getHeight(), getWidth(), </span><span style="color:#0000ff;background-color:#ffffff;">0</span><span style="background-color:#ffffff;">);
    }
}
</span></pre></code></blockquote>

Let's put some components inside this panel and have a look:
<p/>
<blockquote>
<img src="https://swinghelper.dev.java.net/bin/blog/painting/2.PNG" alt="demo screenshot"></img></blockquote>

<p/>
Wow, it seems to work! But...<br/>
It works only when the whole panel is repainted, if you move the mouse over the buttons and type something in the textField, you'll see this picture:
<p/>
<blockquote>
<img src="https://swinghelper.dev.java.net/bin/blog/painting/3.PNG" alt="demo screenshot"></img></blockquote>

<p/>
Here we found the main problem that prevents us from decorating the Swing containers:

<hr/>
<b>When a component is repainted, the paint() method from its parent doesn't get called.</b>
<hr/>

There are three known solutions, how to make the container repaint when any of its children are repainted:

<ol>
<li>Make every child component not opaque.</li>
<li>Implement and set a custom global RepaintManager.</li>
<li>Put a transparent panel on top of our container.
</ol>

<p/>All three method do the same thing - they repaint a part of a container when its child component is repainted, therefore none of them is visibly faster then the others. For JXLayer implementation I examined all of them:

<p/>First method is not the best, because a component may look differently depending on its opaque state. JLabel is a good example - by default, the component is translucent, but if you set its opaque property to true, you'll see the solid background. If a component is opaque, we can't predict how it will look like if we make it not opaque, that's why we can't arbitrarily change this state.

<p/>Custom RepaintManager doesn't change the state of the components and generally works well, for example SwingX library substitues the system RepaintManager with their own <a href="https://swingx.dev.java.net/source/browse/swingx/src/java/org/jdesktop/swingx/RepaintManagerX.java?view=markup">RepaintManagerX</a>. However, RepaintManager is a global resource and your own implementation will work well only if no other component tries to set another one. I wanted JXLayer to be compatible with libraries like SwingX and that's why I couldn't use my own RepaintManager.

<p/>
I found the transparent panel approach the best choice, because it doesn't affect component's state nor any global settings. I only needed to introduce a transparent panel which covers the whole layer, it's not a problem because I have full control of the hierarchy of JXLayer. This transparent panel called glassPane and you can get it by JXLayer.getGlassPane(). Note that it has nothing to do (except the name) with the glassPane from JFrame. 
<p/>

<hr>
<b>When a component is covered by another transparent component, they are always repainted together and the painting starts from their common ancestor, in our case this is JXLayer component.</b>
<hr>

<p/>
Swing is smart enough to not paint more than necessary. If a JXLayer child is repainted, it doesn't mean that the whole JXLayer is repainted - painting happens only within the bounds of the child component. 

<h2>Conclusion</h2>

The JXLayer's glassPane guarantees that layer's paint() method will be notified when any of its child components are repainted. It allows us to implement LayerUIs that paint over the layer:

<blockquote><code>
<pre style="line-height: 120%;font-family:monospace;background-color:#ffffff; border-width:0mm; border-color:#000000; border-style:solid; padding:4px;"><span style="color:#000080;background-color:#ffffff;font-weight:bold;">class</span><span style="background-color:#ffffff;"> MyLayerUI </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">extends</span><span style="background-color:#ffffff;"> AbstractLayerUI&lt;JComponent&gt; {

    </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// Override paintLayer(), not paint() 
</span><span style="background-color:#ffffff;">    </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">protected</span><span style="background-color:#ffffff;"> </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">void</span><span style="background-color:#ffffff;"> paintLayer(Graphics2D g2, JXLayer&lt;JComponent&gt; l) {
        
        </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// You can paint before the layer
</span><span style="background-color:#ffffff;">        </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// it makes sense if you make the layer not opaque
</span><span style="background-color:#ffffff;">        </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// in the installUI() method of this LayerUI
</span><span style="background-color:#ffffff;">        
        </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">super</span><span style="background-color:#ffffff;">.paintLayer(g2, l);
        
        </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// You can paint after the layer
</span><span style="background-color:#ffffff;">        </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// and your painting will always cover all layer's child component
</span><span style="background-color:#ffffff;">    }
}</span></pre></code></blockquote>

<p/>You can even paint the layer's content more than once! <a href="https://jxlayer.dev.java.net/webstart/FlashButtonDemo.jnlp">
        <img border=0 src="http://java.sun.com/products/jfc/tsc/sightings/images/webstart.small.jpg"></a>
 
<p/>
In this demo when you move the mouse over the button, the animation is started and the layer is painted as is, then the scaling transformation is applied and it is painted once again. <a href="https://jxlayer.dev.java.net/source/browse/jxlayer/trunk/src/demo/org/jdesktop/jxlayer/demo/FlashButtonDemo.java?view=markup">FlashButtonDemo</a> is added to the jxlayer's demo package.

<p/>
See you on the <a href="http://forums.java.net/jive/forum.jspa?forumID=140">JXLayer forum</a>
<br><br>
Thanks<br>
alexp]]>

</content>
</entry>
<entry>
<title>JXLayer 3.0 - LockableUI</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/alexfromsun/archive/2008/07/jxlayer_30_lock.html" />
<modified>2008-07-17T12:30:14Z</modified>
<issued>2008-07-13T14:47:12Z</issued>
<id>tag:weblogs.java.net,2008:/blog/alexfromsun/284.10107</id>
<created>2008-07-13T14:47:12Z</created>
<summary type="text/plain">Enabling/Disabling Swing Containers</summary>
<author>
<name>alexfromsun</name>

<email>Alexander.Potochkin@Sun.COM</email>
</author>
<dc:subject>Swing</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/alexfromsun/">
<![CDATA[<p/>
LockableUI is definitely one of the most challenging feature in the <a href="https://jxlayer.dev.java.net/">JXLayer library</a>. I have already  written about why it was difficult and suggested several solutions and discuss the potential problems.
So it was a long way to make it right and now I am satisfied with the result.
<p/>
In this entry I compiled all up-to-date information about this feature, so forget about the blocking glassPanes, input verifiers, old JXLayer API and let's start.
<p/>
<h2>Overview</h2>
The fact that disabling a Swing container doesn't mean disabling its child components, has always been surprising for Swing beginners
(see this <a href="http://forums.java.net/jive/thread.jspa?threadID=22225&tstart=-1">thread</a>
and <a href="http://forums.java.net/jive/thread.jspa?threadID=13758">this one</a>), it surprises me as well, by the way.

<p/>
Consider the following code:

<blockquote><code><pre style="border: 0px solid darkgray; padding: 4px; color: darkblue;">
<FONT style="font-family:monospaced;" COLOR="#000000">JPanel panel = </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>new</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> JPanel(); 
panel.add(</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>new</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> JButton(</FONT><FONT style="font-family:monospaced;" COLOR="#008000"><B>&quot;Hello&quot;</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000">));       
frame.add(panel); 
         
panel.setEnabled(</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>false</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000">);</FONT></PRE></code></blockquote>

Despite the fact that the panel is disabled, its child button remains perfectly accessible. Actually, Swing doesn't provide a way to "disable" a container with all its child components. Recursive disabling or glassPane tricks have serious restrictions and that was the reason why I started to work on a LockableUI, which provides an elegant and safe way to temporary block a specific Swing container.

<p/>Check it out with the webstart link to the  <a href="https://jxlayer.dev.java.net/source/browse/jxlayer/trunk/src/demo/org/jdesktop/jxlayer/demo/LockableDemo.java?view=markup">LockableDemo</a> from the jxlayer demo package:
<a href="https://jxlayer.dev.java.net/webstart/LockableDemo.jnlp">
        <img border=0
             src="http://java.sun.com/products/jfc/tsc/sightings/images/webstart.small.jpg"></a>

<h2>How to use it</h2>

<p/>As with all core LayerUI's, LockableUI is very easy to use:

<blockquote><code>
<pre style="line-height: 120%;font-family:monospace;background-color:#ffffff; border-width:0mm; border-color:#000000; border-style:solid; padding:4px;"><span style="color:#808080;background-color:#ffffff;font-style:italic;">// the component to be locked
</span><span style="background-color:#ffffff;">JPanel panel = getMyPanel();
        
LockableUI lockableUI = </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> LockableUI();        
</span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// wrap the panel with JXLayer and the lockableUI 
</span><span style="background-color:#ffffff;">JXLayer&lt;JComponent&gt; l = </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> JXLayer&lt;JComponent&gt;(panel, lockableUI);        
</span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// lock the layer
</span><span style="background-color:#ffffff;">lockableUI.setLocked(</span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">true</span><span style="background-color:#ffffff;">);

</span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// add the layer as any other component
</span><span style="background-color:#ffffff;">frame.add(l);
</span></pre></code></blockquote>

<p/>After that, your panel and all its children won't receive focus , mouse or keyboard events and when you move the mouse over it, you'll see the wait mouse cursor(on Windows it is hourglass cursor), and after the

<blockquote><code>
<pre style="line-height: 120%;font-family:monospace;background-color:#ffffff; border-width:0mm; border-color:#000000; border-style:solid; padding:4px;"><span style="color:#808080;background-color:#ffffff;font-style:italic;">// unlock the layer        
</span><span style="background-color:#ffffff;">lockableUI.setLocked(</span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">false</span><span style="background-color:#ffffff;">);        
</span></pre></code></blockquote>

the panel and all its children will work as usual. This is particularly useful when you read a big chunk of data from the network or database for a particular component - you lock it untill the data transfer has completed, leaving the rest of the GUI alive.

<p/> 
This is pretty cool, but to make it better we should use some visual effect for the locked layer, to notify the user that the component is locked. In my jxlayer demos I usually take advantage of standard BufferedImageOp mechanism from the core Java2D library.

<p/>With the BufferedImageOps you can have various effects like blurring, color conversion etc... For examplle, the following code snippet makes the locked layer black-and-white:

<blockquote><code>
<pre style="line-height: 120%;font-family:monospace;background-color:#ffffff; border-width:0mm; border-color:#000000; border-style:solid; padding:4px;"><span style="background-color:#ffffff;">LockableUI ui = </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> LockableUI();
JXLayer&lt;JComponent&gt; l = </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> JXLayer&lt;JComponent&gt;(</span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> JButton(</span><span style="color:#008000;background-color:#ffffff;font-weight:bold;">"Hello"</span><span style="background-color:#ffffff;">), ui);

</span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// Java2D grayScale BufferedImageOp
</span><span style="background-color:#ffffff;">ColorConvertOp grayScale =
        </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> ColorConvertOp(ColorSpace.</span><span style="background-color:#ffffff;font-style:italic;">getInstance(</span><span style="background-color:#ffffff;">ColorSpace.</span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;font-style:italic;">CS_GRAY)</span><span style="background-color:#ffffff;">, </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">null</span><span style="background-color:#ffffff;">);
</span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// wrap it with the jxlayer's BufferedImageOpEffect 
</span><span style="background-color:#ffffff;">BufferedImageOpEffect effect = </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> BufferedImageOpEffect(grayScale);
</span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// set it as the locked effect        
</span><span style="background-color:#ffffff;">ui.setLockedEffects(effect);
        
ui.setLocked(</span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">true</span><span style="background-color:#ffffff;">);
frame.add(l);
</span></pre></code></blockquote>


<h2>LockableDemo</h2>

In the LockableDemo I use the beautiful <a href="http://www.jhlabs.com/ip/filters/index.html">set of image 
effects</a> from Jerry Huxtable, here is his BlurFilter and plain LockableUI in action:

<p/>
<blockquote>
<img src="https://swinghelper.dev.java.net/bin/blog/locking/blur.PNG" alt="demo screenshot"></img></blockquote>

<p/>
You can also customize the LockableUI and put the unlock button directly to the layer's glassPane, see the EnhancedLockableUI implementation from the <a href="https://jxlayer.dev.java.net/source/browse/jxlayer/trunk/src/demo/org/jdesktop/jxlayer/demo/LockableDemo.java?view=markup">LockableDemo</a>,
also note the EmbossFilter from Jerry:

<p/>
<blockquote>
<img src="https://swinghelper.dev.java.net/bin/blog/locking/emboss.PNG" alt="demo screenshot"></img></blockquote>

<p/>The last LockableUI's subclass shows how JXLayer and SwingX painters work together. The BusyPainterUI from the <a href="https://jxlayer.dev.java.net/source/browse/jxlayer/trunk/src/demo/org/jdesktop/jxlayer/demo/LockableDemo.java?view=markup">LockableDemo</a>
uses BusyPainter from SwingX librarary and animates it to provide a nice busy effect for the locked layer:

<p/>
<blockquote>
<img src="https://swinghelper.dev.java.net/bin/blog/locking/busy.PNG" alt="demo screenshot"></img></blockquote>

<h2>Implementation</h2>

As all other core LayerUI's, the <a href="https://jxlayer.dev.java.net/source/browse/jxlayer/trunk/src/java/org/jdesktop/jxlayer/plaf/ext/LockableUI.java?view=markup">LockableUI</a> 
neither use frame's glassPane or layeredPane, nor any other global settings like custom RepaintManager or EventQueue, it doesn't use JComponenent.print() methods, which was a problem for the old versions of this feature. All input events, including the keyboard actions, are effectively blocked for the layer's children when it is locked.<br/>

<p/>
<p/>All information about the JXLayer library you can find on <a href="https://jxlayer.dev.java.net/">jxlayer.dev.java.net</a>

<p/>
See you on the <a href="http://forums.java.net/jive/forum.jspa?forumID=140">JXLayer forum</a>
<br><br>
Thanks<br>
alexp]]>

</content>
</entry>
<entry>
<title>JXLayer 3.0 - MouseScrollableUI</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/alexfromsun/archive/2008/06/jxlayer_30_mous.html" />
<modified>2008-06-24T20:50:44Z</modified>
<issued>2008-06-24T18:39:57Z</issued>
<id>tag:weblogs.java.net,2008:/blog/alexfromsun/284.10006</id>
<created>2008-06-24T18:39:57Z</created>
<summary type="text/plain">Implementing the auto-scrolling feature with JXLayer</summary>
<author>
<name>alexfromsun</name>

<email>Alexander.Potochkin@Sun.COM</email>
</author>
<dc:subject>Swing</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/alexfromsun/">
<![CDATA[The mouse auto-scrolling is very popular these days for modern applications. I usually use this feature in the Firefox browser - you click the mouse wheel somewhere on the page and can immediately start scrolling.
<p/>
A few months ago Kirill wrote an <a href="http://www.pushing-pixels.org/?p=280">great review</a> of the "auto-scrolling feature" implementation in Swing. I'd like to add one more item to the list.
<p/>
Suppose you create a JTable, wrap it with JScrollPane and add it to a frame:

<blockquote>
<pre style="line-height: 120%;font-family:monospace;background-color:#ffffff"><span style="background-color:#ffffff;">JScrollPane sp = JScrollPane(createMyTable());
add(sp);             
</span></pre></blockquote>

<p/>
To enable auto-scrolling you just need to wrap a JScrollPane with <a href="https://jxlayer.dev.java.net/">JXLayer</a> and set the MouseScrollableUI to it:

<blockquote>
<pre style="line-height: 120%;font-family:monospace;background-color:#ffffff"><span style="background-color:#ffffff;">JScrollPane sp = JScrollPane(createMyTable());
JXLayer&lt;JScrollPane&gt; l = </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> JXLayer&lt;JScrollPane&gt;(sp, </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> MouseScrollableUI());        
add(l);             
</span>
</pre>
</blockquote>

<p/>After that you can you can activate auto-scrolling by clicking the mouse wheel:

<a href="https://jxlayer.dev.java.net/webstart/MouseScrollableDemo.jnlp">
        <img border=0
             src="http://java.sun.com/products/jfc/tsc/sightings/images/webstart.small.jpg"></a>



<p/>
<img src="https://swinghelper.dev.java.net/bin/blog/scrolling/srollable.PNG" alt="demo screenshot"></img>

<p/>
When the scrolling indicator appears, your can scroll by moving your mouse towards the desirable direction. Auto-scrolling is deactivated by clicking any keyboard or mouse button.

<h2>Implementation</h2>

Things like MouseScrollableUI are very easily implemented with JXLayer,
because it provides a way to catch all mouseEvents for all components inside a JXLayer. 

<blockquote>
<pre style="line-height: 130%;font-family:monospace;background-color:#ffffff"><span style="color:#000080;background-color:#ffffff;font-weight:bold;">class</span><span style="background-color:#ffffff;"> MyLayerUI </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">extends</span><span style="background-color:#ffffff;"> AbstractLayerUI&lt;JComponent&gt; {
    
    </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// This method catches all focus, mouse and keyboard events
</span><span style="background-color:#ffffff;">    </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// for the layer and all its subcomponents
</span><span style="background-color:#ffffff;">    </span><span style="color:#808000;background-color:#ffffff;">@Override
    </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">public</span><span style="background-color:#ffffff;"> </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">void</span><span style="background-color:#ffffff;"> eventDispatched(AWTEvent e, JXLayer&lt;JComponent&gt; l) {
        </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">super</span><span style="background-color:#ffffff;">.eventDispatched(e, l);
        System.</span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;font-style:italic;">out.</span><span style="background-color:#ffffff;">println(</span><span style="color:#008000;background-color:#ffffff;font-weight:bold;">"AWTEvent is dispatched: "</span><span style="background-color:#ffffff;"> + e);
    }

    </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// Utility methods which are called from eventDispatched()
</span><span style="background-color:#ffffff;">    </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// to provide a hook for catching particular type of events
</span><span style="background-color:#ffffff;">    </span><span style="color:#808000;background-color:#ffffff;">@Override
    </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">protected</span><span style="background-color:#ffffff;"> </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">void</span><span style="background-color:#ffffff;"> processMouseEvent(MouseEvent e, JXLayer&lt;JComponent&gt; l) {
        System.</span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;font-style:italic;">out.</span><span style="background-color:#ffffff;">println(</span><span style="color:#008000;background-color:#ffffff;font-weight:bold;">"MouseEvent on component: "</span><span style="background-color:#ffffff;"> + e.getComponent());
    }
    
    </span><span style="color:#808000;background-color:#ffffff;">@Override
    </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">protected</span><span style="background-color:#ffffff;"> </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">void</span><span style="background-color:#ffffff;"> processMouseMotionEvent(MouseEvent e, JXLayer&lt;JComponent&gt; l) {
        System.</span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;font-style:italic;">out.</span><span style="background-color:#ffffff;">println(</span><span style="color:#008000;background-color:#ffffff;font-weight:bold;">"MouseMotionEvent on component: "</span><span style="background-color:#ffffff;"> + e.getComponent());
    }    
}
</span></pre></blockquote>

<p/>
Once you have a way to catch all mouseEvents for all subcomponents, everything else is straightforward. The only specific details is the scrolling indicator, initially I thought to paint it, as usual, in the paintLayer() method. 
<p/>
However I realized that I want to change the mouse cursor when I move the mouse over scrolling indicator and the best solution is to implement it as a custom component, set a resize mouse cursor and place it at the layer's glassPane.
<p/>
The source code of the <a href="https://jxlayer.dev.java.net/source/browse/jxlayer/trunk/src/java/org/jdesktop/jxlayer/plaf/ext/MouseScrollableUI.java?view=markup">MouseScrollableUI</a> is quite compact, the <a href="https://jxlayer.dev.java.net/source/browse/jxlayer/trunk/src/demo/org/jdesktop/jxlayer/demo/MouseScrollableDemo.java?view=markup">MouseScrollableDemo</a>
for the webstart demo is even shorter.<br/>
(the runnable link is above the screenshot)
<p/>
See you on the <a href="http://forums.java.net/jive/forum.jspa?forumID=140">JXLayer forum</a>
<br><br>
Thanks<br>
alexp]]>

</content>
</entry>
<entry>
<title>JXLayer 3.0 - Getting started</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/alexfromsun/archive/2008/06/the_new_jxlayer.html" />
<modified>2008-06-05T18:24:55Z</modified>
<issued>2008-06-05T17:49:46Z</issued>
<id>tag:weblogs.java.net,2008:/blog/alexfromsun/284.9576</id>
<created>2008-06-05T17:49:46Z</created>
<summary type="text/plain">The major update of the JXLayer, the universal decorator for Swing components.</summary>
<author>
<name>alexfromsun</name>

<email>Alexander.Potochkin@Sun.COM</email>
</author>
<dc:subject>Swing</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/alexfromsun/">
<![CDATA[<p/>
It is my pleasure to announce a major update of JXLayer component.
The new version is hosted on its own java.net project <a href="https://jxlayer.dev.java.net/">jxlayer.dev.java.net</a>, where I will also provide links to all my blogs about this component.
<p/>So, why I encourage everybody to try out the new JXLayer?<br/>
Actually to answer this question I am going to write several more blogs, here is a short answer:

<ol>
<li>more consistent and efficient API</li>
<li>easier to use</li>
<li>new functionality</li>
</ol>
<p/>

The JXLayer 3.0 API is a bit different from the previous version and I had good reasons to make it this way. The good news is that I am very happy with the current API and I am not gonna introduce incompatible changes in the future. So, if you are using the previous JXLayer, it won't take much time to adjust your code for the new one, if you haven't tried it yet, it's high time to have a look.
<p/> 
JXLayer is the universal decorator for Swing components, it means that you have a flexible way to enrich the visual appearance of your components and control the input events for the whole component's hierarchy.
<p/>
Just wrap your component with JXLayer and set a LayerUI which implements the required functionality. 
On <a href="https://jxlayer.dev.java.net">jxlayer.dev.java.net</a> you'll find demos of several carefully tested and ready to use LayerUI's implementations. In this entry we are going to see how to create your own ones.
<p/>
Here is a simple example how to create and use LayerUI which paints translucent foreground over the layer:

<pre style="width:800px;background-color:#ffffff; border-width:0px; border-color:#000000; padding:4px;"><span style="background-color:#ffffff">        </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// wrap your component
</span><span style="background-color:#ffffff;">        JXLayer&lt;JComponent&gt; layer = </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> JXLayer&lt;JComponent&gt;(myComponent);

        </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// create custom LayerUI
</span><span style="background-color:#ffffff;">        AbstractLayerUI&lt;JComponent&gt; layerUI = </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> AbstractLayerUI&lt;JComponent&gt;() {

            </span><span style="color:#808000;background-color:#ffffff;">@Override  
            </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">protected</span><span style="background-color:#ffffff;"> </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">void</span><span style="background-color:#ffffff;"> paintLayer(Graphics2D g2, JXLayer&lt;JComponent&gt; l) {
                </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// this paints layer as is
</span><span style="background-color:#ffffff;">                </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">super</span><span style="background-color:#ffffff;">.paintLayer(g2, l);
                </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// custom painting:
</span><span style="background-color:#ffffff;">                </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// here we paint translucent foreground
</span><span style="background-color:#ffffff;">                </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// over the whole layer
</span><span style="background-color:#ffffff;">                g2.setColor(</span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> Color(</span><span style="color:#0000ff;background-color:#ffffff;">0</span><span style="background-color:#ffffff;">, </span><span style="color:#0000ff;background-color:#ffffff;">128</span><span style="background-color:#ffffff;">, </span><span style="color:#0000ff;background-color:#ffffff;">0</span><span style="background-color:#ffffff;">, </span><span style="color:#0000ff;background-color:#ffffff;">128</span><span style="background-color:#ffffff;">));
                g2.fillRect(</span><span style="color:#0000ff;background-color:#ffffff;">0</span><span style="background-color:#ffffff;">, </span><span style="color:#0000ff;background-color:#ffffff;">0</span><span style="background-color:#ffffff;">, l.getWidth(), l.getHeight());
            }
        };

        </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// set our LayerUI
</span><span style="background-color:#ffffff;">        layer.setUI(layerUI);

        </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// add the layer as a usual component
</span><span style="background-color:#ffffff;">        frame.add(layer);
</span></pre>

<p/>
BufferedLayerUI provides more functionality, 
since it paints the layer to the double buffer image, it allows filtering the image with the <a href="http://java.sun.com/javase/6/docs/api/java/awt/image/BufferedImageOp.html">BufferedImageOp</a> subclasses. With it you can invert colors of a layer, blur it apply any other fancy effects. 
<p/>
For the <a href="https://rainbow.dev.java.net/">Rainbow</a> project I used BufferedLayerUI to implement the image editor dialog.
<br/>(Here are some more <a href="http://www.pushing-pixels.org/?p=153">Rainbow screenshots</a>)
<p/>
Let's see how to apply the grayScale effect to a layer:

<pre style="width:1000px;line-height: 120%;font-family:monospace;background-color:#ffffff; border-width:0px; border-color:#000000; border-style:solid; padding:4px;"><span style="background-color:#ffffff;">        </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// wrap you component
</span><span style="background-color:#ffffff;">        JXLayer&lt;JComponent&gt; layer = </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> JXLayer&lt;JComponent&gt;(myComponent);

        </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// here we use BufferedLayerUI which can work with BufferedImageOps  
</span><span style="background-color:#ffffff;">        BufferedLayerUI&lt;JComponent&gt; bufferedLayerUI = </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> BufferedLayerUI&lt;JComponent&gt;();
        
        </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// create a ColorConvertOp to apply grayScale effect
</span><span style="background-color:#ffffff;">        BufferedImageOp grayScaleOp = 
                </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> ColorConvertOp(ColorSpace.</span><span style="background-color:#ffffff;font-style:italic;">getInstance(</span><span style="background-color:#ffffff;">ColorSpace.</span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;font-style:italic;">CS_GRAY)</span><span style="background-color:#ffffff;">, </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">null</span><span style="background-color:#ffffff;">);

        </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// create a BufferedImageOpEffect with the provided BufferedImageOp 
</span><span style="background-color:#ffffff;">        BufferedImageOpEffect imageOpEffect = </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> BufferedImageOpEffect(grayScaleOp);
        
        </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// set BufferedImageOpEffect to the bufferedLayerUI
</span><span style="background-color:#ffffff;">        bufferedLayerUI.setLayerEffects(imageOpEffect);
        
        </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// set the bufferedLayerUI to the layer 
</span><span style="background-color:#ffffff;">        layer.setUI(bufferedLayerUI);

        </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// add the layer as a usual component
</span><span style="background-color:#ffffff;">        frame.add(layer);
</span></pre>

<p/>
And now is the very important news: with JXLayer 3.0 you can catch layer's input events as easy as implement a custom painting. AbstractLayerUI introduces several methods: processFocusEvent, processMouseEvent, processMouseMotionEvent, etc...<br>
The names of the methods speak for themselves. If you'd like to catch all mouseEvents for all components inside your layer - just override processMouseEvent in your custom AbstractLayerUI subclass.

<p/>
<a href="https://jxlayer.dev.java.net/source/browse/jxlayer/trunk/src/demo/org/jdesktop/jxlayer/demo/MouseDrawingDemo.java?view=markup">MouseDrawingDemo</a> combines painting and mouse events processing together.
<p/>
        <a href="https://jxlayer.dev.java.net/webstart/MouseDrawingDemo.jnlp">
            <img border=0
                 src="http://java.sun.com/products/jfc/tsc/sightings/images/webstart.small.jpg"></a>
<p/>
In this demo you can paint over the layer with your mouse, just like you do in any other image editor. <br>
Note that components are alive when you paint over them.
<p/>
<img src="https://swinghelper.dev.java.net/bin/blog/layer1/screenshot.PNG"/>
<p/>
I hope this short overview will help you to invent your own ways of using JXLayer in your projects.<br>
See you one the <a href="http://forums.java.net/jive/forum.jspa?forumID=140">JXLayer forum</a>
<p/>
With best wishes<br/>
alexp]]>

</content>
</entry>
<entry>
<title>RepaintManager&apos;s side effect</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/alexfromsun/archive/2008/04/custom_repaintm.html" />
<modified>2008-04-14T15:00:51Z</modified>
<issued>2008-04-13T15:49:03Z</issued>
<id>tag:weblogs.java.net,2008:/blog/alexfromsun/284.9523</id>
<created>2008-04-13T15:49:03Z</created>
<summary type="text/plain">A little-known side effect of setting a custom RepaintManager or using RepaintManager.setDoubleBufferingEnabled() method</summary>
<author>
<name>alexfromsun</name>

<email>Alexander.Potochkin@Sun.COM</email>
</author>
<dc:subject>Swing</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/alexfromsun/">
<![CDATA[When I worked on the lightweight disabling of compound Swing components for my JXLayer project, I tried different approaches to workaround the problems with the custom painting of double-buffered components.
<p/>
The last try was using the <a href="http://java.sun.com/javase/6/docs/api/javax/swing/JComponent.html#print(java.awt.Graphics)">JComponent.print()</a> method instead of <a href="http://java.sun.com/javase/6/docs/api/javax/swing/JComponent.html#paint(java.awt.Graphics)">JComponent.paint()</a>, which effectively disables the double-buffering for the whole hierarchy of components. While it seems to be a good solution, it has a flaw: print methods may be overridden to provide a specific painting logic when a component is printed rather than painting on the screen.
<br/>(Thanks to David Browne and Kirill Grouchnikov for this information)
<p/> 
Finally I found a correct way of disabling swing containers without recursive disabling of double buffering for the subcomponents or using print() method. I'll describe it in my next blogs 
<br/>(Some great news are coming)
<p/>
Anyway, you may be surprised why I spent my time on that tricks when there is a much cleaner solution for disabling double buffering in Swing. I am talking about <a href="http://java.sun.com/javase/6/docs/api/javax/swing/RepaintManager.html#setDoubleBufferingEnabled(boolean)">RepaintManager.setDoubleBufferingEnabled(boolean)</a> method. At the beginning of painting you can switch the double buffering off and switch it on again at the end. Despite the fact that it changes the global setting for the whole Swing, no one will get hurt because Swing is a single-threaded library. It makes sense, doesn't it?
<p/>I must admit that I don't use RepaintManager in my java.net projects because I am aware of one side effect it causes. 
<p/>
Do you remember the famous<a href="http://weblogs.java.net/blog/zixle/archive/2005/04/no_more_gray_re_1.html"> GrayRect fix</a> for JDK 6?

<p/>The main feature of this fix is the true per-window double buffer implementation, which eliminates unnecessary painting when a window of your java application is brought to the front after it was overlapped by another window. With JDK 5 you often see a gray rectangle when the damaged area is repainted, with JDK 6 the buffered image of the window's content is immediately copied to the screen so can't notice any traces of that.
<p/>
RepaintManager.currentManager(null).<b>setDoubleBufferingEnabled(false)</b> disables the all Swing double buffering. Unfortunately, it is a one-way street for the gray rect fix, calling <b>setDoubleBufferingEnabled(true)</b> after that, enables Swing double buffering, but the gray rect fix is to be disabled forever.
<p/>
The system RepaintManager is created by a private constructor with a special flag which enables the true double buffering. 
Once you set your own implementation of RepaintManager, the gray rect fix is gone, because there is no public API to enable true double buffering for RepaintManager subclasses. 
<p/>
So there is the same problem when you install a custom implementation of the RepaintManager.
<p/>
This demo demonstrates the effect (JDK 6 is required):
<a href="https://swinghelper.dev.java.net/bin/blog/rm/RunDemo.jnlp">
    <img border=0 src="http://java.sun.com/products/jfc/tsc/sightings/images/webstart.small.jpg"></a>



<p/>
Each time the <b>JFrame.paint()</b> is called, the new line is added to the JTextArea. When the demo window is shown, the frame is painted once.
Check out the gray rect fix by moving another window on top of the demo's frame, you'll see that <b>JFrame.paint()</b> is not get called, because Swing uses the per-window buffer instead. This can also be checked without another application, just move the demo's frame partly outside the window back and forth, it will not trigger frame's repainting as well.
<p/>
With the Options menu you can set a new RepaintManager or switch the double buffering off and on again, any of these action will disable the gray rect fix. Choose one of the actions and move the other window on top of the demo again, you'll see that the frame starts to repaint itself and the true double buffering is gone.
<p/>
The source code for this demo is <a href="https://swinghelper.dev.java.net/bin/blog/rm/RepaintManagerTest.java">available</a>.

<p/>That's all for today,<br/>
take care and see you soon<br/><br/>
alexp
 ]]>

</content>
</entry>
<entry>
<title>JTrayIcon update</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/alexfromsun/archive/2008/02/jtrayicon_updat.html" />
<modified>2008-02-14T19:27:21Z</modified>
<issued>2008-02-14T19:12:47Z</issued>
<id>tag:weblogs.java.net,2008:/blog/alexfromsun/284.9194</id>
<created>2008-02-14T19:12:47Z</created>
<summary type="text/plain">TrayIcon and JPopupMenu - will they ever be friend?</summary>
<author>
<name>alexfromsun</name>

<email>Alexander.Potochkin@Sun.COM</email>
</author>
<dc:subject>Swing</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/alexfromsun/">
<![CDATA[<p>JDK 6 introduced plenty of cool desktop features, like famous <a href="http://weblogs.java.net/blog/zixle/archive/2005/04/no_more_gray_re_1.html">gray-rect fix</a> or <a href="http://weblogs.java.net/blog/shan_man/archive/2006/01/first_class_dra.html">advanced drag and drop support</a>, 
<br>all of them made java much closer to the desktop application market and I am very exited about them.
<p>There have been many blogs how useful new features are, 
and I don't want to repeat them. Among all successful and well-designed features there is one which actually has not been completed,
<br>I am speaking about JTrayIcon.
<p>Swing and AWT team work together (by the way, AWT team seats in 10 steps from my room), AWT is responsible for the "native" parts of the code, like topLevel frames, event processing etc, 
<br>when Swing team if focused on their lightWeight components. Actually it is AWT who isolates Swing from any native code and makes Swing cross-platform.
<p>It wasn't a surprise that TrayIcon feature came to AWT team, and they implemented it perfectly - it works well and it is supported for various Windows, Linux and Solaris systems. 
<br>They made it customizable by providing mouse event handling support and a special method <a href="http://java.sun.com/javase/6/docs/api/java/awt/TrayIcon.html#setPopupMenu(java.awt.PopupMenu)">setPopupMenu()</a>  which takes <a href="http://java.sun.com/javase/6/docs/api/java/awt/PopupMenu.html">java.awt.Popup</a> (which is quite old-fashioned but remember it was the AWT feature)
<p><a href="http://java.sun.com/javase/6/docs/api/javax/swing/JPopupMenu.html">JPopupMenu</a> doesn't extend <a href="http://java.sun.com/javase/6/docs/api/java/awt/PopupMenu.html">awt.Popup</a>  but it looked like it would be easy to attach JPopupMenu to the trayIcon with help of MouseListener, but it was not the case.
<p>The fact is that there is no way (or at least easy one) to correctly attach JPopupMenu to a TrayIcon. 
<br>It means that you can't set an icon for a TrayIcon's menuItem or make it look according to the current Look and Feel and, from my point of view, it makes TrayIcon much less useful than it could be.
<p>It is our fault, sorry about that. Now let's see how we can solve this problem.

<p>To make JTrayIcon possible I fixed three particular bugs for the next JDK 6 update release (the famous update #10, aka 6uN) and for the JDK 7 beta

<p>
<a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6583251">ClassCastException in Swing with TrayIcon</a>
<blockquote>If JPopupMenu is shown from a trayIcon's mouseListener an ugly ClassCastException was thrown in some cases.</blockquote>
<p>
<a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6217905">Keyboard navigation problems and highlighting of the first item</a>
<blockquote>
If popup menu lost focus it stopped processing keyboard events in some cases, the first item a popup was <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4740942">highlighed by default</a>
which is very different from any other GUI I've seen
</blockquote>
<p>
<a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6580930">Swing Popups should overlap taskbar</a>
<blockquote>
Finally it was impossible to implement a good looking trayicon's popup menu, because Swing popups couldn't overlap taskbar
</blockquote>
<p>
Having integrated all three fixes I managed to write the <a href="https://swinghelper.dev.java.net/source/browse/swinghelper/src/java/org/jdesktop/swinghelper/tray/JXTrayIcon.java?view=markup">JXTrayIcon class</a>
which extends java.awt.TrayIcon and contains
setJPopuMenu(<a href="http://java.sun.com/javase/6/docs/api/javax/swing/JPopupMenu.html">JPopupMenu</a>) method
<p>Here is how JXTrayIcon looks when you click on it, with the current JDK 6
<blockquote><img src="https://swinghelper.dev.java.net/bin/blog/tray/old.PNG" alt="JXTrayIcon with the current JDK 6"/></blockquote>

<p>the same code is run under JDK 6 update 10 or JDK 7
<blockquote><img src="https://swinghelper.dev.java.net/bin/blog/tray/new.PNG" alt="JXTrayIcon with JDK 6u10 or JDK 7"/></blockquote>
<p>The red quarter circle icon is owned by the JXTrayIcon's test. <br>Note that the first item is not highlighted by default when the popup menu is shown, 
<br>if you move the mouse over it or press the arrow button on your keyboard, the proper item will be highlighted as with a system popup menu.
<p>I encourage you to download the <a href="http://download.java.net/jdk6/">JDK 6u10 early bits</a> and try out the <a href="https://swinghelper.dev.java.net/source/browse/swinghelper/src/java/org/jdesktop/swinghelper/tray/JXTrayIcon.java?view=markup">JXTrayIcon demo</a>
<br>The <a href="https://swinghelper.dev.java.net/bin/tray/tray.jar">runnable jar file</a> is also available for your convenience
<p>I particularly interested how it works in different environments,
<br>any comments and suggestions are welcome as usual
<p>Thank you and sorry this took so long.I hope it was worth the wait.
<p>alexp]]>

</content>
</entry>
<entry>
<title>Making Rainbow: Spotlight effect and soft clipping</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/alexfromsun/archive/2007/11/making_raibow_s.html" />
<modified>2008-06-24T19:17:03Z</modified>
<issued>2007-11-29T19:32:21Z</issued>
<id>tag:weblogs.java.net,2007:/blog/alexfromsun/284.8695</id>
<created>2007-11-29T19:32:21Z</created>
<summary type="text/plain">Detailed tutorial on implementing advanced effect for the our J1 session&apos;s demo</summary>
<author>
<name>alexfromsun</name>

<email>Alexander.Potochkin@Sun.COM</email>
</author>
<dc:subject>Swing</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/alexfromsun/">
<![CDATA[<p>Few weeks ago I submitted a session for the next JavaOne and it reminded me the <a href="https://rainbow.dev.java.net/media/JavaOne2007Rainbow.pdf">previous session</a> which we presented with <a href="http://www.pushing-pixels.org/">Kirill</a>
<p>Before J1, he published a <a href="http://weblogs.java.net/blog/kirillcool/archive/2007/04/bringing_life_t.html">nice teaser</a> with links to blogs about his famous ghost effects and transition layout, so it's hight time for me drop a few lines about implementing a spotLight effect. You can test the whole application on the <a href="https://rainbow.dev.java.net/">main page</a> of the Rainbow project, here is a flash demo which I made specially for this  blog (press the green button on the bottom left side)

<p>
<center>
<OBJECT CLASSID="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" WIDTH="718" HEIGHT="465" CODEBASE="http://active.macromedia.com/flash5/cabs/swflash.cab#version=5,0,0,0">
<PARAM NAME=movie VALUE="https://swinghelper.dev.java.net/bin/blog/rainbow/rainbow.swf">
<PARAM NAME=play VALUE=true>
<PARAM NAME=loop VALUE=false>
<PARAM NAME=quality VALUE=low>
<EMBED SRC="https://swinghelper.dev.java.net/bin/blog/rainbow/rainbow.swf" WIDTH=718 HEIGHT=465 quality=low loop=false TYPE="application/x-shockwave-flash" PLUGINSPAGE="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash">
</EMBED>
</OBJECT>
</center>
<p>

<p><br>
The shortest version of the SpotLightPainter was about 30 lines of code. I slightly modified the original painter from the Rainbow project and included the <a href="https://swinghelper.dev.java.net/source/browse/swinghelper/src/demo/org/jdesktop/swinghelper/layer/demo/SpotLightPainter.java?view=markup">SpotLightPainter</a>  and the <a href="https://swinghelper.dev.java.net/source/browse/swinghelper/src/demo/org/jdesktop/swinghelper/layer/demo/SpotLightDemo.java?view=markup">SpotLightDemo</a> to the demo direcotry for JXLayer.<br>
The painter's code is quite straightforward, there are just two things I'd like to comment:

<h2>ForegroundPainter</h2>
SpotlightPainter has a layered structure: the scrollPane's view component and the tranclucent foreground with the "holes" for matched components. I divide the painting code between two painters - SpotLightPainter extends DefaultPainter, so the wrapped component is automatically painted when you call <i>super.paint(g2, l)</i>, the foregroundPainter is responsible for painting the tranclucent foreground:

<blockquote><code>
<pre style="line-height: 100%;font-family:monospace;background-color:#ffffff; border-width:0pt; border-color:#000000; border-style:solid; padding:4px;"><span style="background-color:#ffffff;">    </span><span style="color:#808000;background-color:#ffffff;">@Override
    </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">public</span><span style="background-color:#ffffff;"> </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">void</span><span style="background-color:#ffffff;"> paint(Graphics2D g2, JXLayer&lt;V&gt; l) {
        </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">super</span><span style="background-color:#ffffff;">.paint(g2, l);
        </span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;">foregroundPainter.</span><span style="background-color:#ffffff;">paint(g2, l);
    }
</span>
</pre></code></blockquote>

<p>The foregroundPainter extends AbstractBufferedPainter which means it is painted via the intermediate image, this is the best solution when it comes to translucency. I fill the whole area with the translucent color and then clip out the shapes over the matched
components:

<blockquote><code>
<pre style="line-height: 100%;font-family:monospace;background-color:#ffffff; border-width:0pt; border-color:#000000; border-style:solid; padding:4px;"><span style="background-color:#ffffff;">        </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">this</span><span style="background-color:#ffffff;">.</span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;">foregroundPainter </span><span style="background-color:#ffffff;">= </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> AbstractBufferedPainter&lt;V&gt;() {
            </span><span style="color:#808000;background-color:#ffffff;">@Override
            </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">protected</span><span style="background-color:#ffffff;"> </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">void</span><span style="background-color:#ffffff;"> paintToBuffer(Graphics2D g2, JXLayer&lt;V&gt; l) {
                
                </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// cleaning up
</span><span style="background-color:#ffffff;">                g2.setComposite(AlphaComposite.</span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;font-style:italic;">Clear)</span><span style="background-color:#ffffff;">;
                g2.fillRect(</span><span style="color:#0000ff;background-color:#ffffff;">0</span><span style="background-color:#ffffff;">, </span><span style="color:#0000ff;background-color:#ffffff;">0</span><span style="background-color:#ffffff;">, l.getWidth(), l.getHeight());
                
                </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// filling with overlayColor
</span><span style="background-color:#ffffff;">                g2.setComposite(AlphaComposite.</span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;font-style:italic;">SrcOver)</span><span style="background-color:#ffffff;">;
                g2.setColor(overlayColor);
                g2.fillRect(</span><span style="color:#0000ff;background-color:#ffffff;">0</span><span style="background-color:#ffffff;">, </span><span style="color:#0000ff;background-color:#ffffff;">0</span><span style="background-color:#ffffff;">, l.getWidth(), l.getHeight());
                
                </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// clipping out the "holes" for matched components
</span><span style="background-color:#ffffff;">                </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">for</span><span style="background-color:#ffffff;"> (Shape shape : </span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;">clipList)</span><span style="background-color:#ffffff;"> {
                    g2.setClip(shape);
                    g2.setComposite(AlphaComposite.</span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;font-style:italic;">Clear)</span><span style="background-color:#ffffff;">;
                    g2.fill(shape);
                    softClipping(g2, shape);
                }
            }
        };
</span>
</pre></code></blockquote>

The important thing that by default, <i>AbstractBufferedPainter.isIncrementalUpdate()</i> returns false, it means that this painter will be updated only if the whole JXLayer is repainted, e.g. when the frame is resized or when <i>SpotLightPainter.fireLayerItemChanged()</i> is called. This optimization allows reusing the foreground image for faster painting, it doesn't slow down the transition effect animation because when you move the mouse over a button, foregroundPainter paints the cached image.

<h2>Soft clipping</h2>
When we prepared our session, Kirill drew my attention to the fact that spotlights didn't look smooth, here the zoomed out screenshot which shows how it looked like:<br>

<div style="text-align: center;">
<img src="https://swinghelper.dev.java.net/bin/blog/rainbow/hardclip.PNG" alt="Initial clipping"</img></div>
<p>
as the result it was possible to see the jaggies on the spotlight's borders and that made this effect look unprofessional. The remedy for this problem is called "soft clipping" and the <a href="http://weblogs.java.net/blog/campbell/archive/2006/07/java_2d_tricker.html">pefect article</a> by Chris Cambell is the first thing that came to my mind when I thought about that.
<p>The trick from Chris produces the very good result but it works for fixed shapes only, I mean you should know the exact shape in advance to create a mask for it. I decided to find a way how to make soft clipping for arbitrary shapes and I actually found it, but...
a few minutes ago I came across the next Chris's blog <a href="http://weblogs.java.net/blog/campbell/archive/2006/07/java_2d_tricker_2.html"> Light and Shadow</a> (I missed it for some reason) where he described exactly what I thought was invented by me! :-)<br>
In the comments for that blog there are a few more reports from people who came to this solution even earlier.<br>
<p>The idea is to mix in the alpha value to the pixels on the shape's border by drawing the same shape with a set <a href="http://java.sun.com/javase/6/docs/api/java/awt/BasicStroke.html">BasicStroke</a>. For the Rainbow project I painted it once with the 50% alpha and doubled basicStroke width.<br>

<div style="text-align: center;">
<img src="https://swinghelper.dev.java.net/bin/blog/rainbow/softclip.PNG" alt="Initial clipping"</img></div>

<p>For the JXLayer's demo I updated SpotLightPainter to be able to set the custom width for the soft clipping, and make it as smooth as you want:<p>

<blockquote><code>
<pre style="line-height: 100%;font-family:monospace;background-color:#ffffff; border-width:0pt; border-color:#000000; border-style:solid; padding:4px;"><span style="background-color:#ffffff;">    </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">private</span><span style="background-color:#ffffff;"> </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">void</span><span style="background-color:#ffffff;"> softClipping(Graphics2D g2, Shape shape) {
        g2.setComposite(AlphaComposite.</span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;font-style:italic;">Src)</span><span style="background-color:#ffffff;">;
        </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">for</span><span style="background-color:#ffffff;"> (</span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">int</span><span style="background-color:#ffffff;"> i = </span><span style="color:#0000ff;background-color:#ffffff;">0</span><span style="background-color:#ffffff;">; i &lt; </span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;">softClipWidth;</span><span style="background-color:#ffffff;"> i++) {
            </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">int</span><span style="background-color:#ffffff;"> alpha = (i + </span><span style="color:#0000ff;background-color:#ffffff;">1</span><span style="background-color:#ffffff;">) * </span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;">overlayColor.</span><span style="background-color:#ffffff;">getAlpha()
                    / (</span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;">softClipWidth </span><span style="background-color:#ffffff;">+ </span><span style="color:#0000ff;background-color:#ffffff;">1</span><span style="background-color:#ffffff;">);
            Color temp = </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> Color(
                    </span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;">overlayColor.</span><span style="background-color:#ffffff;">getRed(),
                    </span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;">overlayColor.</span><span style="background-color:#ffffff;">getGreen(), 
                    </span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;">overlayColor.</span><span style="background-color:#ffffff;">getBlue(), alpha);
            g2.setColor(temp);
            g2.setStroke(</span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> BasicStroke(</span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;">softClipWidth </span><span style="background-color:#ffffff;">- i));
            g2.draw(shape);
        }
    }

</span></pre>
</code></blockquote>

<p/>
<div style="text-align: center;">
<a href="https://swinghelper.dev.java.net/bin/layer/SpotLightDemo.jnlp">
    <img border=0 src="http://java.sun.com/products/jfc/tsc/sightings/images/webstart.small.jpg"></a>
</div> 



<p/>
<div style="text-align: center;">
<img src="https://swinghelper.dev.java.net/bin/blog/rainbow/spotlight.PNG" alt="Spotlight demo"</img></div>


<h2>MouseEvents filtering</h2>
Components which are outside the spotlights shouldn't react on the mouse events and this was the simplest task for the SpotLightPainter

<blockquote><code>
<pre style="line-height: 100%;font-family:monospace;background-color:#ffffff; border-width:0pt; border-color:#000000; border-style:solid; padding:4px;"><span style="background-color:#ffffff;">    </span><span style="color:#808000;background-color:#ffffff;">@Override
    </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">public</span><span style="background-color:#ffffff;"> </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">boolean</span><span style="background-color:#ffffff;"> contains(</span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">int</span><span style="background-color:#ffffff;"> x, </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">int</span><span style="background-color:#ffffff;"> y, JXLayer&lt;V&gt; l) {
        </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">for</span><span style="background-color:#ffffff;"> (Shape shape : </span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;">clipList)</span><span style="background-color:#ffffff;"> {
            </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">if</span><span style="background-color:#ffffff;"> (shape.contains(x, y)) {
                </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">return</span><span style="background-color:#ffffff;"> </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">true</span><span style="background-color:#ffffff;">;
            }
        }
        </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">return</span><span style="background-color:#ffffff;"> </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">false</span><span style="background-color:#ffffff;">;
    }
</span>
</pre></code></blockquote>

<h2>Conclusion</h2>
To add this functionality to your application you just need to wrap you component with JXLayer:

<blockquote><code>
<pre style="line-height: 100%;font-family:monospace;background-color:#ffffff; border-width:0pt; border-color:#000000; border-style:solid; padding:4px;"><span style="background-color:#ffffff;">JXLayer&lt;JComponent&gt; layer = 
     </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> JXLayer&lt;JComponent&gt;(myComponent, </span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;">spotLightPainter)</span>

add(</span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> JScrollPane(layer));

</span></pre>
</code></blockquote>
<p/>

All source and binary files you can find on the <a href="https://swinghelper.dev.java.net/">SwingHelper</a> project site
<p>

Thanks<br>
alexp]]>

</content>
</entry>
<entry>
<title>Debug Swing repainting</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/alexfromsun/archive/2007/11/debug_swing_rep.html" />
<modified>2008-06-24T19:17:03Z</modified>
<issued>2007-11-06T19:22:00Z</issued>
<id>tag:weblogs.java.net,2007:/blog/alexfromsun/284.8585</id>
<created>2007-11-06T19:22:00Z</created>
<summary type="text/plain">Implementing a nice visual indication during repainting of Swing components</summary>
<author>
<name>alexfromsun</name>

<email>Alexander.Potochkin@Sun.COM</email>
</author>
<dc:subject>Swing</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/alexfromsun/">
<![CDATA[<p/>
As everybody knows if you need to repaint a Swing component you should call <a href="http://java.sun.com/javase/6/docs/api/java/awt/Component.html#repaint()">Component.repaint()</a> method,
another well-known tip for the fast painting is:

<p/><i> 
 If only part of your component needs to be updated, make paint requests using a <a href="http://java.sun.com/javase/6/docs/api/javax/swing/JComponent.html#repaint(long,%20int,%20int,%20int,%20int)">version of repaint</a> that specifies the painting region.</i>
<p/>
It is very simple piece of advice - not to paint more than you need,
but sometimes this situation is not easy to catch.
Usually it is obvious when you paint less than you need, but 
repainting something which hasn't been changed is a kind of "invisible" operation.
<p/>
If the whole frame is repainted when any of its children is repainted you would hardly notice it on modern computer and that is the reason why I decided to return to my old love, <a href="http://weblogs.java.net/blog/alexfromsun/archive/2006/02/debugging_swing.html">Swing debugging</a> and add one debugging tool to <a href="https://jxlayer.dev.java.net/">JXLayer project</a>

<p/>
A visual indication for repainting events must work for every component, no matter which color it is painted, so I created an elegant <a href="https://jxlayer.dev.java.net/source/browse/jxlayer/trunk/src/java/org/jdesktop/jxlayer/plaf/ext/DebugRepaintingUI.java?view=markup">layer's UI delegate</a> which catches repainting and shows fade-out effect using inverted colors for a repainted area.

<p/>With this painter you can study your GUI and eliminate unnecessary painting, moreover it is very interesting just to see how Swing paints the core components - what part of a JTree is repainted when you open a node?  What is repainted when you open a popup ? 
<br>
Now it easy to get answers for this kind of questions.

<p/>
<a href="https://jxlayer.dev.java.net/webstart/DebugRepaintingDemo.jnlp">
    <img border=0 src="http://java.sun.com/products/jfc/tsc/sightings/images/webstart.small.jpg"></a> 

<p/>For example, it is easy to see what part of JTextField is repainted when you type in it and what happens when JTree's selection
is changed.I was also very pleased to check that we don't paint more than we need when selection of JTable is changed (second tab in the demo)

<p>I hope you'll find it useful for painting optimization for your custom components and LookAndFeels.
<br>
As usual it works for all LookAndFeels, the only thing you need is to wrap a container with your components with <a href="https://jxlayer.dev.java.net/">JXLayer</a> and set <a href="https://swinghelper.dev.java.net/source/browse/swinghelper/src/demo/org/jdesktop/swinghelper/layer/demo/DebugPainter.java?view=markup">DebugPainter</a>  from JXLayer's demo package.
<p>

<p/>
A flash presentation is available, press the green button below to start:
<p/>

<center><OBJECT CLASSID="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" WIDTH="400" HEIGHT="370" CODEBASE="http://active.macromedia.com/flash5/cabs/swflash.cab#version=7,0,0,0">
<PARAM NAME=movie VALUE="https://swinghelper.dev.java.net/bin/blog/debuglayer/demo.swf">
<PARAM NAME=play VALUE=true>
<PARAM NAME=loop VALUE=false>
<PARAM NAME=wmode VALUE=transparent>
<PARAM NAME=quality VALUE=low>
<EMBED SRC="https://swinghelper.dev.java.net/bin/blog/debuglayer/demo.swf" WIDTH=400 HEIGHT=370 quality=low loop=false wmode=transparent TYPE="application/x-shockwave-flash" PLUGINSPAGE="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash">
</EMBED>
</OBJECT></center>

<p/>

Have a nice day<br>
alexp]]>

</content>
</entry>
<entry>
<title>Why I don&apos;t use Swing hacks  (continuation)</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/alexfromsun/archive/2007/10/why_i_dont_use.html" />
<modified>2008-06-24T19:17:03Z</modified>
<issued>2007-10-09T12:50:24Z</issued>
<id>tag:weblogs.java.net,2007:/blog/alexfromsun/284.8332</id>
<created>2007-10-09T12:50:24Z</created>
<summary type="text/plain">Overview of hacks in validation overlays implementations</summary>
<author>
<name>alexfromsun</name>

<email>Alexander.Potochkin@Sun.COM</email>
</author>
<dc:subject>Swing</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/alexfromsun/">
<![CDATA[<p/>In one of my <a href="http://weblogs.java.net/blog/alexfromsun/archive/2007/08/validation_over.html">previous blogs</a> I answered to Kirill's comment that some of techniques he described in his <a href="http://www.pushing-pixels.org/?p=68">Swing painting pipeline</a> overview are "not good enough for me", 
<br>here I want to explain my point by brifely commenting some of the techinques he covered.

<h2>Implementing validation overlays</h2>

<p/>First of all I want to mention my requirements to the validation overlays implementation:<br/>

<ol>
<li>Solution shouldn't change global settings, it has to be as compatible with any other projects as possible</li>
<li>It should work well inside JScrollPane</li>
<li>Validation icons should respect Z-order of sibling components</li>
</ol>

<h2>RepaintManager</h2>

<p/>When a component requires a custom RepaintManager to be installed 
it sounds for me as strange as if I require to customize your operating system for my application.<br>RepaintManager is a global resouce and changing it to support a particular component is not just awkward but it may cause problems if another component wants to install its own RepaintManager at the same time.<br>Since Swing repaints components asynchronously it is impossible to fix this potential conflict by saving and restoring the old RM after repaint() is called.

<p/><b>Note:</b> <a href="http://swingx.dev.java.net/">SwingX</a> 
uses custom RM for their needs but it's a special case.<br>SwingX is a project which contains extentions for the Swing GUI toolkit which may become a part of the JDK.<br>If we decide to include e.g. translucency to Swing, the default RM will be the best choice to add support for this feature and no doubt, in this case their experience will be very useful.<br>Since a custom RepaintManager works well if you are sure that no one else will change it,
I take <a href="https://swingx.dev.java.net/source/browse/swingx/src/java/org/jdesktop/swingx/RepaintManagerX.java?view=markup">RepaintManagerX</a> as the only recommended alternative implementation

<h2>GlassPane</h2>

<p/>For me it is quite obvious that GlassPane is not the best solution for validation overlays. 
<br>I know that with GlassPane it is impossible to write a robust code which will <i>quickly and correctly</i>:
<ol>
<li>move/hide/show validation icon when its component is moved/hidden/shown</li>
<li>crop the icon when its component is overlapped by another component</li>
</ol>
<p/>I don't even need to repeat that GlassPane is a global resource etc, because all mentioned issues together with the <a href="http://www.pushing-pixels.org/?p=95">popups issue</a> make GlassPane unusable for validation overlays implementation

<h2>JLayeredPane</h2>

<p/>It is the most interesting hack and it deserves special attention because of two remarkable projects.<br/>
Long time ago I came across the <a href="http://rabbit-hole.blogspot.com/2006/04/decoratingoverpainting-swing.html">Decorating/Overpainting Swing Components</a> blog with an impressive demo by Timothy Wall.
<br>He transparently adds all kinds of custom components to the frame's default JLayeredPane to decorate existing components. 
<p/>The demo is really cool, but...<br/>
<ul>
<li>
It fails to meet my second requirement about quick painting inside JScrollPane<br/>
(I can see the labels' flickering when I scroll the JScrollPane in the demo, sorry about that)
</li>
<li>
It also fail to meet the third requrement because 
if two sibling non-opaque components are overlapped it is impossible to detect which component's pixels are transparent to correctly mix their decorations
<br>(I'll give an example later on)
</li>
</ul>

<p/>In addition in the <a href="http://abbot.sourceforge.net/demo/AbstractComponentDecorator.java">AbstractComponentDecorator.java</a> code I found a bunch of FIXME and TODO notes which reminds the situation with my JXTransformer<br> - you can  make it work for a demo, but it will never be completely ready for production use

<p/>The <a href="https://validation.dev.java.net/source/browse/validation/src/tutorial/com/jgoodies/validation/tutorial/util/IconFeedbackPanel.java?rev=1.21&view=markup">IconFeedbackPanel</a> by Karsten Lentzsch is another tricky solution. I wrote a simple test with a JTextField inside IconFeedbackPanel with a validation icon, <br>then I wrapped the JTextField with JScrollPane and the icon unexpectedly was gone.
<br>My first though was that IconFeedbackPanel doesn't support inner scrollPanes at all but then I read this note from its constructor javaDoc:

<br><br>
<i>Note: Typically you should wrap component trees with     getWrappedComponentTree(ValidationResultModel, JComponent)}, not this constructor.</i>
</br>

<p/>When I tried the magic getWrappedComponentTree method the validation icon appeared in the inner JScrollPane and were repainted very quickly during scrolling.
<br>After a few minitues I found the reason - this method traverses the component's hierarchy and wraps JScrollPane's views with additional IconFeedbackPanels!
<br>This is an important detail, I'll return to it later
<p/>The Karsten's code is clear and well-written as usual, only a few things about IconFeedbackPanel caught my attention
<ul>
<li>It removes all validation icons, adds them again and repaints the whole panel during every layout change, which is pretty expensive</li>
<li>Quote from javadoc: 
<br/><br/><i>you must ensure that the wrapped content
 provides enough space to display the overlaid components.
 <br>Since the current implementation positions the overlay components
 in the lower left, just make sure that there are about 6 pixel to the left
 and bottom of the input components that can be marked.</i><br/>
<br/>But what if I don't want to think about 6 pixel to the left and bottom and like to have a solution which will make it right?</li>
</ul>

<p/>Anyway, IconFeedbackPanel works well with JScrollPane, what about the second requirement?

<p/> Okay, you can already guess that this solution doesn't work well for overlapped sibling components either,
<br>to make it work you have to wrap every JTextField with a kind of an IconFeedbackPanel
<p/>Nevertheless, among all mentioned techniques, IconFeedbackPanel is probably the best one

<h2>JXLayer</h2>
<p/>In his comments Kirill mentioned an interesting term - "component-level techniques", comparing JXLayer with GlassPanes and LayeredPanes.
<br>Actually if you need to decorate an existing component you have only three recommended choices:

<ul>
<li>Subclass a component</li>
<li>Make a custom UI delegate</li>
<li>Wrap it with a special decorator</li>
</ul>

<p/>All of them are "component-level techniques" and there is no other valid tecniques in Swing, because only in that cases your components will work in predictable way for all common cases

<p/>JXLayer is a component's wrapper, which meets all my requirements:

<ol>
<li>It doesn't change any global resources</li>
<li>Its decorations are painted quickly and correctly inside JScrollPane

<p><a href="https://swinghelper.dev.java.net/bin/blog/nohacks/Test2.jnlp"><img border=0 src="http://java.sun.com/products/jfc/tsc/sightings/images/webstart.small.jpg"></a>

<li>It respects Z-order of sibling components
<br/>(move the decorated component and note that decorations correctly overlaps with the top circular component)
</li>

<p><a href="https://swinghelper.dev.java.net/bin/blog/nohacks/Test1.jnlp"><img border=0 src="http://java.sun.com/products/jfc/tsc/sightings/images/webstart.small.jpg"></a>
</ol>

<p/>Decorated components behave exactly like any other Swing components and there are no unexpected "special cases" where something might go wrong.
<br>That what I meant when I said that solutions like GlassPanes or LayeredPanes are not good enough for me.
<br>I want to be sure that my components will work well with all existing layouts, like <a href="http://www.jroller.com/gfx/entry/stacklayout">StackLayout</a>
<p/>
Try to make a component which is decorated with JLayeredPane, correctly overlap a non-opaque sibling component
<p/>
In the previous blog I showed two examples of validation decorations: 
when it is completely within the bounds of wrapped component, and JXLayer has the same size as its inner component;
<br>the second variant is when decorations are partially outside (the little red icon on the corner).

<p/> I personally like the first one, because it doesn't affect component's layout and doesn't require a bunch of listeners to be added to the TextField's document.
<br>If I needed to support that fancy outer icon for some TextFields I would use Karsten's trick - he automatically wraps JScrollPane's views only when I'd wrap all TextFields to set them identical insets

<h2>Conclusion</h2>

<p/>Sometimes the "no-hacks rule" is not easy to follow and may require some extra work,<br/>but use it or not is always up to you 

<p/>Thanks<br>
alexp]]>

</content>
</entry>
<entry>
<title>Why I don&apos;t use Swing hacks (in production code)</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/alexfromsun/archive/2007/09/why_i_dont_like.html" />
<modified>2008-06-24T19:17:03Z</modified>
<issued>2007-09-27T15:03:32Z</issued>
<id>tag:weblogs.java.net,2007:/blog/alexfromsun/284.8182</id>
<created>2007-09-27T15:03:32Z</created>
<summary type="text/plain">The recommended techniques seem to be too boring for some people,
when you use a hack it&apos;s like you use a hidden knowledge, isn&apos;t it?</summary>
<author>
<name>alexfromsun</name>

<email>Alexander.Potochkin@Sun.COM</email>
</author>
<dc:subject>Swing</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/alexfromsun/">
<![CDATA[<p/>
One of the big part of my work is fixing bugs in Swing but not all of them are to be fixed, some of them are closed because they describe the situations when someone uses Swing in undocumented way or trying to make Swing do something which it doesn't support.
<p/>My favourite example is so-called "Blocking GlassPane". If you file a bug with a description that you implemented a GlassPane to block your frame and it doesn't work, most likely it will immediately be closed as "not a bug". The reason is simple - glassPane is an internal feature of Swing and the library may use wherever it is necessary, for example currently we make it visible during resizing of internal frames to show a correct mouse cursor above any existing components. 
<p/>
Swing does it well if you just paint something on a GlassPane but when your GlassPane affects the processing of events it becomes what I call a "hack". There are many definitions what a "hack" is, either positive or negative, but I want to give a definition what I mean by this word

<hr/>
<b>Hack is an approach when you use something in an unexpected way</b>
<hr/>

<p/>Hacks don't have to be alway good or bad.
Some of them are creative and effective, some of them are just creative, but they are always different from recommended or well-known solutions.
<p/>
Going back to Swing I want to mention the main feature of a code which uses hacks:

<hr/>
<b>If you use recommended techniques and something doesn't work as it should <br/>Swing team is to be blame.<br/><br/>
If you use a hack and something doesn't work - it is you to be blame.</b>
<hr/>

<p/>Hacks usually work well for a presentation or a blog entry, but very few of them work as good and stable as the core library code. When you think it is good enough, someone else finds a problem whith your code and when you fix it, another issue appears so when you fix the "last" problem you know enough to write another valid test case which will be broken with your code. 

<p/>
Even if you are pretty sure that your hack works well on your computer, there usually no guarantee that it doesn't fail for another OS or with some custom components which use similar hack.

<p/>The "Blocking GlassPane" is an interesting example because it is a well-known hack which has never worked well. It is easy to put a fancy animation to a GlassPane and add an empty MouseListener to block the MouseEvents but people tend to forget about KeyBoard events and it is usually possible to type something in a TextField under a Blocking GlassPane. 

<p/>
I already <a href="http://weblogs.java.net/blog/alexfromsun/archive/2007/06/_enablingdisabl_1.html">blogged</a> about this issue and offered some solutions to make this hack more robust however a month ago I got a message from one of my readers, he told me that my improved Blocking Glasspane fails to block the menu accelerators, so if you use Alt+MenuShortCut the menu will appear.
<p/>
Problems like that is a usual thing when you use hacks. The most straightforward fix for this particular problem would be to disable frame's JMenuBar before showing GlassPane and enabling it again when the GlassPane is gone, but don't ask me how give user a chance to interrupt the time-consuming operation which blocks his frame or how to ignore keyboards actions for other components.

<hr/><b>
Modal dialog is the only recommended solution to block a top level frame</b>
<hr/>

<p/>
During my work on <a href="http://weblogs.java.net/blog/alexfromsun/archive/2006/07/jxtransformer_t.html">JXTransformer</a> I used any kind of hacks to make transformed components work as well as usual ones. I managed to make it work for unsigned applet however I used some fishy techniques which I can hardly recommend. And again I realized that it might work for the most usual cases but there will always be some cases when transformed components behave incorrectly and the only right fix is to change the Swing itself to support AffineTransform for JComponents. 
<p/>
After that I added a special note that JXTransformer has several known limitations and decided that my next project will use only recommended techniques which always work well.
<p/>
That's the reason why I don't use any hacks in <a href="https://swinghelper.dev.java.net/">JXLayer</a> component. When I started this project it was tempting to add some creative hacks to implement some unique features but I keep following the "no hacks rule" because I don't want to be blame if JXLayer wouldn't work for your project.

<h2>When hacks are welcome</h2>
<p/>If you think that I don't use hacks at all, it's not true. There are some situations where hacks (even the dirty ones) are welcome, I am talking about testing and debugging.
Let's say you need to find a cause of a bug, and in this case all means which may help are good (until they are not a part of production code). 
<p/>
On <a href="https://swinghelper.dev.java.net/">SwingHelper</a>  project you can find a <a href="https://swinghelper.dev.java.net/source/browse/swinghelper/src/java/org/jdesktop/swinghelper/debug/CheckThreadViolationRepaintManager.java?view=markup">CheckThreadViolationRepaintManager</a> which helps finding a Event Dispatch Thread violation in Swing applications as well as <a href="https://swinghelper.dev.java.net/source/browse/swinghelper/src/java/org/jdesktop/swinghelper/debug/EventDispatchThreadHangMonitor.java?view=markup">EventDispatchThreadHangMonitor</a> to catch time-consuming tasks on Event Dispatch Thread.
<br/>
I would hardly use custom RepaintManager or EventQueue for my components, but they work very well when it comes to debugging.
<p/>Testing is a similar story, when I have a choice between a manual regression test with no hacks and automated one with hacks, I always choose the last one, just because manual tests don't have much sense

<h2>Conclusion</h2>

<p/>I am a realist and I know that unfortunately it is almost impossible to make a big project without any hacks. The only recommendation I can give for this matter is do not use hacks just because you know them, try to follow the documented patterns as often as possible and you code will be more reliable

<p/>
To be continued...]]>

</content>
</entry>
<entry>
<title>Tag game: better later than never</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/alexfromsun/archive/2007/01/tag_game_better.html" />
<modified>2008-06-24T19:17:03Z</modified>
<issued>2007-01-27T14:01:02Z</issued>
<id>tag:weblogs.java.net,2007:/blog/alexfromsun/284.6424</id>
<created>2007-01-27T14:01:02Z</created>
<summary type="text/plain">My first blog which is not about Swing...</summary>
<author>
<name>alexfromsun</name>

<email>Alexander.Potochkin@Sun.COM</email>
</author>

<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/alexfromsun/">
<![CDATA[<p>A few weeks ago <a href="http://weblogs.java.net/blog/campbell/archive/2007/01/is_this_game_of.html">Chris</a>
tagged 4 people at once !
<br>It was a nice shot and that's why it took a while for me to prepare an answer
<p>So, five strange things about me which came to my mind on this snowy Saturday:

<ul>
<li>I went to a very traditional Soviet school which was considered as the best one in the district I lived. <br>We all wore the red ties because we were  "young pioneers".<br>Sometimes, after the lessons, we were to march along the school hall and sing patriotic songs<br>and because I was a rather tall boy I was selected to carry a big red flag in the vanguard (no jokes).<br>Despite the fact I didn't go to the army, I still remember how to use <a href="http://en.wikipedia.org/wiki/AK-47">Kalashnikov</a></li><br>

<li>I made my first airplane flight when I was 20.<br>It was a little plane for parachute jumpers and it was my first parachute jump</li><br>

<li>When I was a student I, together with my university pals,<br>went to the very north of Russia to do manual labour and raise some money during summer time.<br>I used to dig, drag and drop and after that I realized that I should probably find another job</li><br>

<li>Working on summer allowed me to buy my first PC -   IBM 386 with 4 Mb RAM and 40 MB hard disk,<br>it was really powerful and cost me 550$</li><br>

<li>I like to travel and to meet new people,<br>so don't hesitate if you want to invite me to your city and show some interesting places :-)<br>By the way if you happen to visit <a href="http://www.saint-petersburg.com/">Saint-Petersburg</a>, <br>let me know and I'll select a day to accompany you on your city exploration</li>
</ul>
<p> 
That's it !

<p>
I am tagging <a href="http://weblogs.java.net/blog/kirillcool/">Kirill</a>,  who seems to be the only active javadesktop blogger<br>who hasn't revealed any facts from his biography yet

<p>alexp]]>

</content>
</entry>
<entry>
<title>KISS principle: JXButtonGroupPanel followup</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/alexfromsun/archive/2006/11/kiss_principle.html" />
<modified>2008-06-24T19:17:03Z</modified>
<issued>2006-11-01T18:28:37Z</issued>
<id>tag:weblogs.java.net,2006:/blog/alexfromsun/284.5845</id>
<created>2006-11-01T18:28:37Z</created>
<summary type="text/plain">JXButtonGroupPanel from my  previous blog is rewritten to make it easier to use. 
Just substitute JPanel to the new JXButtonPanel and enjoy arrow keys support for your buttons !</summary>
<author>
<name>alexfromsun</name>

<email>Alexander.Potochkin@Sun.COM</email>
</author>
<dc:subject>Swing</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/alexfromsun/">
<![CDATA[<p>In one of my <a href="http://weblogs.java.net/blog/alexfromsun/archive/2006/08/the_buttongroup.html">previous blog</a> I presented a component which enables arrow keys to transfer focus and selection for Swing buttons.<br> 
And it worked very well, but there were two things which worried me
<ul>
<li>JXButtonGroupPanel offered a different way to bind buttons to a ButtonGroup<br> since it created ButtonGroup and filled it up behind the scene</li>
<li>It was just overcomplicated</li>
</ul>

<p>That why I mentioned Keep It Simple principle<br>
Actually I like to control what is going on in my applications and don't like when componets are trying to be too smart.<br>
Indeed, when you need to add some JRadioButtons to a panel, you usually do something like this:
<p>
<blockquote><code><pre style="border: 1px solid darkgray; padding: 4px; color: darkblue;">
<FONT style="font-family:monospaced;" COLOR="#000000">JPanel panel = </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>new</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> JPanel(); 
</FONT><FONT style="font-family:monospaced;" COLOR="#808080"><I>// Create a ButtonGroup        </I></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> 
ButtonGroup group = </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>new</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> ButtonGroup(); 
 
JRadioButton r1 = </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>new</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> JRadioButton(</FONT><FONT style="font-family:monospaced;" COLOR="#008000"><B>&quot;One&quot;</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000">); 
</FONT><FONT style="font-family:monospaced;" COLOR="#808080"><I>// Add a button to the panel   </I></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> 
panel.add(r1); 
</FONT><FONT style="font-family:monospaced;" COLOR="#808080"><I>// Add a button to the ButtonGroup</I></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> 
group.add(r1); 
 
JRadioButton r2 = </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>new</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> JRadioButton(</FONT><FONT style="font-family:monospaced;" COLOR="#008000"><B>&quot;Two&quot;</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000">); 
panel.add(r2); 
group.add(r2); 
JRadioButton r3 = </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>new</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> JRadioButton(</FONT><FONT style="font-family:monospaced;" COLOR="#008000"><B>&quot;Three&quot;</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000">); 
panel.add(r3); 
group.add(r3); 
 
frame.add(panel);</FONT></PRE></blockquote></code>

<p>I would prefer to change the existing code as little as possible if I just want to enable arrow keys support. 
<p>With all mentioned reasons in mind I rewrote JXButtonGroupPanel to make it shorter and easier to use<br>
I even cut down its name from JXButtonGroupPanel to JXButtonPanel :-)

<p> On the <a href="https://swinghelper.dev.java.net">SwingHelper project</a> you can as usual find the <a href="https://swinghelper.dev.java.net/bin/buttonpanel/buttonpanel.jar">buttongroup.jar</a> and <a href="https://swinghelper.dev.java.net/bin/buttonpanel/buttonpanel-src.zip">buttonpanel-src.zip</a> 
<p>Direct link to <a href="https://swinghelper.dev.java.net/source/browse/swinghelper/src/java/org/jdesktop/swinghelper/buttonpanel/"> JXButtonPanel sources</a>

<p>The demo is also rewritten to take advantage of the new implementation   
<a href="https://swinghelper.dev.java.net/bin/buttonpanel/ButtonPanelDemo.jnlp"><img border=0 src="http://java.sun.com/products/jfc/tsc/sightings/images/webstart.small.jpg"></a>

<h2>Summary</h2>
<ul>
<li>Just change your JPanel to JXButtonPanel and arrow keys will work</li>
<li>It doesn't fill a ButtonGroup up behind the scene anymore</li>
<li>Based on a comment from paulo_matos I added a groupSelectionFollowFocus property<br>which controls whether arrow keys should transfer button's selection as well as focus or not</li>
<li>It is fully tested and ready for production</li>
</ul>
<p>Your comments are welcome !<br>
Thanks<br>
alexp]]>

</content>
</entry>
<entry>
<title>Crazy JButton painters</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/alexfromsun/archive/2006/10/crazy_jbutton_p.html" />
<modified>2008-06-24T19:17:03Z</modified>
<issued>2006-10-05T18:51:50Z</issued>
<id>tag:weblogs.java.net,2006:/blog/alexfromsun/284.5684</id>
<created>2006-10-05T18:51:50Z</created>
<summary type="text/plain">Painters have been in Swing from the beginning !</summary>
<author>
<name>alexfromsun</name>

<email>Alexander.Potochkin@Sun.COM</email>
</author>
<dc:subject>Swing</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/alexfromsun/">
<![CDATA[<p>
Inspired by some latest blogs I decided to find the most hacky and crazy method to paint on a component 
<br>
I chose JButton as the most well-known component to play with
<br><br>
The goal is to implement some custom painting to a button without subclassing it and with no custom UI delegate
<p>
<h2>Custom component</h2>
<p>
As you probably know all Swing components are Containers, 
that means that you can add any children components to them.
However not all Swing components support it, e.g. it usually doesn't make sense to add children to a components like JSlider or JProgressBar<p>
JButton is not supposed to be used as a Container but we certainly can try:
<p>
<blockquote><code><pre style="border: 1px solid darkgray; padding: 4px; color: darkblue;"><FONT style="font-family:monospaced;" COLOR="#000000">JButton button = </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>new</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> JButton(</FONT><FONT style="font-family:monospaced;" COLOR="#008000"><B>&quot;I am a JButton&quot;</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000">);         
</FONT><FONT style="font-family:monospaced;" COLOR="#808080"><I>// JButton's layout is null by default</I></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> 
button.setLayout(</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>new</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> FlowLayout()); 
         
button.add(</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>new</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> JButton(</FONT><FONT style="font-family:monospaced;" COLOR="#008000"><B>&quot;Surprise!&quot;</B></FONT>));</pre></code></blockquote>
<p>
It is the clue to the first trick, you can add a translusent component to the button to make it looks different
<p>
<blockquote><code><pre style="border: 1px solid darkgray; padding: 4px; color: darkblue;">
<FONT style="font-family:monospaced;" COLOR="#000000">button.setLayout(</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>new</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> BorderLayout()); 
button.add(</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>new</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> ComponentPainter()); 
                     
button.revalidate(); 
button.repaint(); 
.                     
.
</FONT>
<FONT style="font-family:monospaced;" COLOR="#000080"><B>class</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> ComponentPainter </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>extends</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> JPanel { 
    </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>protected</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>void</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> paintComponent(Graphics g) { 
        Graphics2D g2 = (Graphics2D) g.create(); 
        </FONT><FONT style="font-family:monospaced;" COLOR="#808080"><I>// It enables painting outside the component's border</I></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> 
        g2.setClip(</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>null</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000">); 
        </FONT><FONT style="font-family:monospaced;" COLOR="#808080"><I>// Make it translucent</I></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> 
        g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">0.3f</FONT><FONT style="font-family:monospaced;" COLOR="#000000">)); 
        </FONT><FONT style="font-family:monospaced;" COLOR="#808080"><I>// Take button's insets into account</I></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> 
        Insets insets = button.getInsets(); 
        </FONT><FONT style="font-family:monospaced;" COLOR="#808080"><I>// Custom painting</I></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> 
        g2.setColor(Color.ORANGE); 
        g2.fillOval(-insets.left, -insets.top, button.getWidth(), button.getHeight()); 
        g2.setColor(Color.GRAY); 
        g2.drawOval(-insets.left, -insets.top, button.getWidth(), button.getHeight()); 
        g2.dispose(); 
    } 
}</FONT></pre></code></blockquote>

<h2>Unusual border</h2>
<p>
Borders in Swing are used to paint decorations around a Component,<br>
but we are going to break the rules and create a Border instance to paint to the whole component's area
<p>
<blockquote><code><pre style="border: 1px solid darkgray; padding: 4px; color: darkblue;">
<FONT style="font-family:monospaced;" COLOR="#000080"><B>class</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> BorderPainter </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>extends</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> AbstractBorder { 
    </FONT><FONT style="font-family:monospaced;" COLOR="#000080">
    <B>public</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>void</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> paintBorder(Component c, Graphics g, </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>int</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> x, </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>int</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> y, </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>int</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> width, </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>int</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> height) { 
        Graphics2D g2 = (Graphics2D) g.create(); 
        g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">0.3f</FONT><FONT style="font-family:monospaced;" COLOR="#000000">)); 
        g2.setPaint(</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>new</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> GradientPaint(</FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">0</FONT><FONT style="font-family:monospaced;" COLOR="#000000">, </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">10</FONT><FONT style="font-family:monospaced;" COLOR="#000000">, Color.BLACK, </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">10</FONT><FONT style="font-family:monospaced;" COLOR="#000000">, </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">10</FONT><FONT style="font-family:monospaced;" COLOR="#000000">, Color.RED, </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>true</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000">)); 
        </FONT><FONT style="font-family:monospaced;" COLOR="#808080"><I>// We are free to paint wherever we want :-)</I></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> 
        g2.fillRect(</FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">0</FONT><FONT style="font-family:monospaced;" COLOR="#000000">, </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">0</FONT><FONT style="font-family:monospaced;" COLOR="#000000">, button.getWidth(), button.getHeight()); 
    } 
}</FONT></pre></code></blockquote>
<p>
The only problem with this approach is that a component can have only one border, and new border will replace the old one.<br>
javax.swing.border.CompoundBorder will help us to compose the existing border with the additional one:
<blockquote><code><pre style="border: 1px solid darkgray; padding: 4px; color: darkblue;">
<FONT style="font-family:monospaced;" COLOR="#000000">Border oldBorder = button.getBorder(); 
button.setBorder(</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>new</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> CompoundBorder(oldBorder, </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>new</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> BorderPainter()));</FONT></pre></code></blockquote>

<p>
<h2>Misuse of Icon</h2>
<p>The last dirty trick involves javax.swing.Icon
<p>it has a paintIcon() method with suggested coordinates as parameters, but as you can guess we are not going to use them.<br>
There might be the same problem as we already mentioned for Borders:
you can set only one icon per a button<br><br>
But it is not a problem for a real hacker :-)
<p>
<blockquote><code><pre style="border: 1px solid darkgray; padding: 4px; color: darkblue;">
<FONT style="font-family:monospaced;" COLOR="#000000">Icon oldIcon = button.getIcon(); 
button.setIcon(</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>new</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> IconPainter(oldIcon)); 
. 
.</FONT>
<FONT style="font-family:monospaced;" COLOR="#000080"><B>class</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> IconPainter </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>implements</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> Icon { 
    </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>private</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>final</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> Icon delegateeIcon; 
 
    </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>public</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> IconPainter(Icon innerIcon) { 
        </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>this</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000">.delegateeIcon = innerIcon; 
    } 
 
    </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>public</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>int</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> getIconWidth() { 
        </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>if</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> (delegateeIcon != </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>null</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000">) { 
            </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>return</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> delegateeIcon.getIconWidth(); 
        } 
        </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>return</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">0</FONT><FONT style="font-family:monospaced;" COLOR="#000000">; 
    } 
 
    </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>public</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>int</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> getIconHeight() { 
        </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>if</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> (delegateeIcon != </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>null</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000">) { 
            </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>return</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> delegateeIcon.getIconHeight(); 
        } 
        </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>return</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">0</FONT><FONT style="font-family:monospaced;" COLOR="#000000">; 
    } 
 
    </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>public</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>void</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> paintIcon(Component c, Graphics g, </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>int</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> x, </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>int</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> y) { 
        </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>if</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> (delegateeIcon != </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>null</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000">) { 
            delegateeIcon.paintIcon(c, g, x, y); 
        } 
        Graphics2D g2 = (Graphics2D) g.create(); 
        g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">0.3f</FONT><FONT style="font-family:monospaced;" COLOR="#000000">)); 
        g2.setPaint(</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>new</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> GradientPaint(</FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">10</FONT><FONT style="font-family:monospaced;" COLOR="#000000">, </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">0</FONT><FONT style="font-family:monospaced;" COLOR="#000000">, Color.RED, </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">10</FONT><FONT style="font-family:monospaced;" COLOR="#000000">, </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">10</FONT><FONT style="font-family:monospaced;" COLOR="#000000">, Color.BLUE, </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>true</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000">)); 
        </FONT><FONT style="font-family:monospaced;" COLOR="#808080"><I>// It is a special icon, it is not interesed in x, y and icon's size </I></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> 
        g2.fillRect(</FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">0</FONT><FONT style="font-family:monospaced;" COLOR="#000000">, </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">0</FONT><FONT style="font-family:monospaced;" COLOR="#000000">, button.getWidth(), button.getHeight()); 
    } 
}</FONT></pre></code></blockquote>

<p>
<h2>Demo</h2>
<p>There is a demo with all this crazy stuff implemented

<p><a href="http://www.java.net/download/javadesktop/blogs/alexfromsun/2006.10.05/buttonpainter.jnlp"><img border=0 src="http://java.sun.com/products/jfc/tsc/sightings/images/webstart.small.jpg"></a>
<p>
I have finally found the modern and fresh look for my buttons !
<p>
<img src="http://www.java.net/download/javadesktop/blogs/alexfromsun/2006.10.05/modernbutton.PNG">
<p>
<a href="http://www.java.net/download/javadesktop/blogs/alexfromsun/2006.10.05/ButtonPainter.java">Source  code</a>
<p>

<h2>Conclusion</h2>
<p>Despite the fact the provided tricks work<br>
please <b>consider this blog as a joke</b><br><br>
I hope no one takes it seriously and starts using something like described "IconPainter"<br><br>

Have a nice day<br>
alexp<br>
;-)]]>

</content>
</entry>
<entry>
<title>A well-behaved GlassPane</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/alexfromsun/archive/2006/09/a_wellbehaved_g.html" />
<modified>2008-06-24T19:17:03Z</modified>
<issued>2006-09-20T20:02:42Z</issued>
<id>tag:weblogs.java.net,2006:/blog/alexfromsun/284.5581</id>
<created>2006-09-20T20:02:42Z</created>
<summary type="text/plain">Fixing common mouseEvents problems for the custom GlassPanes implementations</summary>
<author>
<name>alexfromsun</name>

<email>Alexander.Potochkin@Sun.COM</email>
</author>
<dc:subject>Swing</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/alexfromsun/">
<![CDATA[<p>
I have seen a lot of custom GlassPane tricks, which use GlassPane to "disable" the frame, to provide a visual effects during the lengthy tasks or to give more rich feedback during drag and drop etc...

<p>
The distinctive feature of that tricks is that GlassPane is shown only temporarily,<br>so when the lengthy tast or any other action is completed the custom GlassPane is made hidden and doesn't affect the frame anymore

<p>
I am going to examine special cases when you might want to show a GlassPane to provide a constant visual effects,<br>this way the frame is supposed to function as usual except the big translucent text e.g. "Hello Mom !" is shown on the top of the content pane :-)

<p>
So let's create a GlassPane which shows a colored rectangle at the top right corner of the frame and draws the colored circle to follow the mouse's cursor.<br>As a testing environment please launch this simple application

<p><a href="http://www.java.net/download/javadesktop/blogs/alexfromsun/2006.09.20/glasspane.jnlp"><img border=0 src="http://java.sun.com/products/jfc/tsc/sightings/images/webstart.small.jpg"></a> 

<p>
This application contains two JInternalFrames, 
components on the first frame don't have any special features,
only JTextField has a popupMenu,<br> 
the second frame contains components which have a rollover effect - their background turns green when you move the mouse cursor to them, moreover each of them has a tooltip

<p>
To make it more interesting I implemented a kind of a "focus follow mouse" policy for both internal frames, so when mouse's cursor crosses frames border, the frame becomes selected

<p>
Don't close this application we will use it to test

<h2>The initial GlassPane version</h2>
<p><p>
Most of the similar GlassPane implementations which I tested, copied 
the code from the <a href="http://java.sun.com/docs/books/tutorial/uiswing/components/rootpane.html">
How to use Root Pane</a> Swing tutorial.<br>
The main idea is to add mouseListener and mouseMotionListener to the GlassPane, catch the mouseEvent and then redispatch it to the component found with help of SwingUtilities.getDeepestComponentAt()

<p>
Based on this solution I created the <a href="http://www.java.net/download/javadesktop/blogs/alexfromsun/2006.09.20/InitialGlassPane.java.html ">InitialGlassPane</a> version.

<p>
Please return to the testing application and select the "GlassPane is visible" checkBox from the Options menu or simply press Alt+G to activate this menuItem. 
<p><b>Note: Diring the initial glassPane is visible, it is impossible to select any menuItems, use key accelerators instead</b>

<p>
Notice the red rectangle appeared at the right top frame's corner and the red translucent circle started follow the mouse.<br>Let's check how it affects the frame's contents:

Click to the every component from the first internalFrame, as you can see, they seem to work:<br>
You still can select the CheckBox and edit the JTextField

<p>
Now play with the components from the second internal frame
Here we can quickly notice some odd things like absence of rollover effects.
<p>

Here the list of problems you can see during initial GlassPane is visible:

<ol>
<li>When Options menu is visible it doesn't react to the mouse, 
the textField's popup doesn't work as well</li>
<li>Component's rollover effect is missed</li>
<li>When you move the mouse cursor between the internal frames they don't get selected as they did before</li>
<li>Tooltips become very unreliable, they might appear in unusual places or not appear at all</li>
</ol>

<p>
There is one more problem which is not so visible:
<ul>
 <li>press the JButton</li>
 <li>drag out of its border</li>
 <li>release the mouse button</li>
 <li>The button remains pressed !</li>
</ul>
<p>
Here is a screenshot with the mess you can get with the initial GlassPane

<p>
<img src="http://www.java.net/download/javadesktop/blogs/alexfromsun/2006.09.20/problem.PNG"/>
</p>

<p>
Now hide the glassPane by pressing Alt+G and see the difference,
everything works much better, right ?
<p>
Notice one more little feature:

<ul>
 <li>press the slider</li>
 <li>drag out of the *frame* border</li>
 <li>note that you can still move the slider's thumb</li>
</ul>

<p>
It doesn't work this way for the initial GlassPane, but after all mentioned problems this doesn't look very bad, does it ?

<h2>Why it doesn't work</h2>
<p><p>
GlassPane doesn't get all events you need, e.g. when you move the mouse inside it you redispatch the mouseMotion events only.<br>That's why rollover effect didn't work - just because components didn't receive mouseEntered/MouseExited events.
<p>
That glassPane also breaks the inner mouseEvents processing so it leads to broken drag and drop, menus and tooltips
<p>
<b>Actually redispatching mouseEvents this way is just a bad idea</b><br><br> and I am going to ask to update the Swing tutorial<br>
you can fix some problems for the current implementation but it will never work perfectly
<p>To fix the problems our GlassPane should be absolutely transparent for mouseEvents, it means that we shouldn't  add any Mouse/MouseMotion/MouseWheelListeners to it
<p>
For more information about mouseEvent transparency please refer to the my <a href="http://www.java.net/download/javadesktop/blogs/alexfromsun/2006.06.28/BOF-0204.pdf">my  BoF session</a> from the latest JavaOne conference (see the MouseEvents topic)
<p>
But wait, how can I process the mouseMotion events if I didn't add any mouseListeners to the glassPane ? 
<p>
To get the answer please try the 

<h2>Better GlassPane</h2>
<p><p>
We can catch mouseEvents without mouseListeners with AWTEventListener, this way we will keep our GlassPane transparent for mouseEvents and it will not affect the mouseEvents processing
<p>Check out the <a href="http://www.java.net/download/javadesktop/blogs/alexfromsun/2006.09.20/BetterGlassPane.java.html">Better GlassPane</a> implementation
<p>
Let's return to the testing application, switch the glassPane implementation to the Better GlassPane and make it visible.<br>
After the yellow rectangle and circle appear <b>you will not find any differences</b> in mouse processing !
<p>
Menus, buttons, rollover everything work with no surprises
<p>
This is a really better GlassPane, but it also has a little problem
(the first GlassPane has it as well by the way):
<ul>
<li>Hide the better GlassPane (press Alt+G)</li>
<li>Move the mouse cursor inside the JTextField</li>
<li>The default mouse cursor turns to "text editing" cursor</li>
<li>Show the better GlassPane (press Alt+G)</li>
<li>Move the mouse cursor inside the JTextField</li>
<li>Look that mouse cursor doesn't change</li>
</ul>

<p>
<img src="http://www.java.net/download/javadesktop/blogs/alexfromsun/2006.09.20/better.PNG"/>
</p>
<p>
You can see the same problem if you move the cursor to the internal frame border -<br>
the cursor is supposed to change to show that resizing is allowed
<p>
This GlassPane prevents mouse cursor to be changed, it is always the same no matter which component you work with

<h2>Why it doesn't work</h2>
<p><p> 
The problem is that AWT system show the cursor of the topmost visible component<br>and since our topmost component is GlassPane and it has the default cursor it is always the same
<p> The fix is simple and I am happy to present the

<h2>Final GlassPane</h2>
<p><p>
 To fix the "cursor problem" we should make our GlassPane even more transparent,<br>there is a special method which is used by AWT to detect the target component for the mouseEvents
<PRE><FONT style="font-family:monospaced;" COLOR="#000000"></FONT><FONT style="font-family:monospaced;"COLOR="#000080"><B>public</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>boolean</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> contains(</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>int</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> x, </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>int</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> y)</FONT></PRE>
</BODY>

<p>The hot fix is to override this method to alway return false for the GlassPane,<br> after that you'll start to see proper cursors and your GlassPane will be finally and absolutely transparent,<br><br> because even if you add a MouseListener to it, it will never be notified<br>since such a GlassPane doesn't "contain" any geometrical points
<p>
And here it is time to reveal a big secret: 
<p>
<b>GlassPane might be used by someone else as well</b>

<p>Here is a scenario for our testing application:
<ul>
<li>Hide the current glassPane</li>
<li>Resize an internalFrame with help of the mouse</li>
<li>Notice that during resizing GlassPane becomes visible</li>
<li>When resizing is over GlassPane is made hidden</li>
</ul>

<p>In this case GlassPane is made visible to provide a proper mouse cursor during internalFrame's resizing

<p>Moreover someone else might implement special logic with help of the GlassPane<br>e.g. add some MouseListeners to it during drag and drop and than remove them to restore mouseEvents transparency
 
<p>So, if we prepare our GlassPane for our application only and pretty sure that no one else will use it, it is ok to override contains method to always return false

<p>But this blog is about a <a href="http://www.java.net/download/javadesktop/blogs/alexfromsun/2006.09.20/FinalGlassPane.java.html">well-behaved GlassPane</a> which is supposed to behave well for any situation

<p>So if someone added a mouseListener to the GlassPane or set a new mouse cursor I don't change contains method behaviour<br> 
but return false otherwise

<p>We have finally solved all problems and our final GlassPane does well
<p>
<img src="http://www.java.net/download/javadesktop/blogs/alexfromsun/2006.09.20/final.PNG"/>
</p>

<h2>Conclusion</h2>
<p><p>
Here you can find the <a href="http://www.java.net/download/javadesktop/blogs/alexfromsun/2006.09.20/glasspane.jar">runnable jar</a> and <a href="http://www.java.net/download/javadesktop/blogs/alexfromsun/2006.09.20/sources.zip">archive </a> with all source files

<p>
I hope this tutorial will help you to better understand Swing and AWT mouseEvents processing and<br>let your GlassPanes be really transparent !

<p>See also the follow-up blog <a href="http://weblogs.java.net/blog/alexfromsun/archive/2007/06/_enablingdisabl_1.html"> Enabling/Disabling Swing Containers</a>
]]>

</content>
</entry>
<entry>
<title>The ButtonGroup of my dreams</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/alexfromsun/archive/2006/08/the_buttongroup.html" />
<modified>2008-06-24T19:17:03Z</modified>
<issued>2006-08-23T18:34:37Z</issued>
<id>tag:weblogs.java.net,2006:/blog/alexfromsun/284.5414</id>
<created>2006-08-23T18:34:37Z</created>
<summary type="text/plain">Ease of use + skip unselected buttons + arrow keys support</summary>
<author>
<name>alexfromsun</name>

<email>Alexander.Potochkin@Sun.COM</email>
</author>
<dc:subject>Swing</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/alexfromsun/">
<![CDATA[<p>I have fixed quite a lot of bugs and RFE's in Swing for Java 1.6 and don't really remember all of them,<br> but I do remember one remarkable bug because it took me unusually long time to find a good solution<br>
and after I had fixed it I had to fix several regressions and finally
I completely rolled the fix back<br>

<p>Let me introduce you the bug number <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4226243">4226243</a>
(and 10 related bugs)

<h2>So why fixing it was so difficult ?</h2>

<p>We just should be able to move the focus and selection inside the RadioButtonGroup with help of arrow keys...

<p>That doesn't look like a hard problem

<p>But we also need to skip unselected radioButtons if we move focus from component to component pressing "Tab" button,<br>just like Windows or GTK do it.<br> 
Test any native application with RadioButtonGroup and you will see that<br>
if a RadioButtonGroup has a selected button it is impossible to focus unselected one with help of "Tab" of "Shift+Tab" buttons.

<p>Native ButtonGroup behaviours like a one component:

<p>you press "Tab" -> focus gets the selected button
<br>press "Tab" again -> focus goes out
<br>selection can be changed with help of arrow keys (or by clicking mouse)

<p>This part turned out to be really problematic...
<p>The real killer was the fact that javax.swing.ButtonGroup is not a Swing component,<br>it implements a set of buttons which can be placed on differect panels and<br> theoretically speaking even on different frames ! <br><br>
it might explain why our focus management wasn't ready to such an unnatural request

<p>Finally with great help of AWT team we found a workable fix<br>
but since it is supposed to use some reflection and other hacks<br>
I doubt we will accept this version

<p>It probably was a sad story, but the time wasn't spent in vain
<br>as a result of lengthy work on that bug I got a clear vision of

<h2>Better ButtonGroup implementation</h2>

<p>Please welcome JXButtonGroupPanel from <a href="https://swinghelper.dev.java.net/">SwingHelper</a> project

<ol>
<li>It transparently adds all its children buttons 
to the group
</li>
<li>Can be used as for exclusive JRadioButtons group as well as for group of JButtons</li>
<li>Supports arrow keys and correctly works with focus for exclusive groups</li>
<li>Just makes it easier to implement typical button groups</li>
</ol>
<p><a href="https://swinghelper.dev.java.net/bin/buttonpanel/ButtonPanelDemo.jnlp"><img border=0 src="http://java.sun.com/products/jfc/tsc/sightings/images/webstart.small.jpg"></a>

<p>You just add your buttons to JXButtonGroupPanel and it will do the rest of the work
<p>Please try it and share you opinion !

<p><h3>Note: Please read the <a href="http://weblogs.java.net/blog/alexfromsun/archive/2006/11/kiss_principle.html">Follow up blog</a></h3>]]>

</content>
</entry>

</feed>