A Renderer and a Listener should be able to handle... custom components... the key is the interaction event ..
Four classes: CheckTreeDemo, CheckTree, Node, CheckRenderer, and CheckListener
It can be seen from the class name that CheckTreeDemo is a JFrame class CheckTree is a component, Node is a data model, CheckRenderer is the rendering of the CheckTree, and CheckListener is the event of the CheckTree.
Package tree;
Import java. awt. BorderLayout;
Import javax. swing. JFrame;
Import javax. swing. JPanel;
Import javax. swing. SwingUtilities;
/**
*
* @ Author chensiyu
* @ CreateDate 2011/8/24
*/
Public class CheckTreeDemo extends JPanel {
Private CheckTree checkTree;
Public CheckTreeDemo (){
Init ();
}
Private void init (){
SetLayout (new BorderLayout ());
Node rootNode = new Node ("Root ");
Node [] nodes = new Node [10];
For (int I = 0; I <nodes. length; I ++ ){
Node node = new Node ("Node-" + I );
RootNode. add (node );
}
CheckTree = new CheckTree (rootNode );
Add (checkTree, BorderLayout. CENTER );
}
Public static void main (String [] args ){
Final JFrame frame = new JFrame ();
Frame. setTitle ("CheckTree ");
Frame. setLayout (new BorderLayout ());
Frame. setSize (200,400 );
Frame. getContentPane (). add (new CheckTreeDemo ());
Frame. setdefaclocloseoperation (JFrame. EXIT_ON_CLOSE );
SwingUtilities. invokeLater (new Runnable (){
@ Override
Public void run (){
Frame. setVisible (true );
}
});
}
}
Package tree;
Import javax. swing. JTree;
Import javax. swing. tree. TreeNode;
/**
*
* @ Author chensiyu
* @ CreateDate 2011/8/24
*/
Public class CheckTree extends JTree {
Private CheckRenderer checkRenderer;
Private CheckListener checkListener;
Public CheckTree (){
Init ();
}
Public CheckTree (TreeNode node ){
Super (node );
Init ();
}
Private void init (){
CheckRenderer = new CheckRenderer ();
CheckListener = new CheckListener ();
SetCellRenderer (checkRenderer );
AddMouseListener (checkListener );
}
}
Package tree;
Import javax. swing. tree. DefaultMutableTreeNode;
/**
*
* @ Author chensiyu
* @ CreateDate 2011/8/24
*/
Public class Node extends DefaultMutableTreeNode {
Private String name = "";
Private boolean selected = false;
Public Node (String name ){
Super (name );
SetName (name );
}
Public String getName (){
Return name;
}
Public void setName (String name ){
This. name = name;
}
Public boolean isSelected (){
Return selected;
}
Public void setSelected (boolean selected ){
This. selected = selected;
}
}
Package tree;
/**
*
* @ Author chensiyu
* @ CreateDate 2011/8/24
*/
Import java. awt .*;
Import javax. swing .*;
Import javax. swing. tree .*;
Class CheckRenderer extends JPanel implements TreeCellRenderer {
Protected static JCheckBox check;
Protected JLabel label;
Private static Rectangle checkBounds;
Public CheckRenderer (){
SetLayout (null );
Add (check = new JCheckBox ());
Add (label = new JLabel (""));
Check. setBackground (UIManager. getColor ("Tree. textBackground "));
Label. setForeground (UIManager. getColor ("Tree. textForeground "));
}
@ Override
Public Component getTreeCellRendererComponent (JTree tree, Object value,
Boolean isSelected, boolean expanded, boolean leaf, int row,
Boolean hasFocus ){
String stringValue = tree. convertValueToText (value, isSelected,
Expanded, leaf, row, hasFocus );
SetEnabled (tree. isEnabled ());
Label. setFont (tree. getFont ());
Label. setText (stringValue );
SetBackground (tree. getBackground ());
SetForeground (tree. getForeground ());
If (value instanceof Node ){
Node node = (Node) value;
Check. setSelected (node. isSelected ());
}
Return this;
}
@ Override
Public Dimension getPreferredSize (){
Dimension d_check = check. getPreferredSize ();
Dimension d_label = label. getPreferredSize ();
Return new Dimension (d_check.width + d_label.width,
(D_check.height <d_label.height? D_label.height
: D_check.height ));
}
@ Override
Public void doLayout (){
Dimension d_check = check. getPreferredSize ();
Dimension d_label = label. getPreferredSize ();
Int y_check = 0;
Int y_label = 0;
If (d_check.height <d_label.height ){
Y_check = (d_label.height-d_check.height)/2;
} Else {
Y_label = (d_check.height-d_label.height)/2;
}
Check. setLocation (0, y_check );
Check. setBounds (0, y_check, d_check.width, d_check.height );
Label. setLocation (d_check.width, y_label );
Label. setBounds (d_check.width, y_label, d_label.width, d_label.height );
If (checkBounds = null ){
CheckBounds = check. getBounds ();
}
}
Public static Rectangle getCheckBoxRectangle (){
If (null = checkBounds)
Return new Rectangle (0, 0, 0 );
Return (Rectangle) checkBounds. clone ();
}
}
Package tree;
Import java. awt. Point;
Import java. awt. Rectangle;
Import java. awt. event. MouseAdapter;
Import java. awt. event. MouseEvent;
Import javax. swing. JTree;
Import javax. swing. tree. TreePath;
/**
*
* @ Author chensiyu
* @ CreateDate 2011/8/24
*/
Class CheckListener extends MouseAdapter {
Public CheckListener (){
}
@ Override
Public void mouseClicked (MouseEvent e ){
JTree tree = (JTree) e. getSource ();
Point p = e. getPoint ();
Int x = e. getX ();
Int y = e. getY ();
Int row = tree. getRowForLocation (x, y );
TreePath path = tree. getPathForRow (row );
If (null = path ){
Return;
}
Object component = path. getLastPathComponent ();
If (null = component ){
Return;
}
If (component instanceof Node ){
Rectangle chRect = CheckRenderer. getCheckBoxRectangle ();
Rectangle rowRect = tree. getPathBounds (path );
ChRect. setLocation (chRect. x + rowRect. x, chRect. y + rowRect. y );
If (e. getClickCount () = 1 & chRect. contains (p )){
Node node = (Node) component;
Node. setSelected (! Node. isSelected ());
Tree. repaint ();
}
}
}
}