JComboBox renderer closes after each selection

Hello,

This follows my previous post regarding "How to add JCheckBox objects to JComboBox". With Ice's help, I've managed to make some good progress. So now I'm having other issues as I go further.

In the code below, I have the following issues:

1. My JComboBox renderer closes after each selection and I have to expand it again. I want my renderer to stay open until I'm done making selections and choose to close the renderer from the drop-down arrow in myComboBox.

2. At the moment, when I click on an item in my renderer, it gets selected (which is fine), but when I click on the box itself, it won't select/unselect.

Here's my SSCCE. Could Someone please help me out?

/*MyComboBoxTest.java*/

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import java.awt.event.MouseAdapter;

import java.awt.event.MouseEvent;

import javax.swing.JFrame;

import javax.swing.JComboBox;

publicclass MyComboBoxTestextends JComboBox

{

/**

* @param args

*/

JComboBox myComboBox;

public MyComboBoxTest()

{

myComboBox =new JComboBox();

}

publicstaticvoid main(String[] args){

final MyComboBoxTest myComboBox =new MyComboBoxTest();

myComboBox.getModel().setSelectedItem("Keywords");

myComboBox.insertItemAt("Select All", 0);

myComboBox.insertItemAt("Item1", 1);

myComboBox.insertItemAt("Item2", 2);

myComboBox.insertItemAt("Item3", 3);

myComboBox.insertItemAt("Item4", 4);

JFrame frame =new JFrame("My ComboBox");

frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

frame.setSize(150, 60);

frame.setLocation(300, 300);

frame.getContentPane().add(myComboBox);

frame.setVisible(true);

final IconedCellRenderer renderer = IconedCellRenderer.getCheckBoxRendererInstance();

renderer.setPaintDivider(true);

myComboBox.setRenderer( renderer );

myComboBox.addMouseListener(new MouseAdapter()

{

publicvoid mouseReleased(MouseEvent e)

{

for(int i=0;i<renderer.getSelStateList().length;i++)

{

System.out.println("renderer.getSelStateList["+i+"]: "+renderer.getSelStateList()[i]);

}

}

});

myComboBox.addActionListener(new ActionListener()

{

publicvoid actionPerformed(ActionEvent e)

{

System.out.println("Action Performed");

renderer.setVisible(true);

boolean isSelected = renderer.getSelStateList()[myComboBox.getSelectedIndex()];

if(isSelected==true)

{

if(myComboBox.getSelectedIndex()==0)

{

renderer.setSelStateList(null);

}

else

{

renderer.getSelStateList()[myComboBox.getSelectedIndex()]=false;

renderer.getSelStateList()[0]=false;

}

}

if(isSelected==false)

{

if(myComboBox.getSelectedIndex()==0)

{

for(int i=0;i<renderer.getSelStateList().length;i++)

{

renderer.getSelStateList()[i]=true;

}

}

else

{

renderer.getSelStateList()[myComboBox.getSelectedIndex()]=true;

}

}

}

});

}

}

And here's IconedCellRenderer, implemented by ICE, w/ minor changes from me, that I use as my JComboBox renderer.

/* IconedCellRenderer.java */

import java.awt.*;

import java.awt.event.*;

import java.util.*;

import javax.swing.*;

import javax.swing.border.*;

