I was working in the same application where I found the previous quirk. This time I tried to make a cell renderer put a background color in the cell, to no avail. I even tried to explicitly return a JLabel as the cell renderer, with the proper background color set. Nothing.

The answer to the mystery is the fact that JLabel is transparent by default, transparent components don't render their background, and DefaultTreeCellRenderer extends JLabel.

After some googling again I found out that I'm not alone. There is even a bug raised, and closed as "not a bug". From the JComponent.setOpaque() javadocs:

    /**
     * If true the component paints every pixel within its bounds. 
     * Otherwise, the component may not paint some or all of its
     * pixels, allowing the underlying pixels to show through.
     * 

* The default value of this property is false for JComponent. * However, the default value for this property on most standard * JComponent subclasses (such as JButton and * JTree) is look-and-feel dependent. * * @param isOpaque true if this component should be opaque * @see #isOpaque * @beaninfo * bound: true * expert: true * description: The component's opacity */

The workaround? Add this.setOpaque(true) in the overriden getTreeCellRendererComponent() method:
public class BagroundColorEnabledRenderer extends DefaultTreeCellRenderer {
    public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
	super.getTreeCellRendererComponent(tree,value,sel,expanded,leaf,row);
	this.setOpaque(true);
	return this;
    }
}
Happy Coding!
I have been bitten. ListSelectionListener.valueChanged is called more than once when a selection in a List/Tree/Table is changed. After some googling, I found out that I'm not alone.

The fix is quick enough, but I was curious about why was happening, so I hacked up the following test program:

package org.soronthar.spikes;

import javax.swing.*;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.ListSelectionEvent;

public class ListSelectionSpike extends JFrame {

    public static void main(String[] args) {
        ListSelectionSpike spike = new ListSelectionSpike();
        spike.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JList jList = new JList(new String[]{"One", "Two", "Three"});
        jList.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent e) {
                if (e.getValueIsAdjusting()) {
                    System.out.print("Adjusting ");
                }
                System.out.println("f:" + e.getFirstIndex() + " l:" + e.getLastIndex());
            }
        });
        spike.getContentPane().add(jList);
        spike.pack();
        spike.setVisible(true);
    }
}
After some toying, I found out that valueChanged is called once each time the mouse is pressed and the selection changes without releasing the mouse, and once more when the mouse is released. That means that if you press the mouse, move over all the elements of a list and then release the mouse, valueChanged will be called once for each element plus once at the end (n+1 calls).

If you change the selection using the keyboard, then it gets called once.

I checked the javadocs for ListSelectionListener and the Swing tutorial, and it seems that this behavior is not documented.

After some more digging, I found out that it was even reported as a bug long time ago, and it was closed as "not a bug".
The workaround? Implement your valueChanged method as follows:
           public void valueChanged(ListSelectionEvent e) {
                if (!e.getValueIsAdjusting()) {
                    //do my stuff
                }
            }
The key is that while the mouse is pressed, all the ListSelectionEvents will return true for the e.getValueIsAdjusting() call, and will only return false when the mouse is released. For keyboard operations, it always returns false.

Hope this helps someone. Happy coding!
I was doing some regexp work on one of my projects, when suddenly this well-known and hundred-of-times implemented code right from the javadoc, failed:

   StringBuffer result = new StringBuffer(text.length());
   while (includeMatcher.find()) {
      String includeFile = includeMatcher.group(1);
      String s = readTemplate(includeFile, area,topic,skins,false);
      includeMatcher.appendReplacement(result, s);
   }
   includeMatcher.appendTail(result);
   text = result.toString();


A java.lang.IllegalArgumentException was thrown.

Thanks to google, I found out what happened: There was a $ sign in the replacement string.
Now, of course this was mentioned in the Matcher javadoc but nowhere in the documentation is stated that an IllegalArgumentException will be thrown.

Just for the record: the solution I implemented was to insert the following line just before the appendReplacement call:


s=s.replaceAll("\\$","\\\\\\$")


Hope this post helps someone in the future.

Newbie ScribeFire tip

| | Comments (0) | TrackBacks (0)
The first post I made with ScribeFire, had "Powere by ScribeFire" appended at the end. I wanted to turn that down, so I started to browse the site. In one Comment for the release note i found this tip:

To disable the "Powered by ScribeFire" message, click on the << simbol at the top left of the ScribeFire panel, go to "Settings" and uncheck the "Automatically insert Powered by ScribeFire" setting.

Happy blogging.

Posting to MT using ScribeFire or W.Bloggar

| | Comments (0) | TrackBacks (0)
Just in case someone else got bitten by this, the password to be used to post from a blogging client is not the same password used to login into the MT installation. Thankfully, everything is explained in the SixApart site. Just a note: the setting to change is "WebServices password", not "API Password". Happy blogging!

Powered by ScribeFire.

XmlGridLayout 0.4 Manual

|
  XmlGridLayout 0.4
------------------------------------------------------------------------
(found at XMLGridLayout)

*Table of Contents*

