Problemns with JTree

Hi! I'm having problems with the Tree cell renderer. I must render a tree that have leafs that is also JPanels compounded by a checkbox, an icon and a the text label. It's supposed to alter the state of the checkbox when clicked or when press the spacebar over the cell, but it isn't working...

If I set the tree as editable (down in the code, in main method), the checkbox is selected only after the second click, but the cell is not being highlighted and cannot collapse the category nodes. Otherwise, when set the Tree as NOT editable, the highlight of cell and the rest works, but obviously I cannot edit the checkboxes...

Can someone help me, please?

package test;

import com.interact.sas.ResourceLocator;

import com.interact.sas.dms.*;

import com.interact.sas.ui.UserIconLabel;

import java.awt.*;

import java.awt.event.KeyAdapter;

import java.awt.event.KeyEvent;

import java.util.EventObject;

import java.util.Vector;

import javax.swing.*;

import javax.swing.border.*;

import javax.swing.tree.*;

publicclass DocumentControllerTreeTest

{

staticclass MyTreeCellEditorextends AbstractCellEditorimplements TreeCellEditor, TreeCellRenderer

{

privatestatic Icon iconCategory = ResourceLocator.getIcon("sas/dms/tb_categories.png" );

privatestatic Border noFocusBorder =new EmptyBorder( 1, 1, 1, 1 );

private JPanel cell =new JPanel();

private JCheckBox checkRequired =new JCheckBox();

private UserIconLabel userIconLabel =new UserIconLabel();

private DocumentControllerTree.Item currentItem =null;

public MyTreeCellEditor()

{

userIconLabel.setOpaque(false );

checkRequired.setOpaque(false );

cell.setLayout(new BorderLayout() );

cell.add( checkRequired, BorderLayout.WEST );

cell.add( userIconLabel, BorderLayout.CENTER );

cell.addKeyListener(new KeyAdapter()

{

publicvoid keyPressed( KeyEvent e )

{

if ( e.getKeyCode() == KeyEvent.VK_SPACE )

{

checkRequired.setSelected( ! checkRequired.isSelected() );

e.consume();

}

}

} );

cell.addMouseListener(new java.awt.event.MouseAdapter()

{

publicvoid mouseClicked(java.awt.event.MouseEvent evt)

{

checkRequired.setSelected( ! checkRequired.isSelected() );

}

});

}

/**

* getCellEditorValue

*

* @return Object

*/

public Object getCellEditorValue()

{

currentItem.getController().setRequired( checkRequired.isSelected() );

returnnew Boolean( currentItem.getController().isRequired() );

}

/**

* getTreeCellEditorComponent

*

* @param JTree tree,

* @param Object value,

* @param boolean isSelected,

* @param boolean expanded,

* @param boolean leaf,

* @param int row

* @return Component

*/

public Component getTreeCellEditorComponent( JTree tree,

Object value,

boolean isSelected,

boolean expanded,

boolean leaf,

int row)

{

return getTreeCellRendererComponent( tree, value, isSelected, expanded, leaf, row,true );

}

/**

* getTreeCellRendererComponent

*

* @param JTree tree,

* @param Object value,

* @param boolean selected,

* @param boolean expanded,

* @param boolean leaf,

* @param int row,

* @param boolean hasFocus

* @return Component

*/

public Component getTreeCellRendererComponent( JTree tree,

Object value,

boolean isSelected,

boolean isExpanded,

boolean isLeaf,

int row,

boolean hasFocus )

{

DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;

Object object = node.getUserObject();

if ( objectinstanceof DocumentControllerTree.Item )

{

currentItem = (DocumentControllerTree.Item) object;

checkRequired.setSelected( currentItem.getController().isRequired() );

//checkRequired.setSelected( !checkRequired.isSelected() );

int action = currentItem.getController().getAction();

if ( action == DocumentController.ACTION_APROVE ||

action == DocumentController.ACTION_VERIFY )

{

checkRequired.setVisible(true );

}

else

{

checkRequired.setVisible(false );

}

userIconLabel.setFont( tree.getFont() );

userIconLabel.setUser( currentItem.getUser() );

userIconLabel.setText( currentItem.getUser().getName() );

}

else

{

// nunca poderia chegar aqui ...

checkRequired.setVisible(false );

userIconLabel.setFont( tree.getFont() );

userIconLabel.setIcon( ! isLeaf ? iconCategory :null );

userIconLabel.setText( object.toString() );

}

if ( isSelected )

{

cell.setBackground( UIManager.getColor("Tree.selectionBackground") );

cell.setForeground( UIManager.getColor("Tree.selectionForeground") );

}

else

{

cell.setBackground( tree.getBackground() );

cell.setForeground( tree.getForeground() );

}

Border border = noFocusBorder;

if (hasFocus)

{

if (isSelected)

{

border = UIManager.getBorder("List.focusSelectedCellHighlightBorder");

}

if (border ==null)

{

border = UIManager.getBorder("List.focusCellHighlightBorder");

}

}

cell.setBorder(border);

return cell;

}

}

publicstaticvoid main( String[] args )

{

try

{

DocumentControllerTree tree =new DocumentControllerTree();

DocumentManager dm = DocumentManager.getInstance();

DocumentCategory dc = dm.getCategory( 32 );

Vector<DocumentController> vdc = dm.getControllers( dc );

tree.setCellRenderer(new MyTreeCellEditor() );

tree.setCellEditor(new MyTreeCellEditor() );

tree.setCategory( dc );

tree.setControllers( vdc );

// This must be true

//tree.setEditable( true );

JScrollPane scroller =new JScrollPane( tree );

scroller.setPreferredSize(new Dimension( 240, 320 ) );

JOptionPane.showMessageDialog( null, scroller );

}

catch ( Exception e )

{

e.printStackTrace();

}

System.exit( 0 );

}

}