publicclass IconedCellRendererextends DefaultListCellRendererimplements MouseListener{

public Icon icon, selIcon;

Icon[] icons =null;

publicboolean useIconBackground = true, useIndexSensitiveIcons = false,

useCheckBoxAsIcon = false, useLinkState =false;

Dimension labelDim =null;

public JLabel iconLabel;

public JCheckBox box =null;

public JPanel noback;

public SelectionStateHandler selStateHandler =null;

private JList theList =null;

publicboolean[] selState = null, enableState =null;

int offset = 5;

Rectangle rect =null;

int currentLinkRow = -1;

boolean isOnRow = false, paintDivider =false;

private Icon dividerImage =null;

private Color linkColor = Color.gray, hoverColor = Color.red, selectedLinkColor = Color.green;

/* Initialises the renderer with one icon that is displayed without the

* cell background.

**/

public IconedCellRenderer(Icon icon){

this(icon,false);

}

/* Initialises the renderer with two icons that provide a switch capability

* when a row is selected/deselected

*/

public IconedCellRenderer(Icon icon, Icon selIcon){

this.icon = icon;

this.selIcon = selIcon;

//addMouseListener(this);

}

/* Initialises the renderer with two icons that provide a switch capability

* when a row is selected/deselected. The boolean argument enables the icon

* to either use the renderer background or appear transparent.

*/

public IconedCellRenderer(Icon icon, Icon selIcon,boolean useIconBackground){

this(icon, selIcon);

setIconHasBackground(useIconBackground);

createNoBackgroundPanel();

}

/* Initialises the renderer with a single no siwthing icon. The boolean

* argument enables the icon to either use the renderer background

* or appear transparent.

*/

public IconedCellRenderer(Icon icon,boolean useIconBackground){

this(icon, icon, useIconBackground);

}

/* Initialises the renderer to load two icons from the provided image locations.

* This enables icon switching on selection.

*/

public IconedCellRenderer(String iconLoc, String selIconLoc){

icon =new ImageIcon(iconLoc);

selIcon =new ImageIcon(selIconLoc);

//addMouseListener(this);

}

/* Initialises the renderer to load a single icon from the provided image location.

* The icon can either have the renderer background or not based on the

* boolean property.

*/

public IconedCellRenderer(String iconLoc,boolean iconBackground){

this(iconLoc, iconLoc, iconBackground);

}

/* Initialises the renderer to load two icons from the provided image locations.

* This enables icon switching on selection. The icon can either have the renderer

* background or not based on the boolean property.

*/

public IconedCellRenderer(String iconLoc, String selIconLoc,boolean iconBackground){

this(iconLoc, selIconLoc);

setIconHasBackground(iconBackground);

createNoBackgroundPanel();

}

/* Initialises the renderer to load a single icon from the provided image location.

*/

public IconedCellRenderer(String iconLoc){

this(iconLoc,true);

}

/* Initialises the renderer with an array of image icons that are repeated for

* each row in the list.

*/

public IconedCellRenderer(Icon[] icons,boolean useIconBackground){

this(icons[0], icons[0], useIconBackground);

}

publicvoid createNoBackgroundPanel(){

iconLabel =new JLabel((Icon)null, JLabel.CENTER);

if(labelDim !=null){ iconLabel.setPreferredSize(labelDim);}

iconLabel.setBorder(new EmptyBorder(1,5,1,5) );

noback =new JPanel(new BorderLayout() ){

/**

* Overridden for performance reasons.

* See the ><a href="#override">Implementation Note</a>

* for more information.

*/

//public void validate() {}

// public void invalidate() {}

publicvoid repaint(){}

//public void revalidate() {}

publicvoid repaint(long tm,int x,int y,int width,int height){}

publicvoid repaint(Rectangle r){}

protectedvoid firePropertyChange(String propertyName, Object oldValue, Object newValue){

// Strings get interned...

if (propertyName =="text"

|| ((propertyName =="font" || propertyName =="foreground")

&& oldValue != newValue)){

super.firePropertyChange(propertyName, oldValue, newValue);

}

}

publicvoid firePropertyChange(String propertyName,byte oldValue,byte newValue){}

publicvoid firePropertyChange(String propertyName,char oldValue,char newValue){}

publicvoid firePropertyChange(String propertyName,short oldValue,short newValue){}

publicvoid firePropertyChange(String propertyName,int oldValue,int newValue){}

publicvoid firePropertyChange(String propertyName,long oldValue,long newValue){}

publicvoid firePropertyChange(String propertyName,float oldValue,float newValue){}

publicvoid firePropertyChange(String propertyName,double oldValue,double newValue){}

publicvoid firePropertyChange(String propertyName,boolean oldValue,boolean newValue){}

};

if(useCheckBoxAsIcon()){

box =new JCheckBox();

box.setOpaque(false);

noback.add( box, BorderLayout.WEST );

rect = box.getBounds();

}else{

noback.add( iconLabel, BorderLayout.WEST );

}

noback.add( this, BorderLayout.CENTER );

noback.setBorder(new EmptyBorder(1,1,1,1) );

noback.setOpaque(false);

}

public Component getListCellRendererComponent(JList list, Object value,int index,

boolean isSelected,boolean cellHasFocus){

if(theList ==null || theList != list){

theList = list;

if(useLinkState){

attachLinkSimulationListener();

}

}

setOpaque(true);

setText( value ==null ?"" : value.toString());

if(useIndexSensitiveIcons){

icon = getIcon(index);

}

if(useIconBackground)

setIcon(icon);

setFont( list.getFont() );

setToolTipText(value.toString() );

if(list.isEnabled())

setEnabled( isEnabled(index) );

else

setEnabled( list.isEnabled() );

if(isSelected && isEnabled(index) ){

setForeground( Color.black );

setBackground(new Color(2250, 214, 138) );

if(useIndexSensitiveIcons){

selIcon = getIcon(index);

}

if(useIconBackground)

setIcon(selIcon);

}else{

setForeground(Color.black);

setBackground(Color.white);

setBorder(null);

}

if(cellHasFocus){

setBorder(new CompoundBorder(new LineBorder(new Color(150, 150, 220) ),

new EmptyBorder(2,2,2,2) ) );

}

if(useLinkState){

if(currentLinkRow == index){

setText("<html><u>" + value.toString() +"</u></html>" );

setForeground( getHoverLinkColor() );

}else{

setForeground( getLinkColor() );

}

if(isSelected){

setForeground( getSelectedLinkColor() );

}

setBackground(Color.white);

setBorder(new EmptyBorder(1,1,1,1) );

}

if( shdPaintDivider() ){

Border border =null;

if(index==1)

{

if(dividerImage !=null){

border =new MatteBorder(1,0,0,0, dividerImage);

}else{

border =new MatteBorder(1,0,0,0, getLinkColor() );

}

if(index < theList.getModel().getSize() - 1 ){

setBorder(new CompoundBorder(getBorder(),border) );

}else{

setBorder(new EmptyBorder(1,1,1,1) );

}

}

}

if(useIconBackground ==false){

if(isSelected)

iconLabel.setIcon(selIcon);

else

iconLabel.setIcon(icon);

if(useCheckBoxAsIcon()){

if(selState ==null){

updateSelectionStateTrackers(list);

}

if(selStateHandler ==null){

list.addMouseListener( selStateHandler =new SelectionStateHandler(list) );

}

//if selStateHandler is not null

try{

box.setSelected( selState[index] );

setSelStateList(selState);

}catch(Exception e){}

}

if( shdPaintDivider() ){

//if(index < theList.getModel().getSize() - 1 ) {

noback.setBorder( getBorder() );

setBorder(new EmptyBorder(1,1,1,1) );

//} else {

// noback.get

//}

}

// this should cause a JComboBox to paint the Label instead of the

// check box + label combination

if(index == -1){

JLabel label =new JLabel( this.getText() );

if(iconLabel.getIcon() !=null){

label.setIcon( iconLabel.getIcon() );

}

return label;

}

return noback;

}

returnthis;

}

publicvoid updateSelectionStateTrackers(JList list){

selState =newboolean[ list.getModel().getSize() ];

enableState =newboolean[ list.getModel().getSize() ];

for(int i = 0; i < selState.length; i++){

selState[i] =false;

enableState[i] =true;

setSelStateList(selState);

}

}

publicint[] getSelectedIndices(){

if(!useCheckBoxAsIcon()){

returnnewint[0];

}

int length = 0;

for(int i = 0; i < selState.length; i++){

if(selState[i]){

length++;

setSelStateList(selState);

}

}

int[] indices =newint[length];

for(int i = 0, n = 0; i < selState.length; i++){

if(selState[i]){

indices[n++] = i;

setSelStateList(selState);

}

}

//System.out.println("Selected Indices.length = " + indices.length);

return indices;

}

public Vector getSelectedObjects(){

int[] indices = getSelectedIndices();

Vector objects =new Vector();

for(int i = 0; i < indices.length; i++){

objects.addElement( theList.getModel().getElementAt(indices[i]) );

}

return objects;

}

publicvoid setIconHasBackground(boolean b){

useIconBackground = b;

}

public Icon[] getIcons(){

return icons;

}

public Icon getIcon(int index){

if(icons !=null && icons.length == 0){

return icon;

}

if(icons !=null && index > icons.length){

index = index - (icons.length - 1);

}

return icons[index];

}

publicvoid setIcons(Icon[] icons){

if(icons !=null){

useIndexSensitiveIcons =true;

}

this.icons = icons;

}

publicvoid setIcon(Icon icon,int index){

if(icons !=null && icons.length > 0){

icons[index] = icon;

}

}

publicvoid setIconLabelDimension(Dimension dim){

labelDim = dim;

}

publicstatic IconedCellRenderer getCheckBoxRendererInstance(){

IconedCellRenderer cr =new IconedCellRenderer(new EmptyIcon());

cr.setUseCheckBoxAsIcon(true);

return cr;

}

publicvoid setUseCheckBoxAsIcon(boolean use){

useCheckBoxAsIcon = use;

createNoBackgroundPanel();

}

publicboolean useCheckBoxAsIcon(){

return useCheckBoxAsIcon;

}

publicvoid paintComponent(Graphics g){

super.paintComponent(g);

}

publicvoid setDisplayItemsAsLinks(boolean use){

useLinkState = use;

}

publicvoid setLinkColor(Color color){

linkColor = color;

if(theList !=null){

theList.repaint();

}

}

public Color getLinkColor(){

return linkColor;

}

publicvoid setHoverLinkColor(Color color){

hoverColor = color;

if(theList !=null){

theList.repaint();

}

}

public Color getHoverLinkColor(){

return hoverColor;

}

publicvoid setSelectedLinkColor(Color color){

selectedLinkColor = color;

if(theList !=null){

theList.repaint();

}

}

public Color getSelectedLinkColor(){

return selectedLinkColor;

}

publicvoid attachLinkSimulationListener(){

theList.setCursor( Cursor.getPredefinedCursor(Cursor.HAND_CURSOR) );

theList.addMouseListener(new MouseAdapter(){

publicvoid mouseEntered(MouseEvent e){

isOnRow =true;

}

publicvoid mouseExited(MouseEvent e){

isOnRow =false;

currentLinkRow = -1;

theList.repaint();

}

});

theList.addMouseMotionListener(new MouseMotionAdapter(){

publicvoid mouseMoved(MouseEvent e){

isOnRow =true;

currentLinkRow = theList.locationToIndex( e.getPoint() );

theList.repaint();

}

});

/*table.addMouseListener(new MouseAdapter() {

public void mouseEntered(MouseEvent e) {

}

public void mouseExited(MouseEvent e) {

isOnRow = false;

currentHighlightRow = -1;

table.repaint();

}

});

table.addMouseMotionListener( new MouseMotionAdapter() {

public void mouseMoved(MouseEvent e) {

isOnRow = true;

currentHighlightRow = table.rowAtPoint( e.getPoint() );

table.repaint();

}

});*/

}

publicboolean shdPaintDivider(){

return paintDivider;

}

publicvoid setPaintDivider(boolean paintDivider){

this.paintDivider = paintDivider;

}

publicvoid setDividerImage(Icon icon){

this.dividerImage = icon;

setPaintDivider(true);

}

privatevoid dispatchEvent(MouseEvent me){

if(rect !=null && box !=null && rect.contains(me.getX(), me.getY())){

Point pt = me.getPoint();

pt.translate(0,0);

box.setBounds(rect);

box.dispatchEvent(new MouseEvent(box, me.getID()

, me.getWhen(), me.getModifiers()

, pt.x, pt.y, me.getClickCount()

, me.isPopupTrigger(), me.getButton()));

if(!box.isValid()){

repaint();

System.out.println("Dispatch Event: Box.invalid called");

}

System.out.println("Dispatch Event called");

}else{

System.out.println("Dispatch Event Called, rect null");

}

}

publicvoid mouseClicked(MouseEvent me){

dispatchEvent(me);

}

publicvoid mouseEntered(MouseEvent me){

dispatchEvent(me);

}

publicvoid mouseExited(MouseEvent me){

dispatchEvent(me);

}

publicvoid mousePressed(MouseEvent me){

dispatchEvent(me);

}

publicvoid mouseReleased(MouseEvent me){

dispatchEvent(me);

}

publicclass SelectionStateHandlerextends MouseAdapter{

JList list =null;

public SelectionStateHandler(JList list){

this.list = list;

/*for(int i=0;i<list.getModel().getSize();i++)

{

System.out.println(list.getModel().getElementAt(i));

}*/

}

/*

* Handles the checkbox selection process. Uses the bounds property of the

* check box within the selected cell to determine whether the checkbox should

* be selected or not

**/

publicvoid mouseReleased(MouseEvent e){

if(list ==null || list.getSelectedIndex() == -1

|| !isEnabled( list.locationToIndex(e.getPoint()) ) ){

return;

}

int[] indices = list.getSelectedIndices();

// get the current relative position of the check box

//rect = box.getBounds(rect);

for(int i = 0; i >< indices.length; i++){

// get the current relative position of the check box

int loc = list.locationToIndex( e.getPoint() );

rect = list.getCellBounds(loc,loc);

// ensure the point clicked in within the checkBox

if(e.getX() < (rect.getX() + 20) ){

selState[indices[i]] = !selState[indices[i]];

setSelStateList(selState);

}

}

list.revalidate();

list.repaint();

}

publicvoid selectAll(boolean b){

for(int i = 0; i < list.getModel().getSize(); i++){

try{

selState[i] = b;

}catch(ArrayIndexOutOfBoundsException aie){

updateSelectionStateTrackers(list);

selectAll(b);

return;

}

}

if(list !=null){

list.revalidate();

list.repaint();

}

}

publicvoid setSelectedIndex(int index){

for(int i = 0; i < list.getModel().getSize(); i++){

selState[i] =false;

}

setSelStateList(selState);

selectIndex(index);

}

publicvoid selectIndex(int index){

try{

selState[index] =true;

setSelStateList(selState);

}catch(ArrayIndexOutOfBoundsException aie){

updateSelectionStateTrackers(list);

selectIndex(index);

return;

}

if(list !=null){

list.revalidate();

list.repaint();

}

}

publicvoid setEnabled(int index,boolean b){

try{

enableState[index] = b;

}catch(ArrayIndexOutOfBoundsException aie){

updateSelectionStateTrackers(list);

setEnabled(index, b);

}

}

publicboolean isEnabled(int index){

if(index == -1){

returntrue;

}

boolean isEnabled =true;

try{

isEnabled = enableState[index];

}catch(ArrayIndexOutOfBoundsException aie){

updateSelectionStateTrackers(list);

return isEnabled(index);

}

return isEnabled;

}

publicvoid enableAll(boolean b){

for(int i = 0; i < enableState.length; i++){

enableState[i] = b;

}

}

}

publicvoid selectAll(boolean b){

if(selStateHandler ==null){

return;

}

selStateHandler.selectAll(b);

}

publicvoid setSelectedIndex(int index){

if(selStateHandler ==null){

return;

}

selStateHandler.setSelectedIndex(index);

}

publicvoid selectIndex(int index){

if(selStateHandler ==null){

return;

}

selStateHandler.selectIndex(index);

}

publicvoid enableAll(boolean b){

if(selStateHandler ==null){

return;

}

selStateHandler.enableAll(b);

}

publicvoid setEnabled(int index,boolean enable){

if(selStateHandler ==null){

return;

}

selStateHandler.setEnabled(index, enable);

}

publicboolean isEnabled(int index){

if(selStateHandler ==null){

returntrue;

}

return selStateHandler.isEnabled(index);

}

publicboolean isEnabledAll(){

if(enableState ==null)returntrue;

for(int i = 0; i < enableState.length; i++){

if(!isEnabled(i)){

returnfalse;

}

}

returntrue;

}

publicvoid setSelStateList(boolean [] selState)

{

this.selState = selState;

}

publicboolean[] getSelStateList()

{

return selState;

}

// EmptyIcon implementation

publicstaticclass EmptyIconimplements Icon{

int width = 16, height = 16;

public EmptyIcon(){

setSize(16,16);

}

public EmptyIcon(int width,int height){

setSize(width, height);

}

publicvoid setSize(int width,int height){

this.width = width;

this.height = height;

}

publicint getIconWidth(){return width;}

publicint getIconHeight(){return height;}

publicvoid paintIcon(Component c, Graphics g,int x,int y){}

}

}

