<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3113056103202976131</id><updated>2011-08-07T13:12:17.320+02:00</updated><category term='jtable'/><category term='dropshadow'/><category term='dialog'/><category term='cellRenderer'/><category term='jxlayer'/><category term='jdialog'/><category term='text'/><category term='jlist'/><category term='toggleButton'/><category term='jframe'/><category term='swing'/><title type='text'>Free the pixel</title><subtitle type='html'>About java swing/java2D stuff</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://free-the-pixel.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3113056103202976131/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://free-the-pixel.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Mabs</name><uri>http://www.blogger.com/profile/05193647092760468172</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_MiO_FvhBBtA/S0-XEk_aYnI/AAAAAAAAACA/1tm3UOOLGsQ/s1600-R/xanlogoshiny_trans_small.png'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>16</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3113056103202976131.post-7925026927300636045</id><published>2010-06-05T23:04:00.002+02:00</published><updated>2010-06-06T19:56:23.526+02:00</updated><title type='text'>Animated Scrolling text</title><content type='html'>Some days ago, a friend(hey Luiz!) asked me about a component that could display text with a kind of scrolling animation as you  see in many media players where you see the band name / title name going from right to left. He wanted to add this kind of component to one of his application. As he knows I like to play with swing/java2D he asked me about it.&lt;br /&gt;I like the idea of creating such component; so I had to come up with an implementation, even If I guess you can find some basic implementations on the net.&lt;br /&gt;&lt;br /&gt;I wanted to add a way to control the animation to be able to have some basic animations (Left to right / Right to left / Top to bottom / Bottom to top) and also some more complex animation like sinusoidal animation.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I rapidly had a first draft working, doing the wished animation, but it took a few refractor sessions to have some clean code that gives full control over the animation.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Let’s have a look at the code.&lt;br /&gt;&lt;br /&gt;First the interface that will be used to control the animation:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;public static interface IScrollTextUtils {&lt;br /&gt;    int getYpos(float animProgress, int charnum);&lt;br /&gt;&lt;br /&gt;    int getXpos(float animProgress, int charnum);&lt;br /&gt;&lt;br /&gt;    double getRotate(float animProgress, final int charnum);&lt;br /&gt;&lt;br /&gt;    float getTransformedFontSize(float animProgress, int fontSize, final int charnum);&lt;br /&gt;&lt;br /&gt;    boolean isTimeTolaunchNewTimeline(float animProgress);&lt;br /&gt;&lt;br /&gt;    void textChanged();&lt;br /&gt;&lt;br /&gt;    void paintCharacter(Graphics2D g, String s);&lt;br /&gt;&lt;br /&gt;    int getDuration();&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;It will be used to find out the position of each character, paint the text, the duration of the animation and to determine when to start the next animation.&lt;br /&gt;&lt;br /&gt;More than one of the same animation can run at the same time (you want to start the next animation before the end of the current one to always have some text to display).&lt;br /&gt;&lt;br /&gt;So to deal with multiple animations at the same time we need a list of something that can handle an animation.&lt;br /&gt;AnimationProgressHandler is used for this purpose.&lt;br /&gt;It contains a timeline and a way to start the next animation when required&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;public static class AnimationProgressHandler {&lt;br /&gt;        private Timeline timeline;&lt;br /&gt;        private float animProgress = 0;&lt;br /&gt;        private boolean AlreadyStartedNext = false;&lt;br /&gt;        private ScrollingText scrolling;&lt;br /&gt;&lt;br /&gt;        private AnimationProgressHandler(final ScrollingText scrolling) {&lt;br /&gt;            this.scrolling = scrolling;&lt;br /&gt;            //prepare the timeline&lt;br /&gt;            this.timeline = new Timeline(this);&lt;br /&gt;            this.timeline.addPropertyToInterpolate("animProgress", 0f, 1f);&lt;br /&gt;            this.timeline.setDuration(scrolling.scrollTextUtils.getDuration());&lt;br /&gt;            this.timeline.addCallback(createCallBack(this.timeline));&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public void setAnimProgress(final float animProgress) {&lt;br /&gt;            this.animProgress = animProgress;&lt;br /&gt;            if (!this.AlreadyStartedNext &amp;amp;&amp;amp; this.scrolling.scrollTextUtils.isTimeTolaunchNewTimeline(animProgress)) {&lt;br /&gt;                this.AlreadyStartedNext = true;&lt;br /&gt;                //start the next animation&lt;br /&gt;                this.scrolling.createTimeline().play();&lt;br /&gt;            }&lt;br /&gt;            this.scrolling.repaint();&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private TimelineCallback createCallBack(final Timeline parent) {&lt;br /&gt;            return new TimelineCallbackAdapter() {&lt;br /&gt;                @Override&lt;br /&gt;                public void onTimelineStateChanged(final TimelineState oldState, final TimelineState newState,&lt;br /&gt;                        final float durationFraction, final float timelinePosition) {&lt;br /&gt;                    if (newState == TimelineState.DONE) {&lt;br /&gt;                        //when the animation is done &lt;br /&gt;                        //remove it&lt;br /&gt;                        AnimationProgressHandler.this.scrolling.animHandlers.remove(this);&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;            };&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;the interesting methods in scrolling text are the paint methods&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;paintComponent paint the text for every active timeline&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;    protected void paintComponent(final Graphics g) {&lt;br /&gt;        super.paintComponent(g);&lt;br /&gt;        Graphics2D g2 = (Graphics2D) g.create();&lt;br /&gt;        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);&lt;br /&gt;        // paint the text for each running animation&lt;br /&gt;        for (int i = 0; i &amp;lt; this.animHandlers.size(); i++) {&lt;br /&gt;            paintText(g2, this.animHandlers.get(i).animProgress);&lt;br /&gt;        }&lt;br /&gt;        g2.dispose();&lt;br /&gt;    }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;paintText call  scrollTextUtils to find the x and y coordinates&lt;br /&gt;check if the coordinates are in the visible area&lt;br /&gt;get and set the rotation/font and then paint each character of the text&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;&lt;br /&gt;protected void paintText(final Graphics2D g2, final float animProgress) {&lt;br /&gt;        Font f = getFont();&lt;br /&gt;        for (int i = 0; i &amp;lt; this.text.length(); i++) {&lt;br /&gt;            int x = this.scrollTextUtils.getXpos(animProgress, i);&lt;br /&gt;            if (x &amp;lt; -f.getSize() || x &amp;gt; getWidth()) {&lt;br /&gt;                // do not paint, out of the visible bounds&lt;br /&gt;            } else {&lt;br /&gt;                int y = this.scrollTextUtils.getYpos(animProgress, i);&lt;br /&gt;                if (y &amp;lt; 0 || y &amp;gt; getHeight() + f.getSize()) {&lt;br /&gt;                    // do not paint, out of the visible bounds&lt;br /&gt;                } else {&lt;br /&gt;                    double angle = this.scrollTextUtils.getRotate(animProgress, i);&lt;br /&gt;                    g2.rotate(angle, x, y);&lt;br /&gt;                    g2.setFont(f.deriveFont(this.scrollTextUtils.getTransformedFontSize(animProgress, f.getSize(), i)));&lt;br /&gt;                    g2.translate(x, y);&lt;br /&gt;                    this.scrollTextUtils.paintCharacter(g2, String.valueOf(this.text.charAt(i)));&lt;br /&gt;                    g2.translate(-x, -y);&lt;br /&gt;                    g2.rotate(-angle, x, y);&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        g2.setFont(f);&lt;br /&gt;    }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;you can try it here &lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://free-the-pixel.dev.java.net/files/documents/10830/150667/ScrollingTextDemo.jnlp" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="https://free-the-pixel.dev.java.net/files/documents/10830/147686/webstart.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_MiO_FvhBBtA/TAq6ig_UZFI/AAAAAAAAAGg/81s1jU-RCcc/s1600/textScrolling.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_MiO_FvhBBtA/TAq6ig_UZFI/AAAAAAAAAGg/81s1jU-RCcc/s320/textScrolling.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;the full source code is available at &lt;a href="https://free-the-pixel.dev.java.net/source/browse/free-the-pixel/trunk/src/com/community/xanadu/components/text/ScrollingText.java"&gt;https://free-the-pixel.dev.java.net/source/browse/free-the-pixel/trunk/src/com/community/xanadu/components/text/ScrollingText.java&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3113056103202976131-7925026927300636045?l=free-the-pixel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://free-the-pixel.blogspot.com/feeds/7925026927300636045/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://free-the-pixel.blogspot.com/2010/06/scrolling-text.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3113056103202976131/posts/default/7925026927300636045'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3113056103202976131/posts/default/7925026927300636045'/><link rel='alternate' type='text/html' href='http://free-the-pixel.blogspot.com/2010/06/scrolling-text.html' title='Animated Scrolling text'/><author><name>Mabs</name><uri>http://www.blogger.com/profile/05193647092760468172</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_MiO_FvhBBtA/S0-XEk_aYnI/AAAAAAAAACA/1tm3UOOLGsQ/s1600-R/xanlogoshiny_trans_small.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_MiO_FvhBBtA/TAq6ig_UZFI/AAAAAAAAAGg/81s1jU-RCcc/s72-c/textScrolling.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3113056103202976131.post-6145633764450970739</id><published>2010-04-02T23:21:00.001+02:00</published><updated>2010-04-02T23:24:51.435+02:00</updated><title type='text'>GHOST drag and drop, over multiple windows</title><content type='html'>I guess many people seen the example(the photocollage application) from Romain Guy, when he was still playing with java, about ghost drag and drop using the glass pane to render the ghost image:&lt;br /&gt;&amp;nbsp;&lt;a href="http://www.jroller.com/gfx/entry/drag_and_drop_effects_the"&gt; http://www.jroller.com/gfx/entry/drag_and_drop_effects_the&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;One problem with this implementation is that it used the glasspane, a unique resource of a window.&lt;br /&gt;If that’s a problem for you, you can simply fix it by using JLayeredPane or JXlayer (I won’t talk about this implementation in this article).&lt;br /&gt;&lt;br /&gt;The biggest problem is (and even more lately considering that palettes/multi windows application are vastly used now), how to allow ghost DnD through multiple windows?&lt;br /&gt;You can easily imagine, in the photocollage application of Romain, that the photo thumbnails would be inside a different window than the drop location.&lt;br /&gt;To do that, it’s not possible to use any kind of trick that span over only a window to draw the ghost image.&lt;br /&gt;&lt;br /&gt;The solution I came up with is to use a non opaque window on which the ghost image is drawn and that is dragged around&lt;br /&gt;&lt;br /&gt;While implementing this solution I ran into a unexpected problem: the drop method from DropTarget was never call, so in the DragGestureListener.dragDropEnd(DragSourceDropEvent) , DragSourceDropEvent.getDropSuccess() was always returning false.&lt;br /&gt;I didn’t investigate much on that but I guess it’s because when the drop happen the cursor is over a window (the window where the ghost image is drawn) and not actually over the component that has the drop target.&lt;br /&gt;So my first fix for this, was to add an offset of 1 pixel between the cursor and the ghost window, it worked well. But what I actually wanted is to have the cursor in the middle of the ghost window.&lt;br /&gt;So the true problem was how to get the mouse event to be consumed by the component below the ghost window.&lt;br /&gt;At this time I remember the testing I have done with non opaque window, you could click through a non opaque window if nothing was painting were the click takes place.&lt;br /&gt;&lt;br /&gt;In the example below ,it contains 2 buttons with a bit of space between them, if you click between them the window will lose focus and it’s actually the component behind the window that will grab the focus.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_MiO_FvhBBtA/S7Zasom-39I/AAAAAAAAAGI/CMZgMse2gKk/s320/nonOpaqueWindow.PNG" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;&lt;br /&gt;JDialog d = new JDialog();&lt;br /&gt;WindowsUtils.setOpaque(d, false);&lt;br /&gt;JButton b1 = new JButton("button 1");&lt;br /&gt;JButton b2 = new JButton("button 2");&lt;br /&gt;d.getContentPane().setLayout(new FlowLayout());&lt;br /&gt;d.getContentPane().add(b1);&lt;br /&gt;d.getContentPane().add(b2);&lt;br /&gt;d.pack();&lt;br /&gt;d.setVisible(true);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;So how could I apply this to my ghost window?&lt;br /&gt;&lt;br /&gt;I need the mouse release event to get through the window, so that’s mean the pixel behind the cursor should not be painted. So that’s lead in my implementation to change the clip of the graphics when I am painting the image to keep away one pixel from being painted:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;Area a1 = new Area(getBounds());&lt;br /&gt;//remove the center point (where the cursor is)&lt;br /&gt;a1.subtract(new Area(new Rectangle(getWidth() / 2, getHeight() / 2, 1, 1)));&lt;br /&gt;g2.setClip(a1);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;The missing pixel is normaly not visible by the user as the cursor is over it, but you can see it by taking a screen shot that does not contain the cursor.&lt;br /&gt;&lt;br /&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_MiO_FvhBBtA/S7Za5H-y5BI/AAAAAAAAAGQ/eUw_Of4zPbk/s320/theMissingPixel.PNG" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;To allow a component to be drag:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;DnDGhostManager.enableDrag(JComponent,Transferable)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;to declare a drop location&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;DnDGhostManager.enableDrop(JComponent,DataFlavor,DnDSuccessCallBack)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;where DnDSuccessCallBack is an interface containing a single method&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;void dropSuccess(DataFlavor,DropTargetContext,Transferable,Point);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Demo:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_MiO_FvhBBtA/S7Zd8jWTE4I/AAAAAAAAAGY/pzZHtKn3jRI/s1600/DndDemo.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="211" src="http://2.bp.blogspot.com/_MiO_FvhBBtA/S7Zd8jWTE4I/AAAAAAAAAGY/pzZHtKn3jRI/s400/DndDemo.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://free-the-pixel.dev.java.net/files/documents/10830/149338/ghostDnD.jnlp" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="https://free-the-pixel.dev.java.net/files/documents/10830/147686/webstart.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3113056103202976131-6145633764450970739?l=free-the-pixel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://free-the-pixel.blogspot.com/feeds/6145633764450970739/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://free-the-pixel.blogspot.com/2010/04/ghost-drag-and-drop-over-multiple.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3113056103202976131/posts/default/6145633764450970739'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3113056103202976131/posts/default/6145633764450970739'/><link rel='alternate' type='text/html' href='http://free-the-pixel.blogspot.com/2010/04/ghost-drag-and-drop-over-multiple.html' title='GHOST drag and drop, over multiple windows'/><author><name>Mabs</name><uri>http://www.blogger.com/profile/05193647092760468172</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_MiO_FvhBBtA/S0-XEk_aYnI/AAAAAAAAACA/1tm3UOOLGsQ/s1600-R/xanlogoshiny_trans_small.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_MiO_FvhBBtA/S7Zasom-39I/AAAAAAAAAGI/CMZgMse2gKk/s72-c/nonOpaqueWindow.PNG' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3113056103202976131.post-363469891099794221</id><published>2010-03-14T16:11:00.000+01:00</published><updated>2010-03-14T16:11:31.762+01:00</updated><title type='text'>Substance L&amp;F: Button with multiline text</title><content type='html'>Usually when you need a button with text on multiple lines, you have to use html to format the text.&lt;br /&gt;&lt;br /&gt;This works fine, but as I am using Substance L&amp;amp;F, I ran into an unsupported featured concerning the foreground colour using html.&lt;br /&gt;First, let’s see how substance displays the text in a button.&lt;br /&gt;The foreground color depend of the button state (default,pressed,armed,…)&lt;br /&gt;There is an animated transition when switching state.&lt;br /&gt;&lt;br /&gt;When using html as text the htmlView won’t behave like normal text, I mean by that, that the foreground color will not change because the rendering is delegated to the basicHtml View and not to substance.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_MiO_FvhBBtA/S5z6a6X6jII/AAAAAAAAAFg/EPkz0rayxak/s1600-h/defaultSubstanceButonUIHtml.PNG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_MiO_FvhBBtA/S5z6a6X6jII/AAAAAAAAAFg/EPkz0rayxak/s320/defaultSubstanceButonUIHtml.PNG" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;SubstanceButtonUI default state with HTML text&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_MiO_FvhBBtA/S5z6gWCl0AI/AAAAAAAAAFo/O8fRrop7yUc/s1600-h/pressedSubstanceButonUIHtml.PNG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_MiO_FvhBBtA/S5z6gWCl0AI/AAAAAAAAAFo/O8fRrop7yUc/s320/pressedSubstanceButonUIHtml.PNG" /&gt;&lt;/a&gt;&lt;/div&gt;SubstanceButtonUI rollover state with HTML text, here you can barely see the text&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_MiO_FvhBBtA/S5z6ndCJbfI/AAAAAAAAAFw/ogl_Mehr-Rw/s1600-h/rolloverSubstanceButonUINormalText.PNG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_MiO_FvhBBtA/S5z6ndCJbfI/AAAAAAAAAFw/ogl_Mehr-Rw/s320/rolloverSubstanceButonUINormalText.PNG" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;SubstanceButtonUI default state with normal text&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;In most of the substance LAF, it’s not big a problem as the foreground color doesn’t change with the button state. But with some LAF as SubstanceMagellanLookAndFeel there is a problem as the text become barely readable during the rollover state.&lt;br /&gt;And even if it stay readable, it just seem strange that some buttons have a black foreground when rollover and some a white one as it’s the case for my custom substance LAF.&lt;br /&gt;&lt;br /&gt;So the plan was to make a custom SubstanceButtonUI to manage multiple text lines on JButton, without using the basic html rendering, using \n to split the text.&lt;br /&gt;&lt;br /&gt;There are 2 things to do:&lt;br /&gt;To split the text when it’s changing&lt;br /&gt;To paint the text&lt;br /&gt;&lt;br /&gt;Splitting the text&lt;br /&gt;Cache of the lines&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;&lt;br /&gt;private String[] splittedText = null;&lt;br /&gt;&lt;br /&gt;private class TextChangeListener implements PropertyChangeListener {&lt;br /&gt;        @Override&lt;br /&gt;public void propertyChange(final PropertyChangeEvent evt) {&lt;br /&gt;    if (evt.getNewValue() != null &amp;amp;&amp;amp; !evt.getNewValue().toString().isEmpty()) {&lt;br /&gt;        SubstanceMultiLineButtonUI.this.splittedText = evt.getNewValue().toString().split("\n");&lt;br /&gt;    } else {&lt;br /&gt;        SubstanceMultiLineButtonUI.this.splittedText = null;&lt;br /&gt;    }&lt;br /&gt;    SubstanceMultiLineButtonUI.this.button.repaint();&lt;br /&gt;}&lt;br /&gt;};&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Install the text change listener&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;@Override&lt;br /&gt;    protected void installListeners(final AbstractButton b) {&lt;br /&gt;        super.installListeners(b);&lt;br /&gt;        this.textChangeListener = new TextChangeListener();&lt;br /&gt;        b.addPropertyChangeListener("text", this.textChangeListener);&lt;br /&gt;    }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Painting:&lt;br /&gt;Loop through the lines&lt;br /&gt;Find the correct position to paint each line&lt;br /&gt;Paint the line using the paintButtonText from substanceButtonUI&lt;br /&gt;Find the correct position for the icon and paint it.&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;for (final String s : this.splittedText) {&lt;br /&gt;    viewRect.x = i.left;&lt;br /&gt;    viewRect.y = i.top;&lt;br /&gt;    viewRect.width = b.getWidth() - (i.right + viewRect.x);&lt;br /&gt;    viewRect.height = b.getHeight() - (i.bottom + viewRect.y);&lt;br /&gt;&lt;br /&gt;    textRect.x = textRect.y = textRect.width = textRect.height = 0;&lt;br /&gt;    iconRect.x = iconRect.y = iconRect.width = iconRect.height = 0;&lt;br /&gt;&lt;br /&gt;    String line = SwingUtilities.layoutCompoundLabel(c, fm, s, b.getIcon(), b.getVerticalAlignment(), b.getHorizontalAlignment(), b.getVerticalTextPosition(), b.getHorizontalTextPosition(), viewRect, iconRect, textRect, b.getText() == null ? 0 : b.getIconTextGap());&lt;br /&gt;&lt;br /&gt;    // find the icon location&lt;br /&gt;    if (b.getIcon() != null) {&lt;br /&gt;        if (trueIconRect.x != 0) {&lt;br /&gt;            trueIconRect.x = Math.min(trueIconRect.x, iconRect.x);&lt;br /&gt;        } else {&lt;br /&gt;            trueIconRect.x = iconRect.x;&lt;br /&gt;        }&lt;br /&gt;        trueIconRect.y = iconRect.y;&lt;br /&gt;        trueIconRect.width = iconRect.width;&lt;br /&gt;        trueIconRect.height = iconRect.height;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    //compute the text Y position&lt;br /&gt;    double part = fontMetrics.getStringBounds(line, g2).getHeight();&lt;br /&gt;    double y = 0.5 * this.button.getHeight();&lt;br /&gt;    y -= part * 0.5 * this.splittedText.length;&lt;br /&gt;    y += part * lineNumber;&lt;br /&gt;    textRect.y = (int) y;&lt;br /&gt;    //deletegate to substance&lt;br /&gt;this.paintButtonText(g2, b, textRect, line);&lt;br /&gt;                        &lt;br /&gt;    lineNumber++;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;//paint the icon&lt;br /&gt;if (b.getIcon() != null) {&lt;br /&gt;    if (this.splittedText==null||this.splittedText.length==0) {&lt;br /&gt;    // if no text&lt;br /&gt;        SwingUtilities.layoutCompoundLabel(c, fontMetrics, "", b.getIcon(), b.getVerticalAlignment(), b.getHorizontalAlignment(),viewRect, trueIconRect, textRect, b.getText() == null ? 0 : b.getIconTextGap());&lt;br /&gt;    }&lt;br /&gt;    paintIcon(g2, c, trueIconRect);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_MiO_FvhBBtA/S5z6v4a3YOI/AAAAAAAAAF4/DKYeSV1Riig/s1600-h/defaultMultilineSubstanceButonUI.PNG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_MiO_FvhBBtA/S5z6v4a3YOI/AAAAAAAAAF4/DKYeSV1Riig/s320/defaultMultilineSubstanceButonUI.PNG" /&gt;&lt;/a&gt;&lt;/div&gt;SubstanceMultiLineButtonUI default state&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_MiO_FvhBBtA/S5z62tYCpKI/AAAAAAAAAGA/KvIC3FqxmcU/s1600-h/rolloverMultilineSubstanceButonUI.PNG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_MiO_FvhBBtA/S5z62tYCpKI/AAAAAAAAAGA/KvIC3FqxmcU/s320/rolloverMultilineSubstanceButonUI.PNG" /&gt;&lt;/a&gt;&lt;/div&gt;SubstanceMultiLineButtonUI rollover state&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;To use this UI on a button:&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;JButton b = new JButton("Do this\nand that");&lt;br /&gt;b.setUI(new SubstanceMultiLineButtonUI(b));&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="https://free-the-pixel.dev.java.net/files/documents/10830/148762/multilineButtons.jnlp" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="https://free-the-pixel.dev.java.net/files/documents/10830/147686/webstart.png" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3113056103202976131-363469891099794221?l=free-the-pixel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://free-the-pixel.blogspot.com/feeds/363469891099794221/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://free-the-pixel.blogspot.com/2010/03/substance-l-button-with-multiline-text.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3113056103202976131/posts/default/363469891099794221'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3113056103202976131/posts/default/363469891099794221'/><link rel='alternate' type='text/html' href='http://free-the-pixel.blogspot.com/2010/03/substance-l-button-with-multiline-text.html' title='Substance L&amp;F: Button with multiline text'/><author><name>Mabs</name><uri>http://www.blogger.com/profile/05193647092760468172</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_MiO_FvhBBtA/S0-XEk_aYnI/AAAAAAAAACA/1tm3UOOLGsQ/s1600-R/xanlogoshiny_trans_small.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_MiO_FvhBBtA/S5z6a6X6jII/AAAAAAAAAFg/EPkz0rayxak/s72-c/defaultSubstanceButonUIHtml.PNG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3113056103202976131.post-2212554193982897609</id><published>2010-03-01T19:39:00.001+01:00</published><updated>2010-03-01T21:59:11.030+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='swing'/><category scheme='http://www.blogger.com/atom/ns#' term='toggleButton'/><title type='text'>Customs Toggle buttons</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;First I will talk about why I ended up creating this customs jtoggle button.&lt;br /&gt;&lt;br /&gt;I was asked, what would be the best way to show a choice among 2 available options (option A or option B).&lt;br /&gt;&lt;br /&gt;Usually when you want the user to select one option among a few (let’s say less than 5) you can use some JRadioButton/JCheckBox/JToggleButton.&lt;br /&gt;JCombobox/JList are usually used if you have more possible options, doesn’t really make sense (at least for me) to have a JComboBox/JList with only 2 or 3 available options &lt;br /&gt;&lt;br /&gt;I had to show the icon corresponding to each of the 2 options.&lt;br /&gt;I could have used JRadioButton + a JLabel (to show the icon) or a JToggleButton. &lt;br /&gt;The image being quiet big (&amp;gt; 100*100 pixels), using a JToggleButton is just wrong and plain ugly for this kind of icon.&lt;br /&gt;So my only option left was to use a JRadioButton with a JLabel to show the icon.&lt;br /&gt;&lt;br /&gt;After some tests, I wasn’t really satisfied about how it looked.&lt;br /&gt;I really don’t like the look of the selected/unselected icon sticked to the icon representing the option.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_MiO_FvhBBtA/S4wCnVazJ-I/AAAAAAAAAE4/9CRnDtbauPA/s1600-h/RadioButton.PNG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_MiO_FvhBBtA/S4wCnVazJ-I/AAAAAAAAAE4/9CRnDtbauPA/s320/RadioButton.PNG" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So I though why not use directly the image as component with some kind of visual feedback apply to the image (and not outside like for the JRadioButton)&lt;br /&gt;&lt;br /&gt;The visual feedbacks I considered for this are the following:&lt;br /&gt;-translucent if not selected&lt;br /&gt;-smaller image if not selected&lt;br /&gt;-a selection ring&lt;br /&gt;And of course it should have animated transition between selected/unselected state switch&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You can find the implementation at: &lt;a href="https://free-the-pixel.dev.java.net/source/browse/free-the-pixel/trunk/src/com/community/xanadu/components/buttons/toggleButtons/ShrinkingToggleImageButton.java"&gt;ShrinkingToggleImageButton&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_MiO_FvhBBtA/S4wDHe5KUdI/AAAAAAAAAFA/uE17UvT9D2E/s1600-h/ShrinkingToggleImageButton1.PNG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="122" src="http://2.bp.blogspot.com/_MiO_FvhBBtA/S4wDHe5KUdI/AAAAAAAAAFA/uE17UvT9D2E/s400/ShrinkingToggleImageButton1.PNG" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Some time later, I needed to have a panel to select among 3 options, but this time there was no icon. So I should have just used 3 JRadioButton and be done with it. But considering the application is running on a device with touch-screen and that selecting an option trigger a big change in the screen, it made more sense to have JToggleButton used there.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_MiO_FvhBBtA/S4wDTD2whrI/AAAAAAAAAFI/dAd8iEwX7eo/s1600-h/JtoggleButtonSideBySide.PNG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_MiO_FvhBBtA/S4wDTD2whrI/AAAAAAAAAFI/dAd8iEwX7eo/s320/JtoggleButtonSideBySide.PNG" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;As having 3 JToggleButton side by side doesn’t look that great, I decided to see If I could get something that make sense with a better look.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I rapidly decided to try using ShrinkingToggleImageButton, after playing a bit to create the image, I came up with the following result.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_MiO_FvhBBtA/S4wDhHdpjzI/AAAAAAAAAFQ/SYE57FQEeWo/s1600-h/ToggleImageButtonText2.PNG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_MiO_FvhBBtA/S4wDhHdpjzI/AAAAAAAAAFQ/SYE57FQEeWo/s320/ToggleImageButtonText2.PNG" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I was happy about the result, it looks way better on the screen it’s used on, than some JRadioButton/JToggleButton.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Some time later, I needed a way to select options among 3 again, but this time it had an icon + some text, as I had the same constraints (touch-screen – big buttons needed), I started to play again with ShrinkingToggleImageButton.&lt;br /&gt;&lt;br /&gt;This time I created a class to hold this component, instead of just giving the right image to the shrinkingToggleImageButton: &lt;a href="https://free-the-pixel.dev.java.net/source/browse/free-the-pixel/trunk/src/com/community/xanadu/components/buttons/toggleButtons/ShrinkingToggleImageAndTextButton.java"&gt;ShrinkingToggleImageAndTextButton&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Also it can deal with multiple line text, use \n to wrap to the next line&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_MiO_FvhBBtA/S4wDrEisKmI/AAAAAAAAAFY/Wqr_sQ8Hpu4/s1600-h/ShrinkingToggleImageAndTextButton.PNG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="400" src="http://3.bp.blogspot.com/_MiO_FvhBBtA/S4wDrEisKmI/AAAAAAAAAFY/Wqr_sQ8Hpu4/s400/ShrinkingToggleImageAndTextButton.PNG" width="346" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span id="goog_1267467232976"&gt;&lt;/span&gt;&lt;span id="goog_1267467232977"&gt;&lt;/span&gt;&lt;a href="http://www.blogger.com/"&gt;&lt;/a&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;a href="https://free-the-pixel.dev.java.net/files/documents/10830/148362/ToggleImageButtonDemo.jnlp" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="https://free-the-pixel.dev.java.net/files/documents/10830/147686/webstart.png" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3113056103202976131-2212554193982897609?l=free-the-pixel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://free-the-pixel.blogspot.com/feeds/2212554193982897609/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://free-the-pixel.blogspot.com/2010/03/customs-toggle-buttons.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3113056103202976131/posts/default/2212554193982897609'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3113056103202976131/posts/default/2212554193982897609'/><link rel='alternate' type='text/html' href='http://free-the-pixel.blogspot.com/2010/03/customs-toggle-buttons.html' title='Customs Toggle buttons'/><author><name>Mabs</name><uri>http://www.blogger.com/profile/05193647092760468172</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_MiO_FvhBBtA/S0-XEk_aYnI/AAAAAAAAACA/1tm3UOOLGsQ/s1600-R/xanlogoshiny_trans_small.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_MiO_FvhBBtA/S4wCnVazJ-I/AAAAAAAAAE4/9CRnDtbauPA/s72-c/RadioButton.PNG' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3113056103202976131.post-3190347496830669864</id><published>2010-02-11T18:18:00.005+01:00</published><updated>2010-02-11T22:29:38.334+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='jtable'/><category scheme='http://www.blogger.com/atom/ns#' term='swing'/><title type='text'>Bean reader JTable</title><content type='html'>I have already written about JTable on this blog, a lot can be written about it.&lt;br /&gt;This time I will talk about a custom jtable I developed in order to have the simplest way to show READ ONLY data.&lt;br /&gt;&lt;br /&gt;First how I was coding before:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&lt;br /&gt;class Person{&lt;br /&gt;String firstName;&lt;br /&gt;String lastName;&lt;br /&gt;/*..*/&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;DefaultTableModel dtm= new DefaultTableModel();&lt;br /&gt;for(Person p: getListPersons()){&lt;br /&gt;Dtm.add(new Object[]{p.getFirstName(),p.getLastName()});&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;Dtm.addColumn(“firstName”);&lt;br /&gt;Dtm.addColumn(“lastName”);&lt;br /&gt;&lt;br /&gt;JTable table=new JTable();&lt;br /&gt;table.setModel(dtm);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And to know which Object is currently selected:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;Int index=table.getSelectedIndex();&lt;br /&gt;Int modelIndex=table.convertRowIndexToModel(index);&lt;br /&gt;Person selected=getListPersons.get(modelIndex);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;After coding this way too many time I wondered:&lt;br /&gt;As we only show only one kind of object in the table, wouldn’t it be easier:&lt;br /&gt;to have a table of T&lt;br /&gt;to be able to add/remove a T&lt;br /&gt;to be able to get the selected T&lt;br /&gt;All this without coding a custom JTable or/and TableModel each time&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So the plan is to have an easy way to&lt;br /&gt;-Define the class of objects to show using the JTable&lt;br /&gt;-Define the columns&lt;br /&gt;-Add/remove an object from the table&lt;br /&gt;-Get the selected objects&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So now let’s see the implementation I called BeanReaderJTable&lt;br /&gt;&lt;br /&gt;First we need a generic parameter&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;public class BeanReaderJTable&amp;lt;T&amp;gt; extends JTable {/*…*/}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The contructor take the field names and the column names you want as header value.&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&lt;br /&gt;public BeanReaderJTable(String[] fields, String[] title)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Adding/removing a row or getting the selected objects can’t be easier:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;addRow(T)&lt;br /&gt;addRow(T[])&lt;br /&gt;addRow(Collection&amp;lt;T&amp;gt;)&lt;br /&gt;removeRow(T)&lt;br /&gt;getSelectedObject():T&lt;br /&gt;getSelectedObjects():T[]&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;What is doing the actual job is the GenericTableModel.&lt;br /&gt;The important job is done in getValueAt(int,int). The reflexion API is used to retrieve the value of a given pair field+row&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Now let’s see a sample:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;// declare the type + fields+column title&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;String[] fields = new String[] { "size", "size.width", "size.height", "class", "visible", null };&lt;br /&gt;String[] titles = new String[] { "size", "width", "height", "class", "is visible", null };&lt;br /&gt;BeanReaderJTable&amp;lt;Component&amp;gt; table = new BeanReaderJTable&amp;lt;Component&amp;gt;(fields, titles);&lt;br /&gt;//populate the table&lt;br /&gt;table.addRow(getAllComponents(frame));&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;You may have noticed, I left the last field empty, doing so, an empty column is created that can be used to set for example a button cell editor&lt;br /&gt;&lt;br /&gt;And also what you can see, is that you can access nested field like size.width&lt;br /&gt;&lt;br /&gt;This time you should actually be able to access the code source repository, my java.net project has been approved:&lt;br /&gt;&lt;a href="https://free-the-pixel.dev.java.net/source/browse/free-the-pixel/trunk/src/com/community/xanadu/components/table/BeanReaderJTable.java"&gt;BeanReaderJTable&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_MiO_FvhBBtA/S3Q9ZgwwhXI/AAAAAAAAAEw/wR0qU3ktNFw/s1600-h/BeanReaderJTable.PNG"&gt;&lt;img style="cursor: pointer; width: 459px; height: 172px;" src="http://1.bp.blogspot.com/_MiO_FvhBBtA/S3Q9ZgwwhXI/AAAAAAAAAEw/wR0qU3ktNFw/s400/BeanReaderJTable.PNG" alt="" id="BLOGGER_PHOTO_ID_5437038158643496306" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://free-the-pixel.dev.java.net/files/documents/10830/147861/beanReaderJTable.jnlp"&gt;&lt;img style="cursor: pointer; width: 88px; height: 23px;" src="https://free-the-pixel.dev.java.net/files/documents/10830/147686/webstart.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3113056103202976131-3190347496830669864?l=free-the-pixel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://free-the-pixel.blogspot.com/feeds/3190347496830669864/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://free-the-pixel.blogspot.com/2010/02/bean-reader-jtable.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3113056103202976131/posts/default/3190347496830669864'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3113056103202976131/posts/default/3190347496830669864'/><link rel='alternate' type='text/html' href='http://free-the-pixel.blogspot.com/2010/02/bean-reader-jtable.html' title='Bean reader JTable'/><author><name>Mabs</name><uri>http://www.blogger.com/profile/05193647092760468172</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_MiO_FvhBBtA/S0-XEk_aYnI/AAAAAAAAACA/1tm3UOOLGsQ/s1600-R/xanlogoshiny_trans_small.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_MiO_FvhBBtA/S3Q9ZgwwhXI/AAAAAAAAAEw/wR0qU3ktNFw/s72-c/BeanReaderJTable.PNG' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3113056103202976131.post-5034212649313232973</id><published>2010-02-07T20:44:00.011+01:00</published><updated>2010-02-07T21:50:01.476+01:00</updated><title type='text'>Closing windows in style</title><content type='html'>This week some fun stuff!&lt;br /&gt;&lt;br /&gt;In the post about dialog with drop shadow i mentioned the class WindowFadeInManager to open or close a window with a fadein / fadeout effect, but there is another way to close window in style.&lt;br /&gt;&lt;br /&gt;First, don’t make me say what I didn’t, &lt;span style="font-weight: bold;"&gt;such close transitions should not be used on every windows&lt;/span&gt; in your app, if you do it will just annoy the user.&lt;br /&gt;I usually use them to close loading/splash/main frame of an application.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The base class where all the main work is done is&lt;br /&gt;&lt;a href="https://free-the-pixel.dev.java.net/source/browse/free-the-pixel/trunk/src/com/community/xanadu/components/transition/CloseTransition.java"&gt;CloseTransition&lt;/a&gt; , it’s an abstract class where the only abstract method is&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;protected abstract void paintImage(Graphics g,float animFraction);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This method is responsible of drawing the closing window for a given animation fraction (from 0 to 1)&lt;br /&gt;&lt;br /&gt;The CloseTransition class take care of making a screenshot of the actual window that will get closed. Then it starts the close animation.&lt;br /&gt;&lt;br /&gt;So what to do in this paintImage method?&lt;br /&gt;One easy thing is to show that a window is closing via shapes. For example simply by making the window shrink.&lt;br /&gt;&lt;br /&gt;This is done by extending the ShapeTransition class.&lt;br /&gt;This class has one abstract method:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;public abstract Shape getShape(float animFraction);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This method will get called to set the clip before painting the image of the closing window. There is also an option to automaticly shrink the image of the closing screen.&lt;br /&gt;So to create a close transition, this method will have to return an empty shape when animFraction=1 and a shape that cover totally the original window when animFraction=0&lt;br /&gt;&lt;br /&gt;By default in the ShapeTransition the original window is painted with an alpha value of 1-animfraction to make the window disappear smoothly, you can change this behaviour by setting the fadeout property to false.&lt;br /&gt;&lt;br /&gt;In the repository you will find the following implementation of &lt;a href="https://free-the-pixel.dev.java.net/source/browse/free-the-pixel/trunk/src/com/community/xanadu/components/transition/impl/"&gt;close transitions&lt;/a&gt;:&lt;br /&gt;ShrinkTransition&lt;br /&gt;CircleTransition&lt;br /&gt;RectanglesTransition (the one I use in my apps)&lt;br /&gt;FadeOutTransition&lt;br /&gt;RotationTransition&lt;br /&gt;PinchTransition, the funniest one, only work well on small window&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;To start a close transition you can follow this example:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;myFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);&lt;br /&gt;myFrame.addWindowListener(new WindowAdapter() {&lt;br /&gt;@Override&lt;br /&gt;public void windowClosing(WindowEvent e) {&lt;br /&gt;RectanglesTransition transition = new RectanglesTransition(myFrame);&lt;br /&gt;transition.startCloseTransition();&lt;br /&gt;}&lt;br /&gt;});&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;By default the action at the end of the transition is system.exit(0); because those close transitions are meant to be used to close main frame of an application but anyway you can set the end action:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;transition.setEndAction(AbstractAction);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_MiO_FvhBBtA/S28csyMLT9I/AAAAAAAAAEQ/nRerVGGjzy4/s1600-h/CloseTransitionRectangles.PNG"&gt;&lt;img style="cursor: pointer; width: 400px; height: 243px;" src="http://4.bp.blogspot.com/_MiO_FvhBBtA/S28csyMLT9I/AAAAAAAAAEQ/nRerVGGjzy4/s400/CloseTransitionRectangles.PNG" alt="" id="BLOGGER_PHOTO_ID_5435594830972145618" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_MiO_FvhBBtA/S28cx0nq8bI/AAAAAAAAAEY/t4Y4BJKDcxc/s1600-h/CloseTransitionRotate.PNG"&gt;&lt;img style="cursor: pointer; width: 320px; height: 235px;" src="http://3.bp.blogspot.com/_MiO_FvhBBtA/S28cx0nq8bI/AAAAAAAAAEY/t4Y4BJKDcxc/s400/CloseTransitionRotate.PNG" alt="" id="BLOGGER_PHOTO_ID_5435594917523681714" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_MiO_FvhBBtA/S28c2F6hC0I/AAAAAAAAAEg/FJ2MSWmnrXE/s1600-h/CloseTransitionPinch.PNG"&gt;&lt;img style="cursor: pointer; width: 400px; height: 251px;" src="http://3.bp.blogspot.com/_MiO_FvhBBtA/S28c2F6hC0I/AAAAAAAAAEg/FJ2MSWmnrXE/s400/CloseTransitionPinch.PNG" alt="" id="BLOGGER_PHOTO_ID_5435594990885604162" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://free-the-pixel.dev.java.net/files/documents/10830/147684/CloseTransitionDemo.jnlp"&gt;&lt;img style="cursor: pointer; width: 88px; height: 23px;" src="https://free-the-pixel.dev.java.net/files/documents/10830/147686/webstart.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3113056103202976131-5034212649313232973?l=free-the-pixel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://free-the-pixel.blogspot.com/feeds/5034212649313232973/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://free-the-pixel.blogspot.com/2010/02/closing-windows-with-style.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3113056103202976131/posts/default/5034212649313232973'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3113056103202976131/posts/default/5034212649313232973'/><link rel='alternate' type='text/html' href='http://free-the-pixel.blogspot.com/2010/02/closing-windows-with-style.html' title='Closing windows in style'/><author><name>Mabs</name><uri>http://www.blogger.com/profile/05193647092760468172</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_MiO_FvhBBtA/S0-XEk_aYnI/AAAAAAAAACA/1tm3UOOLGsQ/s1600-R/xanlogoshiny_trans_small.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_MiO_FvhBBtA/S28csyMLT9I/AAAAAAAAAEQ/nRerVGGjzy4/s72-c/CloseTransitionRectangles.PNG' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3113056103202976131.post-1661873178014045127</id><published>2010-02-05T23:07:00.003+01:00</published><updated>2010-02-06T13:03:38.589+01:00</updated><title type='text'>Moving to java.dev.net</title><content type='html'>As kenai is closing i am moving my code repository to &lt;a href="https://free-the-pixel.dev.java.net/"&gt;https://free-the-pixel.dev.java.net&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;edit:&lt;br /&gt;here is the mail i got a few hours after migrating to java.net :&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;In an effort to get information out to the Kenai community quickly, while trying to manage the integration of our two companies, I think we did a poor job at communicating our plans for Kenai.com to you.  I would like to remedy that now.  Our strategy is simple.  We don't believe it makes sense to continue investing in multiple hosted development sites that are basically doing the same thing.  Our plan is to shut down kenai.com and focus our efforts on java.net as the hosted development community.  We are in the process of migrating java.net to the kenai technology.  This means that any project currently hosted on kenai.com will be able to continue as you are on java.net.  We are still working out the technical details, but the goal is to make this migration as seamless as possible for the current kenai.com projects.  So in the meantime I suggest that you stay put on kenai.com and let us work through the details and get back to you later this month. &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Thanks for your feedback and patience.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Ted Farrell&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Oracle Corporation&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;that's great news,&lt;br /&gt;well i did the manual migrating to java.net but i won't complain i didn t have so many stuff  as i only started begining on this years.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3113056103202976131-1661873178014045127?l=free-the-pixel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://free-the-pixel.blogspot.com/feeds/1661873178014045127/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://free-the-pixel.blogspot.com/2010/02/moving-to-javadevnet.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3113056103202976131/posts/default/1661873178014045127'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3113056103202976131/posts/default/1661873178014045127'/><link rel='alternate' type='text/html' href='http://free-the-pixel.blogspot.com/2010/02/moving-to-javadevnet.html' title='Moving to java.dev.net'/><author><name>Mabs</name><uri>http://www.blogger.com/profile/05193647092760468172</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_MiO_FvhBBtA/S0-XEk_aYnI/AAAAAAAAACA/1tm3UOOLGsQ/s1600-R/xanlogoshiny_trans_small.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3113056103202976131.post-8432315028731531097</id><published>2010-01-28T17:47:00.011+01:00</published><updated>2010-02-05T22:58:56.724+01:00</updated><title type='text'>Table and actions.</title><content type='html'>If you have been developing client software you certainly already ran into the following situation:&lt;br /&gt;You have a table full of data, each line corresponding to an object you can interact with. Where and how should I put buttons for this purpose?&lt;br /&gt;&lt;br /&gt;I will explore several implementations in order to handle this situation.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Cell editors/renderer&lt;/span&gt;s&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_MiO_FvhBBtA/S2HDUyB3tzI/AAAAAAAAADg/hAP956QDTS8/s1600-h/buttonsCellEditors.png"&gt;&lt;img style="cursor: pointer; width: 358px; height: 121px;" src="http://2.bp.blogspot.com/_MiO_FvhBBtA/S2HDUyB3tzI/AAAAAAAAADg/hAP956QDTS8/s400/buttonsCellEditors.png" alt="" id="BLOGGER_PHOTO_ID_5431837387379947314" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This way is often seen to handle this situation, you have to add one column per action, and then the button will appear on each line thanks to a cell renderer/editor.&lt;br /&gt;I don’t find it really appealing visually, because repeating the same button over and over again on each line seems wrong to me, but at least it’s easy to see that the action on the button will be applied to the selected row.&lt;br /&gt;Adding columns + most likely increasing the row height (to display properly an icon) are a waste of space if you don’t have so much of it at first.&lt;br /&gt;&lt;br /&gt;I know by experience that developers that do not understand swing correctly (well, that’s a nice 99% of the people I worked with) tend to fail miserably at writing cell renderer/editor, is why I tried not to advice people to use custom cell editor/renderer.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Buttons outside the table&lt;/span&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_MiO_FvhBBtA/S2HDasemmvI/AAAAAAAAADw/GI7r5hPGd8w/s1600-h/outsideButtons.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 74px;" src="http://4.bp.blogspot.com/_MiO_FvhBBtA/S2HDasemmvI/AAAAAAAAADw/GI7r5hPGd8w/s400/outsideButtons.png" alt="" id="BLOGGER_PHOTO_ID_5431837488969063154" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;It’s possible to add buttons somewhere on the screen that will do something related to the selected row in the table, that’s the easiest solution. The main problem of this implementation is that buttons are actually outside the table and hence that the buttons are not yet directly linked to the selected row, it might confuse the user.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Popup menu&lt;/span&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_MiO_FvhBBtA/S2HDhYkoNiI/AAAAAAAAAEI/axTwf7Vjgdg/s1600-h/popupButtons.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 111px;" src="http://1.bp.blogspot.com/_MiO_FvhBBtA/S2HDhYkoNiI/AAAAAAAAAEI/axTwf7Vjgdg/s400/popupButtons.png" alt="" id="BLOGGER_PHOTO_ID_5431837603884709410" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Right click on the table to show a popup menu&lt;br /&gt;This one is also an easy solution.&lt;br /&gt;The main drawback of this solution is that at first the user has no idea there is actions available on the selected row via a popup menu&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Overlay buttons&lt;/span&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_MiO_FvhBBtA/S2HDfc2vQsI/AAAAAAAAAEA/W4VxUEmvXfk/s1600-h/overlayButtons.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 112px;" src="http://4.bp.blogspot.com/_MiO_FvhBBtA/S2HDfc2vQsI/AAAAAAAAAEA/W4VxUEmvXfk/s400/overlayButtons.png" alt="" id="BLOGGER_PHOTO_ID_5431837570674672322" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;So far the main drawbacks of the above solutions are: buttons not directly linked to the selected row, popup not visible at first, repeating the same button again and again.&lt;br /&gt;So why not try to come with a solution that will meet the following requirement:&lt;br /&gt;Only one button per action visible at the same time, linked to the selected row.&lt;br /&gt;Let’s have a look at the outside button way. What was is main problem? The buttons are not linked to the selected row. So how would it be possible to link it?&lt;br /&gt;&lt;br /&gt;The solution I came up with is to use a JLayeredPane to position the buttons next to the selected row: &lt;a href="https://free-the-pixel.dev.java.net/source/browse/free-the-pixel/trunk/src/com/community/xanadu/components/table/PanelTableWithOverlayButtons.java"&gt;here&lt;span style="text-decoration: underline;"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Mixed approach&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;What happen now if there are more than 2 actions, so 2+ buttons.&lt;br /&gt;The cell renderer approach will need more even more column, so even more space wasted.&lt;br /&gt;The button overlay approach will also need some space to show the button, and the furthest button will not seems so much connected to the selected row&lt;br /&gt;&lt;br /&gt;Only the popup approach is behaving well in this case, but at the same time it’s not user friendly as the possibility to see the popup is not explicit.&lt;br /&gt;&lt;br /&gt;(I am not talking about the buttons outside the table way because I consider it not user friendly, because of how unrelated are the buttons with the table)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So why not mixed the popup approach with the 2 others?&lt;br /&gt;&lt;br /&gt;Popup + cell renderer/editor  /  Popup + overlay button&lt;br /&gt;The principle is the same in both approach, that is, to show a button that say “click me to see the popup” and put it either as a cell renderer or as an overlay button.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_MiO_FvhBBtA/S2HDc6gxHaI/AAAAAAAAAD4/-DsOiTDkbrM/s1600-h/overlayAndPopupButtons.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 108px;" src="http://4.bp.blogspot.com/_MiO_FvhBBtA/S2HDc6gxHaI/AAAAAAAAAD4/-DsOiTDkbrM/s400/overlayAndPopupButtons.png" alt="" id="BLOGGER_PHOTO_ID_5431837527095975330" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_MiO_FvhBBtA/S2HDXzUPU8I/AAAAAAAAADo/rYU7XSWA_Uw/s1600-h/cellEditorAndPopupButtons.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 117px;" src="http://2.bp.blogspot.com/_MiO_FvhBBtA/S2HDXzUPU8I/AAAAAAAAADo/rYU7XSWA_Uw/s400/cellEditorAndPopupButtons.png" alt="" id="BLOGGER_PHOTO_ID_5431837439265035202" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You can find all the above implementations &lt;a href="https://free-the-pixel.dev.java.net/source/browse/free-the-pixel/trunk/src/com/community/xanadu/demo/components/TableAndActionsDemo.java"&gt;here&lt;/a&gt;&lt;br /&gt;&lt;a href="http://kenai.com/projects/mabs-swing/sources/source-code-repository/content/FreeThePixel/src/com/community/xanadu/demo/components/TableAndActionsDemo.java"&gt;&lt;/a&gt;&lt;br /&gt;web start demo:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://free-the-pixel.dev.java.net/files/documents/10830/147683/TableActions.jnlp"&gt;&lt;img style="cursor: pointer; width: 88px; height: 23px;" src="https://free-the-pixel.dev.java.net/files/documents/10830/147686/webstart.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://kenai.com/projects/mabs-swing/downloads/download/jnlp/TableActions.jnlp"&gt;&lt;br /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3113056103202976131-8432315028731531097?l=free-the-pixel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://free-the-pixel.blogspot.com/feeds/8432315028731531097/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://free-the-pixel.blogspot.com/2010/01/table-and-actions.html#comment-form' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3113056103202976131/posts/default/8432315028731531097'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3113056103202976131/posts/default/8432315028731531097'/><link rel='alternate' type='text/html' href='http://free-the-pixel.blogspot.com/2010/01/table-and-actions.html' title='Table and actions.'/><author><name>Mabs</name><uri>http://www.blogger.com/profile/05193647092760468172</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_MiO_FvhBBtA/S0-XEk_aYnI/AAAAAAAAACA/1tm3UOOLGsQ/s1600-R/xanlogoshiny_trans_small.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_MiO_FvhBBtA/S2HDUyB3tzI/AAAAAAAAADg/hAP956QDTS8/s72-c/buttonsCellEditors.png' height='72' width='72'/><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3113056103202976131.post-3890032652799804044</id><published>2010-01-21T18:29:00.017+01:00</published><updated>2010-02-05T22:53:48.937+01:00</updated><title type='text'>Validation overlays</title><content type='html'>What I mean validation is for example to have an error icon in a corner of a text field if the input is wrong.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_MiO_FvhBBtA/S1iPnVJdk-I/AAAAAAAAADA/WC1BLTFPLcU/s1600-h/sample.PNG"&gt;&lt;img style="cursor: pointer; width: 223px; height: 36px;" src="http://1.bp.blogspot.com/_MiO_FvhBBtA/S1iPnVJdk-I/AAAAAAAAADA/WC1BLTFPLcU/s320/sample.PNG" alt="" id="BLOGGER_PHOTO_ID_5429247256649634786" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Like a year ago I read a serie of articles about validation overlays on Kirill Grouchnikov blog at &lt;a href="http://www.pushing-pixels.org/?p=69"&gt;http://www.pushing-pixels.org/?p=69&lt;/a&gt;  that I really encourage you to read to have some information/idea how this can be implemented. I came to the conclusion that there were only easy 2 ways of doing this, using glasspane or jxlayer.&lt;br /&gt;The glasspane suffer a performance issue and by the fact that there is only 1 glasspane per window.&lt;br /&gt;JXlayer only drawback is that you can’t put the icon outside of the component.&lt;br /&gt;&lt;br /&gt;One day I noticed that &lt;a href="https://jide-oss.dev.java.net/"&gt;jide &lt;/a&gt;provide an easy way to add an overlay component to any component.&lt;br /&gt;There is one problem although with jide you have to override the paintComponent Method(and add the required code) of each component you want to have the overlay component.&lt;br /&gt;That’s a constraint I really didn’t want to deal with to have validation overlays, that’s make the code too complicated/unreadable&lt;br /&gt;&lt;br /&gt;If you don’t override the paint method, the error icon won’t get repainted after the overlaid component, so the result is that the error icon will be partially/totally hidden by the overlaid component.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_MiO_FvhBBtA/S1iPq-tp5yI/AAAAAAAAADI/Llwa6xOUdfU/s1600-h/iconNotRepainted.PNG"&gt;&lt;img style="cursor: pointer; width: 222px; height: 32px;" src="http://3.bp.blogspot.com/_MiO_FvhBBtA/S1iPq-tp5yI/AAAAAAAAADI/Llwa6xOUdfU/s320/iconNotRepainted.PNG" alt="" id="BLOGGER_PHOTO_ID_5429247319346898722" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So the idea was to have a way to repaint the error icon each time the overlaid component is painted without to have to override the paintcomponent method of each overlaid component.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I came up with the idea to wrap the jide overlayable component inside a JXLayer, and to call the paint component of the overlay component inside the paint layer of the jxlayer, and Voila! Now we have the better of the 2 worlds: the error icon can be outside out the overlaid component and the error icon will be repainted each time the overlaid component does.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The error icon appears/disappear with a smooth animation as I like it.&lt;br /&gt;The icon is a true component so it can have a tooltip, in our case the tooltip will be the error message.&lt;br /&gt;You can change the default error icon for all or for one component:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;ValidationPanelIcon.setDefaultIcon(BufferedImage)&lt;br /&gt;ValidationOverlay.setIcon(BufferedImage newicon)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;You can change the default location of the icon:&lt;br /&gt;By changing the values of&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;ValidationPanelIcon.DEFAULT_XOFFSET&lt;br /&gt;ValidationPanelIcon.DEFAULT_YOFFSET&lt;br /&gt;ValidationPanelIcon.DEFAULT_ICON_LOCATION&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Or by calling&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;ValidationIOverlay.setIconLocation(int xoffset, int yoffset, int location)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;As there is a JXlayer in use, why not also us it fully and paint something on the layer?&lt;br /&gt;&lt;br /&gt;You can specify a ValidationPaint :&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;ValidationIOverlay.setPaint(ValidationPaint)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;ValidationPaint is an abstact class with the following method:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&lt;br /&gt;/**&lt;br /&gt;*&lt;br /&gt;* @param g&lt;br /&gt;* @param msg the list of error message&lt;br /&gt;* @param width width of the layer&lt;br /&gt;* @param height height of the layer&lt;br /&gt;* @param animProgress goes from 0 to 1 and then from 1 to 0, the duration of the animation can be set using ValidationOverlay.setAnimationDuration&lt;br /&gt;*/&lt;br /&gt;public abstract void paint(Graphics2D g, List&amp;lt;String&amp;gt; msg, JXLayer&amp;lt;JComponent&amp;gt; layer, float animProgress);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;A default implementation is available :&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;ValidationPaint.getColorValidationPaint(Color)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;This default implementation paint a rectangle over the component of the given color with a blink animation&lt;br /&gt;&lt;br /&gt;As an example with a custom ValidationPaint it’s possible to write the error messages directly on the layer&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_MiO_FvhBBtA/S1iPtfl1u6I/AAAAAAAAADQ/_vSoP4bmLtM/s1600-h/CustomValidationPaint.PNG"&gt;&lt;img style="cursor: pointer; width: 289px; height: 53px;" src="http://1.bp.blogspot.com/_MiO_FvhBBtA/S1iPtfl1u6I/AAAAAAAAADQ/_vSoP4bmLtM/s320/CustomValidationPaint.PNG" alt="" id="BLOGGER_PHOTO_ID_5429247362532228002" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;ValidationOverlayFactory&lt;br /&gt;&lt;br /&gt;To create the validation component use ValidationOverlayFactory:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;createBlinking(T, List&amp;lt;Validator&amp;lt;T&amp;gt;&amp;gt;)&lt;br /&gt;createBlinking(T, Validator&amp;lt;T&amp;gt;)&lt;br /&gt;createBlinkingAndIcon(T, Validator&amp;lt;T&amp;gt;)&lt;br /&gt;createBlinkingAndIconComponent(T, List&amp;lt;Validator&amp;lt;T&amp;gt;&amp;gt;)&lt;br /&gt;createErrorOverlayedIcon(T, List&amp;lt;Validator&amp;lt;T&amp;gt;&amp;gt;)&lt;br /&gt;createErrorOverlayedIcon(T, Validator&amp;lt;T&amp;gt;)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Validator is a simple interface&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;public interface Validator&amp;lt;T extends JComponent&amp;gt; {&lt;br /&gt;String validate(T comp);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The validate method should return the error message or null if no error has been detected.&lt;br /&gt;&lt;br /&gt;To execute the validator you have to call&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;ValidationOverlayFactory.validate(JComponent)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;The jcomponent given to this method is your original component on wich you add the overlay&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;TextValidationOverlayFactory is a facility class to create validation overlaid component for text component, it installs automatically a listener to call ValidationOverlayFactory.check on a text changed.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_MiO_FvhBBtA/S1iPwVivpwI/AAAAAAAAADY/_cxF-en_ItI/s1600-h/validationOverlayDemo.PNG"&gt;&lt;img style="cursor: pointer; width: 400px; height: 313px;" src="http://3.bp.blogspot.com/_MiO_FvhBBtA/S1iPwVivpwI/AAAAAAAAADY/_cxF-en_ItI/s400/validationOverlayDemo.PNG" alt="" id="BLOGGER_PHOTO_ID_5429247411374499586" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="text-decoration: underline;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://free-the-pixel.dev.java.net/files/documents/10830/147685/valdiationOverlays.jnlp"&gt;&lt;img style="cursor: pointer; width: 88px; height: 23px;" src="https://free-the-pixel.dev.java.net/files/documents/10830/147686/webstart.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;validation overlays source code &lt;a href="https://free-the-pixel.dev.java.net/source/browse/free-the-pixel/trunk/src/com/community/xanadu/demo/components/ValidationOverlaysDemoFrame.java"&gt;here&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3113056103202976131-3890032652799804044?l=free-the-pixel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://free-the-pixel.blogspot.com/feeds/3890032652799804044/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://free-the-pixel.blogspot.com/2010/01/validation-overlays.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3113056103202976131/posts/default/3890032652799804044'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3113056103202976131/posts/default/3890032652799804044'/><link rel='alternate' type='text/html' href='http://free-the-pixel.blogspot.com/2010/01/validation-overlays.html' title='Validation overlays'/><author><name>Mabs</name><uri>http://www.blogger.com/profile/05193647092760468172</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_MiO_FvhBBtA/S0-XEk_aYnI/AAAAAAAAACA/1tm3UOOLGsQ/s1600-R/xanlogoshiny_trans_small.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_MiO_FvhBBtA/S1iPnVJdk-I/AAAAAAAAADA/WC1BLTFPLcU/s72-c/sample.PNG' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3113056103202976131.post-3718010595782034105</id><published>2010-01-16T13:25:00.005+01:00</published><updated>2010-02-05T22:51:38.544+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='swing'/><category scheme='http://www.blogger.com/atom/ns#' term='cellRenderer'/><title type='text'>Animated cell renderer</title><content type='html'>This article will take as example list cell renderer but the same way can be applied to animate tree/table renderer.&lt;br /&gt;&lt;br /&gt;Let’s start from where the last article end: the renderer is bigger when the cell is selected, why not animate the fact that the renderer size increase over time, to let the user know it’s actually the one that he selected that get bigger.&lt;br /&gt;&lt;br /&gt;First we need a way to store the animation value for each cell:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&lt;br /&gt;Map&amp;lt;Integer, Float&amp;gt; mapAnimation = new HashMap&amp;lt;Integer, Float&amp;gt;();&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The renderer will look up for the animation value:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&lt;br /&gt;public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, final boolean cellHasFocus) {&lt;br /&gt;&lt;br /&gt;JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index,isSelected, cellHasFocus);&lt;br /&gt;&lt;br /&gt;Float progress = mapAnimation.get(index);&lt;br /&gt;if (progress == null) {&lt;br /&gt;  progress = 0f;&lt;br /&gt;}&lt;br /&gt;label.setFont(label.getFont().deriveFont(10 + 20 * progress));&lt;br /&gt;label.setPreferredSize(new Dimension(50, (int) (15 + 35 * progress)));&lt;br /&gt;return label;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;A selection listener to start the animation:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;list.getSelectionModel().addListSelectionListener(new ListSelectionListener() {&lt;br /&gt;@Override&lt;br /&gt;public void valueChanged(final ListSelectionEvent e) {&lt;br /&gt;  if (e.getValueIsAdjusting()) {&lt;br /&gt;      return;&lt;br /&gt;  }&lt;br /&gt;  final Timeline timeline = new Timeline();&lt;br /&gt;  timeline.setDuration(200);&lt;br /&gt;  timeline.addCallback(new TimelineCallback() {&lt;br /&gt;      /*…see below…*/  &lt;br /&gt;  });&lt;br /&gt;  timeline.play();&lt;br /&gt;}&lt;br /&gt;});&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The TimelineCallBack allow us to define what to do on each timeline pulse, it’s where the animation map will get populated.&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;new TimelineCallback() {&lt;br /&gt;@Override&lt;br /&gt;public void onTimelinePulse(float durationFraction,float TimelinePosition) {&lt;br /&gt;  // set the progress for the selected index&lt;br /&gt;   mapAnimation.put(list.getSelectedIndex(), durationFraction);&lt;br /&gt;  //set the progress for the last selected index&lt;br /&gt;  if (oldSelected[0] != -1) {&lt;br /&gt;      mapAnimation.put(oldSelected[0], 1 - durationFraction);&lt;br /&gt;  }&lt;br /&gt;//compute the size for each cell with the new animation values&lt;br /&gt;  SwingUtilities.invokeLater(new Runnable(){&lt;br /&gt;      Override&lt;br /&gt;      public void run(){&lt;br /&gt;          JlistUtils.computeListSize(list);&lt;br /&gt;      }&lt;br /&gt;  });&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;And that’s it! You now have an animated renderer.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://free-the-pixel.dev.java.net/files/documents/10830/147672/Demo1AnimatedCellRenderer.jnlp"&gt;&lt;img style="cursor: pointer; width: 88px; height: 23px;" src="https://free-the-pixel.dev.java.net/files/documents/10830/147686/webstart.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;A bit more complex examples:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_MiO_FvhBBtA/S1GyukTGrKI/AAAAAAAAACw/iLXn6QToxio/s1600-h/CellRendererAnimatedDemo2.PNG"&gt;&lt;img style="cursor: pointer; width: 216px; height: 320px;" src="http://4.bp.blogspot.com/_MiO_FvhBBtA/S1GyukTGrKI/AAAAAAAAACw/iLXn6QToxio/s320/CellRendererAnimatedDemo2.PNG" alt="" id="BLOGGER_PHOTO_ID_5427315539045690530" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="text-decoration: underline;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://free-the-pixel.dev.java.net/files/documents/10830/147673/Demo2AnimatedCellRenderer.jnlp"&gt;&lt;img style="cursor: pointer; width: 88px; height: 23px;" src="https://free-the-pixel.dev.java.net/files/documents/10830/147686/webstart.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_MiO_FvhBBtA/S1Gyxa8NSrI/AAAAAAAAAC4/5P-MOuLUBwg/s1600-h/CellRendererAnimatedDemo3.PNG"&gt;&lt;img style="cursor: pointer; width: 320px; height: 241px;" src="http://2.bp.blogspot.com/_MiO_FvhBBtA/S1Gyxa8NSrI/AAAAAAAAAC4/5P-MOuLUBwg/s320/CellRendererAnimatedDemo3.PNG" alt="" id="BLOGGER_PHOTO_ID_5427315588073343666" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://free-the-pixel.dev.java.net/files/documents/10830/147675/Demo3AnimatedCellRenderer.jnlp"&gt;&lt;img style="cursor: pointer; width: 88px; height: 23px;" src="https://free-the-pixel.dev.java.net/files/documents/10830/147686/webstart.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;as always you can find the source code in the source code repository &lt;a href="https://free-the-pixel.dev.java.net/source/browse/free-the-pixel/trunk/src/com/community/xanadu/demo/components/JList/animated/"&gt;here&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3113056103202976131-3718010595782034105?l=free-the-pixel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://free-the-pixel.blogspot.com/feeds/3718010595782034105/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://free-the-pixel.blogspot.com/2010/01/animated-cell-renderer.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3113056103202976131/posts/default/3718010595782034105'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3113056103202976131/posts/default/3718010595782034105'/><link rel='alternate' type='text/html' href='http://free-the-pixel.blogspot.com/2010/01/animated-cell-renderer.html' title='Animated cell renderer'/><author><name>Mabs</name><uri>http://www.blogger.com/profile/05193647092760468172</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_MiO_FvhBBtA/S0-XEk_aYnI/AAAAAAAAACA/1tm3UOOLGsQ/s1600-R/xanlogoshiny_trans_small.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_MiO_FvhBBtA/S1GyukTGrKI/AAAAAAAAACw/iLXn6QToxio/s72-c/CellRendererAnimatedDemo2.PNG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3113056103202976131.post-3618519515919982046</id><published>2010-01-16T12:20:00.010+01:00</published><updated>2010-02-05T22:52:02.913+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='swing'/><category scheme='http://www.blogger.com/atom/ns#' term='cellRenderer'/><category scheme='http://www.blogger.com/atom/ns#' term='jlist'/><title type='text'>Dynamic size cell list renderer</title><content type='html'>What I mean by dynamic size is that the renderer can changed size for a given index.&lt;br /&gt;&lt;br /&gt;Let’s take what can be seen at first as a very easy example:&lt;br /&gt;For example when you select an item, you would like to increase the font size of the label.&lt;br /&gt;&lt;br /&gt;It seems easy, let’s just create a custom renderer and change the font size based on the isSelected parameter.&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&lt;br /&gt;public Component getListCellRendererComponent(JList list, Object value,int index, boolean isSelected, boolean cellHasFocus) {&lt;br /&gt;JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);&lt;br /&gt;if (isSelected) {&lt;br /&gt;label.setFont(label.getFont().deriveFont(35f));&lt;br /&gt;} else {&lt;br /&gt;label.setFont(label.getFont().deriveFont(10f));&lt;br /&gt;}&lt;br /&gt;return label;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_MiO_FvhBBtA/S1Gn786pPCI/AAAAAAAAACg/JfjKdZiYSCs/s1600-h/CellRendererSizeDemo0.PNG"&gt;&lt;img style="cursor: pointer; width: 298px; height: 192px;" src="http://4.bp.blogspot.com/_MiO_FvhBBtA/S1Gn786pPCI/AAAAAAAAACg/JfjKdZiYSCs/s320/CellRendererSizeDemo0.PNG" alt="" id="BLOGGER_PHOTO_ID_5427303674364378146" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The font size is bigger but the size of the label is not increased, hence the label is partly hidden .&lt;br /&gt;&lt;br /&gt;So let’s try to change the size of the label:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;public Component getListCellRendererComponent(JList list, Object value,int index, boolean isSelected, boolean cellHasFocus) {&lt;br /&gt;&lt;br /&gt;JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);&lt;br /&gt;if (isSelected) {&lt;br /&gt;  label.setFont(label.getFont().deriveFont(35f));&lt;br /&gt;  label.setPreferredSize(new Dimension(50, 50));&lt;br /&gt;} else {&lt;br /&gt;  label.setFont(label.getFont().deriveFont(10f));&lt;br /&gt;  label.setPreferredSize(new Dimension(50, 15));&lt;br /&gt;}&lt;br /&gt;return label;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://free-the-pixel.dev.java.net/files/documents/10830/147677/Demo1DynamicSizeJList.jnlp"&gt;&lt;img style="cursor: pointer; width: 88px; height: 23px;" src="https://free-the-pixel.dev.java.net/files/documents/10830/147686/webstart.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;To our surprise it doesn’t work. Why?&lt;br /&gt;&lt;br /&gt;The answer is in the BasicListUI class, the height of each cell is cached, it doesn’t get computed each time the getListCellRendererComponent method get called. That’s where our problem lies.&lt;br /&gt;&lt;br /&gt;By looking a bit more closely at BasicListUI, one can see that the cache is populated in the updateLayoutState method and that’s only getting called after a change in the model.&lt;br /&gt;&lt;br /&gt;We have to call this method in order to compute the new size of each cell, but this method is protected,so we won’t be able to call this method directly so we will use reflection.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;public static void computeListSize(final JList list) {&lt;br /&gt;if (list.getUI() instanceof BasicListUI) {&lt;br /&gt; BasicListUI ui = (BasicListUI) list.getUI();&lt;br /&gt;&lt;br /&gt; try {&lt;br /&gt;     Method method = BasicListUI.class.getDeclaredMethod("updateLayoutState");&lt;br /&gt;     method.setAccessible(true);&lt;br /&gt;     method.invoke(ui);&lt;br /&gt;     list.revalidate();&lt;br /&gt;     list.repaint();&lt;br /&gt; } catch (Exception e) {&lt;br /&gt;     e.printStackTrace();&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;In our case we need to compute the cell size when a cell gets selected:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;list.getSelectionModel().addListSelectionListener(new ListSelectionListener() {&lt;br /&gt;@Override&lt;br /&gt;public void valueChanged(final ListSelectionEvent e) {&lt;br /&gt;JlistUtils.computeListSize(list);&lt;br /&gt;}&lt;br /&gt;});&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://free-the-pixel.dev.java.net/files/documents/10830/147674/Demo2DynamicSizeJList.jnlp"&gt;&lt;img style="cursor: pointer; width: 88px; height: 23px;" src="https://free-the-pixel.dev.java.net/files/documents/10830/147686/webstart.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;But as you can see if you run this webstart demo , it doesn’t work, so why ?&lt;br /&gt;The answer is in the updateLayoutState method.:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;protected void updateLayoutState(){&lt;br /&gt;//…&lt;br /&gt;Component c = renderer.getListCellRendererComponent(list, value, index, false, false);&lt;br /&gt;//…&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The 2 last parameters are isSelected and cellHasFocus, which means we can’t use isSelected+cellHasFocus to determine the size of the renderer.&lt;br /&gt;&lt;br /&gt;So the last version of our renderer is:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&lt;br /&gt;public Component getListCellRendererComponent(JList list,Object value, int index, boolean isSelected, boolean cellHasFocus) {&lt;br /&gt;&lt;br /&gt;JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);&lt;br /&gt;if (list.getSelectedIndex() == index) {&lt;br /&gt;label.setFont(label.getFont().deriveFont(35f));&lt;br /&gt;label.setPreferredSize(new Dimension(50, 50));&lt;br /&gt;} else{&lt;br /&gt;label.setFont(label.getFont().deriveFont(10f));&lt;br /&gt;label.setPreferredSize(new Dimension(50, 15));&lt;br /&gt;}&lt;br /&gt;return label;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This time we actually have what we expected: the cell selected is bigger.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://free-the-pixel.dev.java.net/files/documents/10830/147676/Demo3DynamicSizeJList.jnlp"&gt;&lt;img style="cursor: pointer; width: 88px; height: 23px;" src="https://free-the-pixel.dev.java.net/files/documents/10830/147686/webstart.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_MiO_FvhBBtA/S1Goj_xPMyI/AAAAAAAAACo/R4a4b68oAxw/s1600-h/CellRendererSizeDemo3.PNG"&gt;&lt;img style="cursor: pointer; width: 299px; height: 300px;" src="http://2.bp.blogspot.com/_MiO_FvhBBtA/S1Goj_xPMyI/AAAAAAAAACo/R4a4b68oAxw/s320/CellRendererSizeDemo3.PNG" alt="" id="BLOGGER_PHOTO_ID_5427304362324996898" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You can find the source of those demo in the following package in the source code repository &lt;a href="https://free-the-pixel.dev.java.net/source/browse/free-the-pixel/trunk/src/com/community/xanadu/demo/components/JList/dynamicsize/"&gt;here&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;all the jars files has been signed to run via webstart; that was needed because of the use of  Method.setAccessible to be able to call a protected method&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3113056103202976131-3618519515919982046?l=free-the-pixel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://free-the-pixel.blogspot.com/feeds/3618519515919982046/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://free-the-pixel.blogspot.com/2010/01/dynamic-size-cell-list-renderer.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3113056103202976131/posts/default/3618519515919982046'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3113056103202976131/posts/default/3618519515919982046'/><link rel='alternate' type='text/html' href='http://free-the-pixel.blogspot.com/2010/01/dynamic-size-cell-list-renderer.html' title='Dynamic size cell list renderer'/><author><name>Mabs</name><uri>http://www.blogger.com/profile/05193647092760468172</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_MiO_FvhBBtA/S0-XEk_aYnI/AAAAAAAAACA/1tm3UOOLGsQ/s1600-R/xanlogoshiny_trans_small.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_MiO_FvhBBtA/S1Gn786pPCI/AAAAAAAAACg/JfjKdZiYSCs/s72-c/CellRendererSizeDemo0.PNG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3113056103202976131.post-7697462236269885930</id><published>2010-01-14T17:50:00.006+01:00</published><updated>2010-02-05T22:43:25.435+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='jxlayer'/><category scheme='http://www.blogger.com/atom/ns#' term='dialog'/><title type='text'>DialogWithDropShadow +JXLayer  use case</title><content type='html'>The drop shadow dialog/frame from the last article is indeed not something to use everywhere.&lt;br /&gt;There is one situation although I like to use it:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_MiO_FvhBBtA/S09UBhymudI/AAAAAAAAAB0/D54idjTBLmQ/s1600-h/DialogUseCase.png"&gt;&lt;img style="cursor: pointer; width: 338px; height: 251px;" src="http://2.bp.blogspot.com/_MiO_FvhBBtA/S09UBhymudI/AAAAAAAAAB0/D54idjTBLmQ/s320/DialogUseCase.png" alt="" id="BLOGGER_PHOTO_ID_5426648461231962578" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;While opening a dialog over a JFrame, a gray filter is applied over the JFrame using JXLayer, the gray filter is of course faded in using a fast animation (500ms =&gt; the same time it take for the dialogWithDropShadow to fade in). I really like the result, it makes the dialog really stand out, and make the user focus on it.&lt;br /&gt;Launch the web start demo to see the animation.&lt;br /&gt;&lt;br /&gt;The fade in of the gray filter is done by animating the alpha property in the ColorLayerUI class.&lt;br /&gt;This &lt;a href="https://free-the-pixel.dev.java.net/source/browse/free-the-pixel/trunk/src/com/community/xanadu/components/layer/ColorLayerUI.java"&gt;ColorLayerUI&lt;/a&gt; is really simple; it’s just paint a grey rectangle in the paintLayer method.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://free-the-pixel.dev.java.net/files/documents/10830/147682/dialogColorLayerUI.jnlp"&gt;&lt;img style="cursor: pointer; width: 88px; height: 23px;" src="https://free-the-pixel.dev.java.net/files/documents/10830/147686/webstart.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://kenai.com/projects/mabs-swing/downloads/download/jnlp/dialogColorLayerUI.jnlp"&gt;&lt;br /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3113056103202976131-7697462236269885930?l=free-the-pixel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://free-the-pixel.blogspot.com/feeds/7697462236269885930/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://free-the-pixel.blogspot.com/2010/01/dialogwithdropshadow-jxlayer-use-case.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3113056103202976131/posts/default/7697462236269885930'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3113056103202976131/posts/default/7697462236269885930'/><link rel='alternate' type='text/html' href='http://free-the-pixel.blogspot.com/2010/01/dialogwithdropshadow-jxlayer-use-case.html' title='DialogWithDropShadow +JXLayer  use case'/><author><name>Mabs</name><uri>http://www.blogger.com/profile/05193647092760468172</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_MiO_FvhBBtA/S0-XEk_aYnI/AAAAAAAAACA/1tm3UOOLGsQ/s1600-R/xanlogoshiny_trans_small.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_MiO_FvhBBtA/S09UBhymudI/AAAAAAAAAB0/D54idjTBLmQ/s72-c/DialogUseCase.png' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3113056103202976131.post-3679855352222035682</id><published>2010-01-09T11:24:00.028+01:00</published><updated>2010-02-05T22:38:52.332+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='jframe'/><category scheme='http://www.blogger.com/atom/ns#' term='dropshadow'/><category scheme='http://www.blogger.com/atom/ns#' term='swing'/><category scheme='http://www.blogger.com/atom/ns#' term='jdialog'/><title type='text'>Customs JDialog/JFrame</title><content type='html'>&lt;p style="margin-bottom: 0cm;" lang="en-GB"&gt;I wanted a JDialog/JFrame that looks better than the standards ones, so I ended up coding these classes : DialogWithDropShadow/FrameWithDropShadow , and yes something I am really bad at is naming.&lt;br /&gt;&lt;br /&gt;They are JDialog / JFrame with round corner and drop shadow.&lt;br /&gt;&lt;br /&gt;It’s JDialog/JFrame which has been set non opaque using the WindowsUtils class( wrapper around AWTUtilities + some other methods). It’s the custom content pane that deal with painting the background+shadow, and the layered pane is used to position the title bar&lt;br /&gt;&lt;/p&gt;&lt;p style="margin-bottom: 0cm;" lang="en-GB"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_MiO_FvhBBtA/S0hZsERERfI/AAAAAAAAAAU/rAEIZq1HTMs/s1600-h/DialogWithDropShadow.PNG"&gt;&lt;img style="cursor: pointer; width: 307px; height: 208px;" src="http://3.bp.blogspot.com/_MiO_FvhBBtA/S0hZsERERfI/AAAAAAAAAAU/rAEIZq1HTMs/s320/DialogWithDropShadow.PNG" alt="" id="BLOGGER_PHOTO_ID_5424684364762203634" border="0" /&gt;&lt;/a&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_MiO_FvhBBtA/S0hf6DdOQII/AAAAAAAAABc/Py6KrLSad8w/s1600-h/FrameWithDropShadow.PNG"&gt;&lt;img style="cursor: pointer; width: 309px; height: 208px;" src="http://1.bp.blogspot.com/_MiO_FvhBBtA/S0hf6DdOQII/AAAAAAAAABc/Py6KrLSad8w/s320/FrameWithDropShadow.PNG" alt="" id="BLOGGER_PHOTO_ID_5424691202132689026" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;Under SubstanceDustCoffeeLookAndFeel&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p style="margin-bottom: 0cm;" lang="en-GB"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_MiO_FvhBBtA/S0hbdoqmRMI/AAAAAAAAAA0/7ozCLo57phA/s1600-h/DialogWithDropShadowMetal.PNG"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 306px; height: 207px;" src="http://3.bp.blogspot.com/_MiO_FvhBBtA/S0hbdoqmRMI/AAAAAAAAAA0/7ozCLo57phA/s320/DialogWithDropShadowMetal.PNG" alt="" id="BLOGGER_PHOTO_ID_5424686315858183362" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p style="margin-bottom: 0cm;" lang="en-GB"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_MiO_FvhBBtA/S0hgD2V_EXI/AAAAAAAAABk/DnvMWyNy9fs/s1600-h/FrameWithDropShadowMetal.PNG"&gt;&lt;img style="cursor: pointer; width: 307px; height: 210px;" src="http://1.bp.blogspot.com/_MiO_FvhBBtA/S0hgD2V_EXI/AAAAAAAAABk/DnvMWyNy9fs/s320/FrameWithDropShadowMetal.PNG" alt="" id="BLOGGER_PHOTO_ID_5424691370411364722" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin-bottom: 0cm;" lang="en-GB"&gt;under metal LAF&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Title bar&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;For the dialog you can choose to have (default value) or not the close button using the following constructor&lt;br /&gt;&lt;span style="color: rgb(102, 102, 102);"&gt;DialogWithDropShadow (Window frame, boolean draggable, boolean withCloseButton)&lt;/span&gt;&lt;br /&gt;or the setter&lt;br /&gt;&lt;span style="color: rgb(102, 102, 102);"&gt;setWithCloseButton(boolean)&lt;/span&gt;&lt;br /&gt;If the close button is not visible and that the title is empty there will be not y offset.&lt;br /&gt;&lt;p style="margin-bottom: 0cm;" lang="en-GB"&gt; &lt;/p&gt;&lt;br /&gt;&lt;p style="margin-bottom: 0cm;" lang="en-GB"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_MiO_FvhBBtA/S0hb8cSguUI/AAAAAAAAABE/iVkk3IcLOFo/s1600-h/DialogWithDropShadowNoTitleBar.PNG"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 310px; height: 208px;" src="http://4.bp.blogspot.com/_MiO_FvhBBtA/S0hb8cSguUI/AAAAAAAAABE/iVkk3IcLOFo/s320/DialogWithDropShadowNoTitleBar.PNG" alt="" id="BLOGGER_PHOTO_ID_5424686845111875906" border="0" /&gt;&lt;/a&gt;&lt;/p&gt; &lt;p style="margin-bottom: 0cm;" lang="en-GB"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin-bottom: 0cm;" lang="en-GB"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin-bottom: 0cm;" lang="en-GB"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin-bottom: 0cm;" lang="en-GB"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin-bottom: 0cm;" lang="en-GB"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin-bottom: 0cm;" lang="en-GB"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin-bottom: 0cm;" lang="en-GB"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin-bottom: 0cm;" lang="en-GB"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin-bottom: 0cm;" lang="en-GB"&gt;&lt;span style="font-weight: bold;"&gt;Background&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;You can change the background color using either getContentPane().setBackground(Color)&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_MiO_FvhBBtA/S0hcQTq9W8I/AAAAAAAAABM/YW1RLfK4RyI/s1600-h/DialogWithDropShadowBackground.PNG"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 309px; height: 209px;" src="http://1.bp.blogspot.com/_MiO_FvhBBtA/S0hcQTq9W8I/AAAAAAAAABM/YW1RLfK4RyI/s320/DialogWithDropShadowBackground.PNG" alt="" id="BLOGGER_PHOTO_ID_5424687186395880386" border="0" /&gt;&lt;/a&gt; &lt;p style="margin-bottom: 0cm;"&gt;&lt;span lang="en-GB"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-bottom: 0cm;"&gt;&lt;span lang="en-GB"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-bottom: 0cm;" lang="en-GB"&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style="margin-bottom: 0cm;" lang="en-GB"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin-bottom: 0cm;" lang="en-GB"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin-bottom: 0cm;" lang="en-GB"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin-bottom: 0cm;" lang="en-GB"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin-bottom: 0cm;" lang="en-GB"&gt;&lt;br /&gt;or setContentPaneBackground(Paint)&lt;br /&gt;&lt;/p&gt;&lt;p style="margin-bottom: 0cm;" lang="en-GB"&gt; &lt;/p&gt;&lt;p style="margin-bottom: 0cm;" lang="en-GB"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_MiO_FvhBBtA/S0hchUYb_oI/AAAAAAAAABU/XvHfG70BepI/s1600-h/DialogWithDropShadowPaint.PNG"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 306px; height: 203px;" src="http://3.bp.blogspot.com/_MiO_FvhBBtA/S0hchUYb_oI/AAAAAAAAABU/XvHfG70BepI/s320/DialogWithDropShadowPaint.PNG" alt="" id="BLOGGER_PHOTO_ID_5424687478644407938" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0cm;" lang="en-GB"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin-bottom: 0cm;" lang="en-GB"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin-bottom: 0cm;" lang="en-GB"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin-bottom: 0cm;" lang="en-GB"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin-bottom: 0cm;" lang="en-GB"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin-bottom: 0cm;" lang="en-GB"&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Fade in / Fade out&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This window can be shown or hidden using a fade in/fade out animation with the 2 followings methods:&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(102, 102, 102);"&gt;startShowAnim()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(102, 102, 102);"&gt;startHideAnim()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Those 2 methods in fact only call WindowFadeInManager.fadeIn/fadeout&lt;br /&gt;&lt;br /&gt;WindowFadeInManager is a utility class used to fade in or fade out windows, you can use it on any window, but you will need at least java 6 update 10 to use this feature, if you don’t, it won’t crash, it will just setVisible true/false on the given window&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Resizable&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;By default they are resizable, it uses com.jidesoft.swing.Resizable behind the scene to make it resizable, just call setResizable(false) to remove this default behavior.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Draggable&lt;/span&gt;&lt;br /&gt;Both dialog and frame are draggable by default, not only on the title bar, from anywhere if the mouse event is not catched by another component.   &lt;a href="https://free-the-pixel.dev.java.net/source/browse/free-the-pixel/trunk/src/com/community/xanadu/listeners/Draggable.java"&gt;draggable class&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You can find the source code &lt;a href="https://free-the-pixel.dev.java.net/source/browse/free-the-pixel/trunk/src/com/community/xanadu/components/windows/dropShadow/"&gt;here&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://free-the-pixel.dev.java.net/files/documents/10830/147679/DialogWithDropShadowSubstance.jnlp"&gt;&lt;img style="cursor: pointer; width: 88px; height: 23px;" src="https://free-the-pixel.dev.java.net/files/documents/10830/147686/webstart.png" alt="" border="0" /&gt;&lt;/a&gt; dialog under substance&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://free-the-pixel.dev.java.net/files/documents/10830/147681/FrameWithDropShadowSubstance.jnlp"&gt;&lt;img style="cursor: pointer; width: 88px; height: 23px;" src="https://free-the-pixel.dev.java.net/files/documents/10830/147686/webstart.png" alt="" border="0" /&gt;&lt;/a&gt;  frame under substance&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://free-the-pixel.dev.java.net/files/documents/10830/147678/DialogWithDropShadowMetal.jnlp"&gt;&lt;img style="cursor: pointer; width: 88px; height: 23px;" src="https://free-the-pixel.dev.java.net/files/documents/10830/147686/webstart.png" alt="" border="0" /&gt;&lt;/a&gt; dialog under metal&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://free-the-pixel.dev.java.net/files/documents/10830/147679/DialogWithDropShadowSubstance.jnlp"&gt;&lt;img style="cursor: pointer; width: 88px; height: 23px;" src="https://free-the-pixel.dev.java.net/files/documents/10830/147686/webstart.png" alt="" border="0" /&gt;&lt;/a&gt; frame under metal&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://kenai.com/projects/mabs-swing/downloads/download/jnlp/FrameWithDropShadowMetal.jnlp"&gt;&lt;/a&gt; &lt;p&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3113056103202976131-3679855352222035682?l=free-the-pixel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://free-the-pixel.blogspot.com/feeds/3679855352222035682/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://free-the-pixel.blogspot.com/2010/01/customs-jdialogjframe.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3113056103202976131/posts/default/3679855352222035682'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3113056103202976131/posts/default/3679855352222035682'/><link rel='alternate' type='text/html' href='http://free-the-pixel.blogspot.com/2010/01/customs-jdialogjframe.html' title='Customs JDialog/JFrame'/><author><name>Mabs</name><uri>http://www.blogger.com/profile/05193647092760468172</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_MiO_FvhBBtA/S0-XEk_aYnI/AAAAAAAAACA/1tm3UOOLGsQ/s1600-R/xanlogoshiny_trans_small.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_MiO_FvhBBtA/S0hZsERERfI/AAAAAAAAAAU/rAEIZq1HTMs/s72-c/DialogWithDropShadow.PNG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3113056103202976131.post-3729968557976445353</id><published>2010-01-08T23:24:00.006+01:00</published><updated>2010-02-05T22:27:44.825+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='text'/><category scheme='http://www.blogger.com/atom/ns#' term='swing'/><title type='text'>Text prompt</title><content type='html'>&lt;span lang="en-GB"&gt;I really like the solution to create a text prompt I saw at &lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&lt;u&gt;&lt;a href="http://tips4java.wordpress.com/2009/11/29/text-prompt/"&gt;&lt;span lang="en-GB"&gt;http://tips4java.wordpress.com/2009/11/29/text-prompt/&lt;/span&gt;&lt;/a&gt;&lt;/u&gt;&lt;/span&gt;&lt;br /&gt;&lt;p style="margin-bottom: 0cm;"&gt;&lt;span lang="en-GB"&gt;Something I really like also is smooth transition between component states, so I had to add fade in / fade out transition for this text prompt component!&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin-bottom: 0cm;"&gt;My first idea was to do the animation using the alpha component of the foreground. But after the first test i noticed that i forgot the icon of the JLabel!&lt;/p&gt;&lt;p style="margin-bottom: 0cm;"&gt;So i ended up using JXPanel on which one i add the JLabel, and then doing the animation of the JXPanel alpha property. &lt;/p&gt;&lt;p style="margin-bottom: 0cm;"&gt;&lt;span lang="en-GB"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-bottom: 0cm;"&gt;&lt;span lang="en-GB"&gt;You can find the source in the repository  &lt;/span&gt;&lt;a href="https://free-the-pixel.dev.java.net/source/browse/free-the-pixel/trunk/src/com/community/xanadu/components/text/TextPrompt.java"&gt;here&lt;/a&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style="margin-bottom: 0cm;"&gt;&lt;span lang="en-GB"&gt;Feel free to try it out:&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-bottom: 0cm;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://free-the-pixel.dev.java.net/files/documents/10830/147671/textPrompt.jnlp"&gt;&lt;img style="cursor: pointer; width: 88px; height: 23px;" src="https://free-the-pixel.dev.java.net/files/documents/10830/147686/webstart.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin-bottom: 0cm;"&gt;I have one problem with this component, it only hapens under substance LAF, i have to create the textPrompt component in another invokeLater else i can't see the text prompt, i still need to investigate this point.&lt;/p&gt;&lt;p style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin-bottom: 0cm;"&gt;Ok, that's it for my first article on a swing component, i hope i didn't forget anything and that the web start demo works.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3113056103202976131-3729968557976445353?l=free-the-pixel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://free-the-pixel.blogspot.com/feeds/3729968557976445353/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://free-the-pixel.blogspot.com/2010/01/text-prompt.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3113056103202976131/posts/default/3729968557976445353'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3113056103202976131/posts/default/3729968557976445353'/><link rel='alternate' type='text/html' href='http://free-the-pixel.blogspot.com/2010/01/text-prompt.html' title='Text prompt'/><author><name>Mabs</name><uri>http://www.blogger.com/profile/05193647092760468172</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_MiO_FvhBBtA/S0-XEk_aYnI/AAAAAAAAACA/1tm3UOOLGsQ/s1600-R/xanlogoshiny_trans_small.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3113056103202976131.post-4047507366642369377</id><published>2010-01-08T21:30:00.004+01:00</published><updated>2010-01-08T23:52:45.459+01:00</updated><title type='text'>Libraries dependencies + source code repository</title><content type='html'>You can find the required libraries at:&lt;br /&gt;&lt;a href="http://kenai.com/projects/mabs-swing/downloads/download/lib.zip"&gt;http://kenai.com/projects/mabs-swing/downloads/download/lib.zip&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You can find the source code repository at:&lt;br /&gt;&lt;a href="https://svn.kenai.com/svn/mabs-swing%7Esource-code-repository"&gt;https://svn.kenai.com/svn/mabs-swing~source-code-repository&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The source code contains already several components/demos. I am trying to centralise there all the common components I am usually using in my projects, I will try to write articles about most of them.&lt;br /&gt;&lt;br /&gt;The main required libraries, I am using, are the following:&lt;br /&gt;-Substance: My favourite LAF .&lt;br /&gt;-Trident: for animations + required by substance&lt;br /&gt;-Miglayout: the easiest and most readable layout manager around imho.&lt;br /&gt;-SwingX&lt;br /&gt;-JXlayer&lt;br /&gt;-Filers from jhlabs&lt;br /&gt;-jide-oss&lt;br /&gt;&lt;br /&gt;Some components are developed to match specialy substance LAF by querying the skin to get colors, but even if I do that, I try to always see first if substance is the current LAF, if not I use some default colors.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3113056103202976131-4047507366642369377?l=free-the-pixel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://free-the-pixel.blogspot.com/feeds/4047507366642369377/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://free-the-pixel.blogspot.com/2010/01/libraries-dependencies-source-code.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3113056103202976131/posts/default/4047507366642369377'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3113056103202976131/posts/default/4047507366642369377'/><link rel='alternate' type='text/html' href='http://free-the-pixel.blogspot.com/2010/01/libraries-dependencies-source-code.html' title='Libraries dependencies + source code repository'/><author><name>Mabs</name><uri>http://www.blogger.com/profile/05193647092760468172</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_MiO_FvhBBtA/S0-XEk_aYnI/AAAAAAAAACA/1tm3UOOLGsQ/s1600-R/xanlogoshiny_trans_small.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3113056103202976131.post-4527893290530843086</id><published>2010-01-04T17:56:00.001+01:00</published><updated>2010-01-08T23:52:29.941+01:00</updated><title type='text'>Welcome to my blog</title><content type='html'>Hi and welcome to my blog.&lt;br /&gt;That's been a few now that i am following some blogs about java swing/java2d.&lt;br /&gt;I have been thinking to create this blog for a few now; with a new year it's a good time to start, so here we go.&lt;br /&gt;&lt;br /&gt;So here will be the place where i will share interresting components or cool effects developed in swing/java2d&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3113056103202976131-4527893290530843086?l=free-the-pixel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://free-the-pixel.blogspot.com/feeds/4527893290530843086/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://free-the-pixel.blogspot.com/2010/01/hi-and-welcome-to-my-blog.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3113056103202976131/posts/default/4527893290530843086'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3113056103202976131/posts/default/4527893290530843086'/><link rel='alternate' type='text/html' href='http://free-the-pixel.blogspot.com/2010/01/hi-and-welcome-to-my-blog.html' title='Welcome to my blog'/><author><name>Mabs</name><uri>http://www.blogger.com/profile/05193647092760468172</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_MiO_FvhBBtA/S0-XEk_aYnI/AAAAAAAAACA/1tm3UOOLGsQ/s1600-R/xanlogoshiny_trans_small.png'/></author><thr:total>0</thr:total></entry></feed>