[10768 byte] By [Janioa] at [2007-11-27 8:19:39]
# 1
It is a bad idea to be trying to base your tree model on a JPanel. Build a proper treemodel with data backing it and handle the rest with the renderer and editor settings
tjacobs01a at 2007-7-12 20:07:51 > top of Java-index,Desktop,Core GUI APIs...
# 2
Yes, make this cell in the renderer?Make sense. I'll try it.
Janioa at 2007-7-12 20:07:51 > top of Java-index,Desktop,Core GUI APIs...
# 3
Did you look at http://propertytree.dev.java.net/ ? I haven't read your code completely, but from what you say, it seems this is approximately the same thing.
rebola at 2007-7-12 20:07:51 > top of Java-index,Desktop,Core GUI APIs...
# 4

> Did you look at http://propertytree.dev.java.net/ ? I

> haven't read your code completely, but from what you

> say, it seems this is approximately the same thing.

I have been seeing the site for now, and also the source code, but I don't want to use this jar library. Mine is different, and to keep the look of my project, the checkbox is the first component in the left and is the only editable object.

Janioa at 2007-7-12 20:07:51 > top of Java-index,Desktop,Core GUI APIs...
# 5

Then remember: one click to have focus in a tree node, and only then is the chackbox available to be clicked. That's why you need two clicks, I think. If you want it otherwise, have the tree (or the cellrenderer or whatever) forward so it reaches the combobox immediately.

Still haven't read your code, but remember that the default cellrenderer implementation only paints the cells - they are not present themselves on screen, they are merely painted, 玜s if? (You probably have already read that somewhere else).

rebola at 2007-7-12 20:07:51 > top of Java-index,Desktop,Core GUI APIs...
# 6
Ok, can I have the same class as an editor and renderer, as is now?Or they must be separated?The problem is not only the focus, it is very strange...Message was edited by: Janio
Janioa at 2007-7-12 20:07:51 > top of Java-index,Desktop,Core GUI APIs...
# 7

Well, I wouldn't have, but as far as I can see,it should be possible. Bear in mind, though, that debugging is far simpler when methods are as simple as possible. I firmly believe that you would track your bug in no time if you had different classes for rendering and editing.

Can't test your code since you use the com.interact.sas.*stuff.