[50340 byte] By [programmer_girla] at [2007-11-27 11:51:03]
# 1

Hiya p_g. Here is a quick fix to your problem (Done according to requirements posted)

import java.awt.*;

import java.awt.event.*;

import javax.swing.*;

public class MyComboBoxTest extends JComboBox {

//JComboBox myComboBox;

public MyComboBoxTest() {

super();

}

public void setPopupVisible(boolean b) {

if(!b) {

//super.hidePopup();

} else {

super.showPopup();

}

}

public static void main(String[] args) {

final MyComboBoxTest myComboBox = new MyComboBoxTest();

myComboBox.getModel().setSelectedItem("Keywords");

myComboBox.insertItemAt("Select All", 0);

myComboBox.insertItemAt("Item1", 1);

myComboBox.insertItemAt("Item2", 2);

myComboBox.insertItemAt("Item3", 3);

myComboBox.insertItemAt("Item4", 4);

JFrame frame = new JFrame("My ComboBox");

frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

frame.setSize(150, 60);

frame.setLocation(300, 300);

frame.getContentPane().add(myComboBox);

frame.setVisible(true);

final IconedCellRenderer renderer = IconedCellRenderer.getCheckBoxRendererInstance();

renderer.setPaintDivider(true);

myComboBox.setRenderer( renderer );

}

}