1. What is it? <#d3e8>
2. Requirements <#d3e22>
3. Directory Structure <#d3e25>
4. Rebuilding from the sources <#d3e47>
5. Layout Sintaxis <#d3e50>
6. How to layout components? <#d3e137>
7. Demo Classes <#d3e149>


    1. What is it?

XmlGridLayout is a LayoutManager that seeks to provide all the power of
GridBagLayout with the simplicity of an HTML table. Also, it tries to be
a way to separate the layout declaration from the component declaration.

Let see an example with Layout and Component declared together:

JPanel panel=new JPanel(new BorderLayout());
panel.add(new JLabel(),BorderLayout.SOUTH);
panel.add(new JPanel(),BorderLayout.CENTER);

If we want to change the layout of this panel (be it change the manager
or change the placement) we would need to modify 3 lines of code.

Now let's see an example with Layout and Components declared separately:

JPanel panel=new JPanel(new XmlGridLayout(layout);
panel.add("mainPanel",new JPanel());
panel.add("statusLabel",new JLabel());

The layout variable could be a declared variable with the layout string,
or the readed content of a file.

Now,if we want to change the layout we just need to change the content
of the layout variable (or the file with the layout definition). This
means that the same layout coud be used by several components (just pass
the same layout variable to all the XmlGridLayout instances). Also,
notice that each component is given a descriptive name in the layout.


    2. Requirements

XmlGridLayout has been tested with the JRE 1.4.0+. I think that it could
work in previous versions if the org.apache.crimson.parser.XMLReaderImpl
class and supporting classes are omewhere in the classpath, but haven't
test it so I can't guarantee it.


    3. Directory Structure

The XmlGridLayout package has several directories in it:

src     XmlGridLayout sources. These are the only sources you need to
rebuild the project
demo     Source of the demo classes
tests     Sources of the tests
doc     Javadocs
out     where all the compiled classes are stored.


    4. Rebuilding from the sources

To recompile, check the build.xml file and provide the path to all the
libraries needed (basically, JUnit) and run the main target. At some
future time a package with all the required libraries will also be
provided.


    5. Layout Sintaxis

A layout is defined using an xml document which has a sintax that is
very similar to that of an HTML table. Currently a DTD is not provided,
and the idea is that layout documents wont be checked against a DTD but
the parsing process will check for errors.

Tags and Attributes are case sensitive. Attribute values are/NOT/ case
sensitive. Following the list of recognized tags:

/Tag/     /Attribute/     /Description/
table                   Specify the begining of layout declaration

        cellpadding     This attribute specifies the internal padding of the
                        component, that is, how much to add to both minimun
                        width and height of the component. (default=0)

        cellspacing     This attribute specifies the external padding of the
                        component, the minimum amount of space between the
                        component and the edges of the cell (default=0)

tr                      Specify that a row of compoenents is being defined.

td                      Specify a cell.

        fill            Specify whether and how the component must grow to
                        fit the cell (if needed) Valid values are:
                        Both, Horizontal, Vertical and None (default: None).

        align           Specify the horizontal alignment of the component
                        inside the cell. Valid values are: Left, Right and
                        Center (default: Center)

        valign          Specify the vertical alignment of the component inside
                        the cell. Valud values are: Top, Bottom, Middle
                        (default: Middle).

        colspan         Specify how many columns this cell will take as a display
                        area (default: 1).

        width           The percentage of the row thar this cell will use.
                        Last cell will have all the remaining space.
                        Valid values: from 1% to 100%. Defaults to an even
                        distribution of space among cells.

        height          The percentage of the column that this cell will use.
                        Last cell will have all the remaining space.
                        Valid values: from 1% to 100%.
                        Defaults to an even distribution of space among cells.
        
        class           The style this cell will use (see below)

styles                  Opening element to group all the defined cell styles.

style                   Defines an style. It accepts all the td tag attributes
                        plus the attribute id

        id              Defines the id of this style, to be referenced by the class
                        atribute of the td tag

Let's see an example:

  1 <table cellpadding='2' cellspacing='1'>
  2    <styles>
  3        <style id='fillall' fill='BOTH' width='100%' height='50%' />
  4    </styles>
  5    <tr>
  6        <td align='right' width='50%' height='50%'>component1</td>
  7        <td align='left' width=50%' height=50%' valign='top'>component2</td>
  8    </tr>
  9    <tr>
 10        <td colspan='2' class='fillall'>component3</td>
 11    </tr>
 12 </table>
 13
 14

Let's explain it, line by line:

<table cellpadding='2' cellspacing='1'>

Here it's declaring a layout that has an internal padding of 2 pixels,
with 1 pixel separation between cells.

  <styles>
       <style id='fillall' fill='BOTH' width='100%' height='50%' />
   </styles>

Now it's defining the styles to be used in the layout. Specifically,
it's creating a style named "fillall", Cells that use this style will
have the 100% of the remaining horizontal space, 50% of the remaining
vertical space and the component will stretch in both directions to fill it.

   <tr>
       <td align='right' width='50%' height='50%'>component1</td>
       <td align='left' width=50%' height=50%' valign='top'>component2</td>
   </tr>

Defines a row with two cells. The first cell will have its content
aligned to the right (align='right'), will receive 50% of the remaining
horizontal space (width='50%'), 50% of the remaining vertical space
(height='50%') and is associated to the name component1. The second cell
will have its content aligned to the left (align='left') and to the top
(valign='top'), will receive 50% of the remaining horizontal space
(width='50%'), 50% of the remaining vertical space (height='50%') and is
associated to the name component2.

   <tr>
       <td colspan='2' class='fillall'>component3</td>
   </tr>

On the second row, there is only one cell that will span over 2 columns
(colspan='2'). Note that because the cell was associated to the class
"fillall" then it will have the properties as specified in the style
"fillall". This cell is associated to the name component3


    6. How to layout components?

After you build your XML specifying the layout, you must create an
XMLGridLayout instance with that layout, and then add component to the
container using the same names used in the XML. Example:

    JFrame frame=new JFrame();
    Container panel = frame.getContentPane();
    panel.setLayout(new XMLGridLayout(xmlLayout));

Now, you must create as many components as declared in the layout:

        JLabel label=new JLabel("This is a label");
        JTextField textField=new JTextField("This is a textField");
        JTextArea textArea=new JTextArea("This is a textArea");

And now add them to the container, using as the name of the component
the name used in the cell you want it to be:

panel.add("component1",label);
panel.add("component2",textField);
panel.add("component3",textArea);

To see the result, run the class/org.soronthar.layout.ReadmeExample/. In
the top-left corner of the screen you should see the frame configured
using XMLGridLayout, and in the center of the screen the one configured
with the GridBagLayout. Play with both and try to find any difference.

Just for the sake of comparison, here are the equivalent constraints
with GridBagLayout, as used in the example class:

panel.add(label, new GridBagConstraints(0, 0,
                                        1, 1,
                                        0.5, 0.5,
                                        GridBagConstraints.EAST,
                                        GridBagConstraints.NONE,
                                        new Insets(1, 1, 1, 1),
                                        2, 2));

panel.add(textField, new GridBagConstraints(1, 0,
                                            1, 1,
                                            0.5, 0.5,
                                            GridBagConstraints.NORTHWEST,
                                            GridBagConstraints.NONE,
                                            new Insets(1, 1, 1, 1),
                                            2, 2));

panel.add(textArea, new GridBagConstraints(0, 1,
                                           2, 1,
                                           1, 0.5,
                                           GridBagConstraints.CENTER,
                                           GridBagConstraints.BOTH,
                                           new Insets(1, 1, 1, 1),
                                           2, 2));


    7. Demo Classes

org.soronthar.layout.ReadmeExample     The class with the example in this
                                       document

org.soronthar.layout.DemoFrame        A very crude demo. Toy with it commenting and
                                      decomenting the "LabelC" component.

org.soronthar.layout.BigDemoFrame     A performance demo. After the frame in shown,
                                      check the console to see the time spend parsing
                                      the layout from the XML. Toy with it changing the 
                                      number of component, but be careful to maintain
                                      the number of columns on sync



*Copyright 2004 Rafael Alvarez (Soronthar)*
*Last Updated: 2004-07-28*

A XML Based Swing Layout Manager

| | Comments (0) | TrackBacks (0)
(reposted from a long-forgotten blog)

There used to be a movement to promote the creation of complex GUI using XML. This seems like a good idea, if you can find a nice way to express what you want.

IMO, the flaw in the implementations I have found so far is that all of them seems to mix up both definition of the component (properties, etc), the behavior of the component (Listener registration) and the Layout. Everything is thrown in the same bag and shaked. It's just a way to express things with XML instead of Java, so there is no true advantage to that approach unless you want to cut down the compilation process (see [1]).

So, why would I want to represent a GUI as XML?... I can see two reasons:
 * Ease the GUI manipulation by tools
 * Tackle the complexity of GUI building with Awt/Swing

The first one is pretty much straightforward: It's easier to maintain a script that has a well known (albeit rigid) semantic than to maintain a class that the programmer will try to modify to bend it to it's will.
The second point raises an interesting question: Is really that complex to create a GUI? If so, why?

Most Java  programmers I know tremble at the mention of two dreaded words: SWING and AWT. Those few braves who don't tremble, but are willing and sometimes eager to dive in the complexity of building, GUI start to shake at the mention of one "simple" class: GridBagLayout. This layout is famed for it's flexibility and complexity... Add this to the fact that struggling with the layout managers, preferred sizes, layout hints and so on to make the components be displayed the way we want can be one of the most titanical and time-consuming task in the GUI development and you can see that making a good GUI in Swing can be daunting to some people.

But what if laying out the GUI were a task as simple as building an HTML table? Perhaps this first barrier would be lifted and the programmer can concentrate in what he knows best: To program logic.

Playing with MT

|
Currently I'm playing with MoveableType, to learn how to use the templating system to create a beautiful website. Thus, this particular blog is set to "dynamically publish all templates" so I don't need to republish everything each time I do a change.

After I manage to learn how to do things, I'll put it back to "statically publish all templates". I like having the generated html around (being burned one to many times with dynamic content generation in other blog/wiki/content management systems).

June 2008

Sun Mon Tue Wed Thu Fri Sat
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30          

Categories