rebola at 2007-7-12 20:07:51 > top of Java-index,Desktop,Core GUI APIs...
# 8

OMG... I'm trying various things, but I'm very confused...

I even created a class Cell, that extends from JPanel (and I added the checkbox and labels to it) and implements TreeCellEditor, and in the class that extends from JTree I use the same Cell as a renderer and I pass the same objects to the constructor of Cell... I know, it is not good...

In the class that extends from JTree, I set the model in constructor passing the root node, like this: setModel( new DefaultTreeModel( root ) );

This Tree is giving me much work... and I'm not a novice with Java...

I'm grateful for your help, guys, but you or anyone can explain me how is the best way to achieve my objective?

Message was edited by:

Janio

Janioa at 2007-7-12 20:07:51 > top of Java-index,Desktop,Core GUI APIs...
# 9

OK, here's briefly what I'd do:

1

In your tree constructor, set a custom TreeCellRenderer. (I assume your tree extends JTree.)

2

Create a custom TreeCellRenderer by extending JPanel and implementing TreeCellRenderer. In the getTreeCellRendererComponent method, remember you don't have to use a component that you have around. You use the tree node's text: tree.convertValueToText(value, sel, expanded, leaf, row, hasFocus));

This returns a string. The string could be "true" or "false". You then create a JCheckBox based on this value. Add the JCheckBox to 玹his? i.e. to the custom TreeCellRenderer that extends a JPanel. Return 玹his? Remember that once 玹his?is returned, the value is forgotten and the JCheckBox is unclickable. (What you click actually is the TreeCellRenderer, that then decides you want to focus a node and thereafter passes focus and subsequent clicks to your panel and/or the TreeCellEditor).

3

Back to the tree constructor. Set your TreeCellEditor to a custom class of yours. Copy the code from DefaultCellEditor. There is a constructor in DefaultCellEditor that accepts a JCheckBox as sole argument. Try that one. In an inner class in DefaultCellEditor, EditorDelegate, you'll find the stopCellEditing method. Override it and make sure to convert boolean values back to "true" or "false" in the tree node, so that the renderer will have the right value to work with.

From there on, I guess things should work by themselves. (Warning: completely unchecked!!!) If not, at least the code is sufficiently separated for us to know where it fails (renderer, editor, tree...)

PS. Second thought: DefaultMutableTreeNode accepts an Object as object, not only a string. Maybe you could use a boolean value or a Boolean object directly in the tree node instead of strings...

Just my 2 cents

rebola at 2007-7-12 20:07:51 > top of Java-index,Desktop,Core GUI APIs...
# 10

I tried some of your tips, but it doesn't worked correctly for me, maybe because I'm using own components. But the tips have helped me!

I'm not using anymore the code that appears in the first topic. I'm trying another solution: created a TreeCellRenderer that have a JPanel cell and in the JPanel I added the checkbox and a component that is a label with an Icon and a String. Created also a TreeCellEditor with the same components. The major part of problems have been solved and the checkboxes is working properly, but I can't use the arrows of the keyboard to circle through the nodes (like in anyone JTree...) and I have problems adding and deleting a node from the tree... if I click only one time over the node and after press the button to add an element, it works... but if I click more times in the node (like editing the checkbox) and press the button to add or delete nodes, it causes a NullPointerException in my method buildTree(), in the line

((DefaultTreeModel)getModel()).nodeStructureChanged( (DefaultMutableTreeNode)getModel().getRoot() );

Probably both problems exists because I have too much objetcs inside another object inside a component inside another component... and I'm not administrating these correctly... Any tips?

Janioa at 2007-7-12 20:07:51 > top of Java-index,Desktop,Core GUI APIs...
# 11

Finally! All is resolved and the tree is working. I created a class named Cell that extends from JPanel and there I put the components and Values. All the nodes of the Tree are Cell's objects now. Also created the renderer and editor classes. Must make full use of the OO Programming.

And the null error that I mentioned above is why needed to collapse the Tree before the call... I dunno why...

Thank you guys, you helped me.

Janioa at 2007-7-12 20:07:51 > top of Java-index,Desktop,Core GUI APIs...