Honestly, you did not need to post the entire mountain of code, (although someone might need later). Also, about the two methods you added to IconedCellRenderer, I'm not exactly sure what they are supposed to do cause the cellrenderer already handles the selection and deselection of the checkboxes (which works on my system without a hitch in the above example).

ICE

icewalker2ga at 2007-7-29 18:35:53 > top of Java-index,Desktop,Core GUI APIs...
# 2

Your question is about keeping the popup open. We don't care about the other cusomizations you have done to the combo box. The other code has abosolutely nothing to do with keeping the combo box open.

First figure out how to solve this problem using the default combo box. Then once that is working you move on to incorporate what you learned with this problem to get is working with your other code.

The first two letters of SSCCE are "Short and Simple". You will never learn to problem solve if your code is 400 lined long.

camickra at 2007-7-29 18:35:53 > top of Java-index,Desktop,Core GUI APIs...
# 3

Hello! Thanks again for your help.

Now my JComboBox renderer stays open until I decide to close it, which is great.

About the two methods I added to IconedCellRenderer, I added them because I needed to use them in MyComboBoxTest. Before I used these two methods in MyComboBoxTest, in order to select/deselect a JCheckBox I needed to click on the box itself, as opposed to anywhere on the text.So now, after these changes I'm able to click anywhere on the JCheckBox text (not just the actual box icon) and select/deselect.

Although, now when I click on the box itself it doesn't do anything. So, that's what I need your help with.

Thanks!

programmer_girla at 2007-7-29 18:35:53 > top of Java-index,Desktop,Core GUI APIs...
# 4

> Although, now when I click on the box itself it doesn't do anything. So, that's what I need your help with.

That is why I said they were unnecessary. You should take time to go over the code in the renderer class to see what is actually does, not just use it cause you are in a jam.

Below is a section from the SelectionStateHandler inner class of renderer, which actually takes care of all the mouse clicking and selection of the items. Comment out the if statement in the for loop to enable check box selection when any part of the item is clicked. You can always uncomment it to return to original functionality.

public void mouseReleased(MouseEvent e) {

if(list == null || list.getSelectedIndex() == -1

|| !isEnabled( list.locationToIndex(e.getPoint()) ) ) {

return;

}

int[] indices = list.getSelectedIndices();

// get the current relative position of the check box

//rect = box.getBounds(rect);

for(int i = 0; i < indices.length; i++) {

// get the current relative position of the check box

int loc = list.locationToIndex( e.getPoint() );

rect = list.getCellBounds(loc,loc);

// ensure the point clicked in within the checkBox

if(e.getX() < (rect.getX() + 20) ) {

selState[indices[i]] = !selState[indices[i]];

}

}

list.revalidate();

list.repaint();

}

ICE

icewalker2ga at 2007-7-29 18:35:53 > top of Java-index,Desktop,Core GUI APIs...
# 5

Ice, you might not believe this. But right before I read your solution, I was looking at the renderer and found the line of code that was doing this. So I just took it out. It's where it says "ensure the point clicked in within the checkBox" in the mouseReleased method inside SelectionStateHandler, which is exactly where you made your changes in the last post.

Thanks again. I think I'm starting to think well :)

programmer_girla at 2007-7-29 18:35:53 > top of Java-index,Desktop,Core GUI APIs...