2012-10-13 27 views

Trả lời

15

Đây là ví dụ đầy đủ minh họa cách thêm hộp kiểm vào nút Jtree. Tôi đã sử dụng JTree với các nút dựa trên nội dung của Hệ thống tệp.

Tôi cũng sử dụng AddCheckBoxToTree.CheckTreeManager lớp để quản lý các tùy chọn lựa chọn hoặc bán lựa chọn.

Sử dụng

public AddCheckBoxToTree.CheckTreeManager getCheckTreeManager() { 
    return checkTreeManager; 
} 

phương pháp để chơi với con đường cây lựa chọn.

ví dụ:

// clear all selected path in order 
    TreePath[] paths=getCheckTreeManager().getSelectionModel().getSelectionPaths(); 
    if(paths != null){ 
     for(TreePath tp : paths){ 
      getCheckTreeManager().getSelectionModel().removeSelectionPath(tp); 
     } 
    } 

ở đây tôi dán tất cả các mã mà làm điều đó:

package com.demo.tree.checkbox; 


import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Component; 
import java.awt.Graphics; 
import java.awt.event.MouseEvent; 
import java.awt.event.WindowAdapter; 
import java.awt.event.WindowEvent; 
import java.awt.event.WindowListener; 
import java.io.File; 
import java.util.Vector; 

import javax.swing.Icon; 
import javax.swing.ImageIcon; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JOptionPane; 
import javax.swing.JScrollPane; 
import javax.swing.JTree; 
import javax.swing.SwingUtilities; 
import javax.swing.ToolTipManager; 
import javax.swing.UIManager; 
import javax.swing.event.TreeExpansionEvent; 
import javax.swing.event.TreeExpansionListener; 
import javax.swing.tree.DefaultMutableTreeNode; 
import javax.swing.tree.DefaultTreeModel; 
import javax.swing.tree.TreeCellRenderer; 
import javax.swing.tree.TreePath; 
import javax.swing.tree.TreeSelectionModel; 



public class FileTreeViewer extends JFrame { 

private static final long serialVersionUID = 1L; 
public static final ImageIcon ICON_COMPUTER = new ImageIcon(""); 
public static final ImageIcon ICON_DISK = new ImageIcon("defaults1.png"); 
public static final ImageIcon ICON_FOLDER = new ImageIcon("fol_orig.png"); 
public static final ImageIcon ICON_EXPANDEDFOLDER = new ImageIcon("folder_open.png"); 

protected JTree m_tree; 
protected DefaultTreeModel m_model; 

AddCheckBoxToTree AddCh = new AddCheckBoxToTree(); 

private AddCheckBoxToTree.CheckTreeManager checkTreeManager; 


protected TreePath m_clickedPath; 

public FileTreeViewer() 
{ 
    super("Demo tree check box"); 
    setSize(400, 300); 

    DefaultMutableTreeNode top = new DefaultMutableTreeNode(
      new IconData(ICON_COMPUTER, null, "Computer")); 

    DefaultMutableTreeNode node; 
    File[] roots = File.listRoots(); 
    for (int k=0; k<roots.length; k++) 
    { 
     node = new DefaultMutableTreeNode(new IconData(ICON_DISK, null, new FileNode(roots[k]))); 
     top.add(node); 
     node.add(new DefaultMutableTreeNode(new Boolean(true))); 
    } 

    m_model = new DefaultTreeModel(top); 

    m_tree = new JTree(m_model){ 
     public String getToolTipText(MouseEvent ev) 
     { 
      if(ev == null) 
       return null; 
      TreePath path = m_tree.getPathForLocation(ev.getX(), 
        ev.getY()); 
      if (path != null) 
      { 
       FileNode fnode = getFileNode(getTreeNode(path)); 
       if (fnode==null) 
        return null; 
       File f = fnode.getFile(); 
       return (f==null ? null : f.getPath()); 
      } 
      return null; 
     } 
    }; 

    ToolTipManager.sharedInstance().registerComponent(m_tree); 

    m_tree.putClientProperty("JTree.lineStyle", "Angled"); 

    TreeCellRenderer renderer = new IconCellRenderer(); 
    m_tree.setCellRenderer(renderer); 

    m_tree.addTreeExpansionListener(new DirExpansionListener()); 

    m_tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); 
    m_tree.setShowsRootHandles(true); 
    m_tree.setEditable(false); 


    checkTreeManager = AddCh.new CheckTreeManager(m_tree, null); 



    JScrollPane s = new JScrollPane(); 
    s.getViewport().add(m_tree); 
    getContentPane().add(s, BorderLayout.CENTER); 


    WindowListener wndCloser = new WindowAdapter(){ 
     public void windowClosing(WindowEvent e){ 
      System.exit(0); 
     } 
    }; 

    addWindowListener(wndCloser); 

    setVisible(true); 
} 

DefaultMutableTreeNode getTreeNode(TreePath path) 
{ 
    return (DefaultMutableTreeNode)(path.getLastPathComponent()); 
} 

FileNode getFileNode(DefaultMutableTreeNode node) 
{ 
    if (node == null) 
     return null; 
    Object obj = node.getUserObject(); 
    if (obj instanceof IconData) 
     obj = ((IconData)obj).getObject(); 
    if (obj instanceof FileNode) 
     return (FileNode)obj; 
    else 
     return null; 
} 

public AddCheckBoxToTree.CheckTreeManager getCheckTreeManager() { 
    return checkTreeManager; 
} 

// Make sure expansion is threaded and updating the tree model 
// only occurs within the event dispatching thread. 
class DirExpansionListener implements TreeExpansionListener 
{ 
    public void treeExpanded(TreeExpansionEvent event) 
    { 
     final DefaultMutableTreeNode node = getTreeNode(
       event.getPath()); 
     final FileNode fnode = getFileNode(node); 

     Thread runner = new Thread() 
     { 
      public void run() 
      { 
       if (fnode != null && fnode.expand(node)) 
       { 
        Runnable runnable = new Runnable() 
        { 
         public void run() 
         { 
          m_model.reload(node); 
         } 
        }; 
        SwingUtilities.invokeLater(runnable); 
       } 
      } 
     }; 
     runner.start(); 
    } 

    public void treeCollapsed(TreeExpansionEvent event) {} 
} 



public static void main(String argv[]) 
{ 
    try { 
     UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); 
    } catch (Exception evt) {} 
    new FileTreeViewer(); 
} 
} 

class IconCellRenderer extends JLabel implements TreeCellRenderer{ 
protected Color m_textSelectionColor; 
protected Color m_textNonSelectionColor; 
protected Color m_bkSelectionColor; 
protected Color m_bkNonSelectionColor; 
protected Color m_borderSelectionColor; 

protected boolean m_selected; 

public IconCellRenderer() 
{ 
    super(); 
    m_textSelectionColor = UIManager.getColor(
      "Tree.selectionForeground"); 
    m_textNonSelectionColor = UIManager.getColor(
      "Tree.textForeground"); 
    m_bkSelectionColor = UIManager.getColor(
      "Tree.selectionBackground"); 
    m_bkNonSelectionColor = UIManager.getColor(
      "Tree.textBackground"); 
    m_borderSelectionColor = UIManager.getColor(
      "Tree.selectionBorderColor"); 
    setOpaque(false); 
} 

public Component getTreeCellRendererComponent(JTree tree, 
     Object value, boolean sel, boolean expanded, boolean leaf, 
     int row, boolean hasFocus) 

{ 
    DefaultMutableTreeNode node = 
      (DefaultMutableTreeNode)value; 
    Object obj = node.getUserObject(); 
    setText(obj.toString()); 

    if (obj instanceof Boolean) 
     setText("Retrieving data..."); 

    if (obj instanceof IconData) 
    { 
     IconData idata = (IconData)obj; 
     if (expanded) 
      setIcon(idata.getExpandedIcon()); 
     else 
      setIcon(idata.getIcon()); 
    } 
    else 
     setIcon(null); 

    setFont(tree.getFont()); 
    setForeground(sel ? m_textSelectionColor : 
     m_textNonSelectionColor); 
    setBackground(sel ? m_bkSelectionColor : 
     m_bkNonSelectionColor); 
    m_selected = sel; 
    return this; 
} 

public void paintComponent(Graphics g) 
{ 
    Color bColor = getBackground(); 
    Icon icon = getIcon(); 

    g.setColor(bColor); 
    int offset = 0; 
    if(icon != null && getText() != null) 
     offset = (icon.getIconWidth() + getIconTextGap()); 
    g.fillRect(offset, 0, getWidth() - 1 - offset, 
      getHeight() - 1); 

    if (m_selected) 
    { 
     g.setColor(m_borderSelectionColor); 
     g.drawRect(offset, 0, getWidth()-1-offset, getHeight()-1); 
    } 

    super.paintComponent(g); 
} 
} 

class IconData { 
protected Icon m_icon; 
protected Icon m_expandedIcon; 
protected Object m_data; 

public IconData(Icon icon, Object data) 
{ 
    m_icon = icon; 
    m_expandedIcon = null; 
    m_data = data; 
} 

public IconData(Icon icon, Icon expandedIcon, Object data) 
{ 
    m_icon = icon; 
    m_expandedIcon = expandedIcon; 
    m_data = data; 
} 

public Icon getIcon() 
{ 
    return m_icon; 
} 

public Icon getExpandedIcon() 
{ 
    return m_expandedIcon!=null ? m_expandedIcon : m_icon; 
} 

public Object getObject() 
{ 
    return m_data; 
} 

public String toString() 
{ 
    return m_data.toString(); 
} 
} 

class FileNode { 
protected File m_file; 

public FileNode(File file) 
{ 
    m_file = file; 
} 

public File getFile() 
{ 
    return m_file; 
} 

public String toString() 
{ 
    return m_file.getName().length() > 0 ? m_file.getName() : 
     m_file.getPath(); 
} 

public boolean expand(DefaultMutableTreeNode parent){ 
    DefaultMutableTreeNode flag = (DefaultMutableTreeNode)parent.getFirstChild(); 
    if (flag==null) // No flag 
     return false; 
    Object obj = flag.getUserObject(); 
    if (!(obj instanceof Boolean)) 
     return false;  // Already expanded 

    parent.removeAllChildren(); // Remove Flag 

    File[] files = listFiles(); 
    if (files == null) 
     return true; 

    Vector<FileNode> v = new Vector<FileNode>(); 

    for (int k=0; k<files.length; k++){ 
     File f = files[k]; 
     if (!(f.isDirectory())) 
      continue; 

     FileNode newNode = new FileNode(f); 

     boolean isAdded = false; 
     for (int i=0; i<v.size(); i++) 
     { 
      FileNode nd = (FileNode)v.elementAt(i); 
      if (newNode.compareTo(nd) < 0) 
      { 
       v.insertElementAt(newNode, i); 
       isAdded = true; 
       break; 
      } 
     } 
     if (!isAdded) 
      v.addElement(newNode); 
    } 

    for (int i=0; i<v.size(); i++){ 
     FileNode nd = (FileNode)v.elementAt(i); 
     IconData idata = new IconData(FileTreeViewer.ICON_FOLDER, FileTreeViewer.ICON_EXPANDEDFOLDER, nd); 
     DefaultMutableTreeNode node = new 
       DefaultMutableTreeNode(idata); 
     parent.add(node); 

     if (nd.hasSubDirs()) 
      node.add(new DefaultMutableTreeNode( 
        new Boolean(true))); 
    } 

    return true; 
} 

public boolean hasSubDirs(){ 
    File[] files = listFiles(); 
    if (files == null) 
     return false; 
    for (int k=0; k<files.length; k++) 
    { 
     if (files[k].isDirectory()) 
      return true; 
    } 
    return false; 
} 

public int compareTo(FileNode toCompare){ 
    return m_file.getName().compareToIgnoreCase(
      toCompare.m_file.getName()); 
} 

protected File[] listFiles(){ 
    if (!m_file.isDirectory()) 
     return null; 
    try 
    { 
     return m_file.listFiles(); 
    } 
    catch (Exception ex) 
    { 
     JOptionPane.showMessageDialog(null, "Error reading directory "+m_file.getAbsolutePath(),"Warning", JOptionPane.WARNING_MESSAGE); 
     return null; 
    } 
} 
} 

Đến nay tất cả là tốt và rõ ràng. Bây giờ tôi sẽ dán điều khiển lựa chọn, ở đây chúng tôi đi:

Ở đây chúng ta tạo ra yếu tố hộp kiểm để thêm sau khi đến nút cây

package com.demo.tree.checkbox; 


import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.ItemListener; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import java.awt.event.MouseListener; 

import javax.swing.AbstractAction; 
import javax.swing.ActionMap; 
import javax.swing.ButtonGroup; 
import javax.swing.ButtonModel; 
import javax.swing.Icon; 
import javax.swing.JCheckBox; 
import javax.swing.SwingUtilities; 
import javax.swing.event.ChangeListener; 
import javax.swing.plaf.ActionMapUIResource; 


public class TristateCheckBox extends JCheckBox { 
static final long serialVersionUID =0; 

/** This is a type-safe enumerated type */ 
public static class State 
{ 
    private State() {} 
} 

public final  State NOT_SELECTED = new State(); 
public final  State SELECTED  = new State(); 
public final static State DONT_CARE = new State(); 

private final TristateDecorator model; 

public TristateCheckBox(String text, Icon icon, State initial){ 
    super(text, icon); 
    // Add a listener for when the mouse is pressed 
    super.addMouseListener(new MouseAdapter() { 
     public void mousePressed(MouseEvent e) { 
      grabFocus(); 
      model.nextState(); 
     } 
    }); 

    // Reset the keyboard action map 
    ActionMap map = new ActionMapUIResource(); 
    map.put("pressed", new AbstractAction() { 

     private static final long serialVersionUID = 1L; 

     public void actionPerformed(ActionEvent e) { 
      grabFocus(); 
      model.nextState(); 
     } 
    }); 

    map.put("released", null); 

    SwingUtilities.replaceUIActionMap(this, map); 

    // set the model to the adapted model 
    model = new TristateDecorator(getModel()); 
    setModel(model); 
    setState(initial); 
} 

// Constractor types: 
public TristateCheckBox(String text, State initial) { 
    this(text, null, initial); 
} 

public TristateCheckBox(String text) { 
    this(text, DONT_CARE); 
} 

public TristateCheckBox() { 
    this(null); 
} 

/** No one may add mouse listeners, not even Swing! */ 
public void addMouseListener(MouseListener l) { } 
/** 
* Set the new state to either SELECTED, NOT_SELECTED or 
* DONT_CARE. If state == null, it is treated as DONT_CARE. 
*/ 
public void setState(State state) { 
    model.setState(state); 
} 
/** Return the current state, which is determined by the 
* selection status of the model. */ 
public State getState() { 
    return model.getState(); 
} 

public void setSelected(boolean b) { 
    if (b) { 
     setState(SELECTED);   
    } else { 
     setState(NOT_SELECTED);   
    } 
} 
/** 
* Exactly which Design Pattern is this? Is it an Adapter, 
* a Proxy or a Decorator? In this case, my vote lies with the 
* Decorator, because we are extending functionality and 
* "decorating" the original model with a more powerful model. 
*/ 
private class TristateDecorator implements ButtonModel { 
    private final ButtonModel other; 
    private TristateDecorator(ButtonModel other) { 
     this.other = other; 
    } 
    private void setState(State state) { 
     if (state == NOT_SELECTED) { 
      other.setArmed(false); 
      setPressed(false); 
      setSelected(false); 
     } else if (state == SELECTED) { 
      other.setArmed(false); 
      setPressed(false); 
      setSelected(true); 
     } else { // either "null" or DONT_CARE 
      other.setArmed(true); 
      setPressed(true); 
      setSelected(false); 
     } 
    } 
    /** 
    * The current state is embedded in the selection/armed 
    * state of the model. 
    * 
    * We return the SELECTED state when the checkbox is selected 
    * but not armed, DONT_CARE state when the checkbox is 
    * selected and armed (grey) and NOT_SELECTED when the 
    * checkbox is deselected. 
    */ 
    private State getState() { 
     if (isSelected() && !isArmed()) { 
      // normal black tick 
      return SELECTED; 
     } else if (isSelected() && isArmed()) { 
      // don't care grey tick 
      return DONT_CARE; 
     } else { 
      // normal deselected 
      return NOT_SELECTED; 
     } 
    } 

    /** We rotate between NOT_SELECTED, SELECTED and DONT_CARE.*/ 
    private void nextState() { 
     State current = getState(); 
     if (current == NOT_SELECTED) { 
      setState(SELECTED); 
     } else if (current == SELECTED) { 
      setState(DONT_CARE); 
     } else if (current == DONT_CARE) { 
      setState(NOT_SELECTED); 
     } 
    } 

    /** Filter: No one may change the armed status except us. */ 
    public void setArmed(boolean b) { 
    } 

    /** We disable focusing on the component when it is not 
    * enabled. */ 
    public void setEnabled(boolean b) { 
     setFocusable(b); 
     other.setEnabled(b); 
    } 

    /** All these methods simply delegate to the "other" model 
    * that is being decorated. */ 
    public boolean isArmed()        {return other.isArmed(); } 
    public boolean isSelected()       {return other.isSelected(); } 
    public boolean isEnabled()       {return other.isEnabled(); } 
    public boolean isPressed()       {return other.isPressed(); } 
    public boolean isRollover()       {return other.isRollover(); } 
    public int  getMnemonic()       {return other.getMnemonic(); } 
    public String getActionCommand()      {return other.getActionCommand();} 
    public Object[]getSelectedObjects()     {return other.getSelectedObjects();} 
    public void setSelected(boolean b)     {other.setSelected(b);} 
    public void setPressed(boolean b)     {other.setPressed(b);} 
    public void setRollover(boolean b)     {other.setRollover(b);} 
    public void setMnemonic(int key)     {other.setMnemonic(key);}    
    public void setActionCommand(String s)    {other.setActionCommand(s);}      
    public void setGroup(ButtonGroup group)   {other.setGroup(group);}  
    public void addActionListener(ActionListener l) {other.addActionListener(l);} 
    public void removeActionListener(ActionListener l) {other.removeActionListener(l);}  
    public void addItemListener(ItemListener l)  {other.addItemListener(l);}  
    public void removeItemListener(ItemListener l)  {other.removeItemListener(l);}  
    public void addChangeListener(ChangeListener l) {other.addChangeListener(l);}  
    public void removeChangeListener(ChangeListener l) {other.removeChangeListener(l);}  

} 
} 

Sau khi chúng tôi thêm CheckTreeManager:

package com.demo.tree.checkbox; 

import java.awt.BorderLayout; 
import java.awt.Component; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import java.util.ArrayList; 
import java.util.Stack; 

import javax.swing.JCheckBox; 
import javax.swing.JPanel; 
import javax.swing.JTree; 
import javax.swing.event.TreeSelectionEvent; 
import javax.swing.event.TreeSelectionListener; 
import javax.swing.tree.DefaultTreeSelectionModel; 
import javax.swing.tree.TreeCellRenderer; 
import javax.swing.tree.TreeModel; 
import javax.swing.tree.TreePath; 
import javax.swing.tree.TreeSelectionModel; 


public class AddCheckBoxToTree { 


public class CheckTreeSelectionModel extends DefaultTreeSelectionModel{ 
    static final long serialVersionUID =0; 
    private TreeModel model; 

    public CheckTreeSelectionModel(TreeModel model){ 
     this.model = model; 

     setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION); 
    }  

    // tests whether there is any unselected node in the subtree of given path (DONT_CARE) 
    public boolean isPartiallySelected(TreePath path){ 
     if(isPathSelected(path, true)){ 
      return false; 
     } 

     TreePath[] selectionPaths = getSelectionPaths(); 

     if(selectionPaths==null){ 
      return false; 
     } 

     for(int j = 0; j<selectionPaths.length; j++){ 
      if(isDescendant(selectionPaths[j], path)){ 
       return true; 
      }      
     } 

     return false; 
    } 

    // tells whether given path is selected. 
    // if dig is true, then a path is assumed to be selected, if 
    // one of its ancestor is selected. 
    public boolean isPathSelected(TreePath path, boolean dig){      
     if(!dig){ 
      return super.isPathSelected(path); 
     } 

     while(path!=null && !super.isPathSelected(path)){ 
      path = path.getParentPath(); 
     } 

     return path!=null; 
    } 

    // is path1 descendant of path2 
    private boolean isDescendant(TreePath path1, TreePath path2){ 
     Object obj1[] = path1.getPath(); 
     Object obj2[] = path2.getPath(); 
     for(int i = 0; i<obj2.length; i++){ 
      if(obj1[i]!=obj2[i]) 
       return false; 
     } 
     return true; 
    } 

    public void setSelectionPaths(TreePath[] pPaths){ 
     throw new UnsupportedOperationException("not implemented yet!!!"); 
    } 

    public void addSelectionPaths(TreePath[] paths){ 

     // unselect all descendants of paths[] 
     for(int i = 0; i<paths.length; i++) 
     { 
      TreePath path = paths[i]; 

      TreePath[] selectionPaths = getSelectionPaths(); 

      if(selectionPaths==null){ 
       break; 
      } 

      ArrayList<TreePath> toBeRemoved = new ArrayList<TreePath>(); 

      for(int j = 0; j<selectionPaths.length; j++) 
      { 
       if(isDescendant(selectionPaths[j], path)) 
       { 
        toBeRemoved.add(selectionPaths[j]); 
       } 
      } 
      super.removeSelectionPaths((TreePath[])toBeRemoved.toArray(new TreePath[0])); 
     } 

     // if all siblings are selected then unselect them and select parent recursively 
     // otherwize just select that path. 
     for(int i = 0; i<paths.length; i++){ 
      TreePath path = paths[i]; 

      TreePath temp = null; 

      while(areSiblingsSelected(path)){ 
       temp = path; 

       if(path.getParentPath()==null) 
       { 
        break; 
       } 

       path = path.getParentPath(); 
      } 

      if(temp!=null){ 
       if(temp.getParentPath()!=null) 
       { 
        addSelectionPath(temp.getParentPath()); 
       } 
       else 
       { 
        if(!isSelectionEmpty()) 
        { 
         removeSelectionPaths(getSelectionPaths()); 
        } 

        super.addSelectionPaths(new TreePath[]{temp}); 
       }     
      } 
      else 
      { 
       super.addSelectionPaths(new TreePath[]{ path}); 
      } 
     } 
    } 

    // tells whether all siblings of given path are selected. 
    private boolean areSiblingsSelected(TreePath path){ 
     TreePath parent = path.getParentPath(); 

     if(parent==null){ 
      return true; 
     } 

     Object node = path.getLastPathComponent(); 

     Object parentNode = parent.getLastPathComponent(); 

     int childCount = model.getChildCount(parentNode); 

     Boolean isParameters = false; 
     Boolean isDescription = false; 

     for(int i = 0; i<childCount; i++){ 

      Object childNode = model.getChild(parentNode, i); 



      if(childNode==node){ 
       continue; 
      } 

// If last Path component equals to "parameters" or "description" - select second child too. 
      if(childCount == 2) 
      { 
       if(childNode.toString().equals("parameters") && model.isLeaf(childNode)) 
       { 
        isParameters = true; 
       } 
       if(childNode.toString().equals("description") && model.isLeaf(childNode)) 
       { 
        isDescription = true; 
       } 
      } 


      if(!isPathSelected(parent.pathByAddingChild(childNode)) && !isParameters && !isDescription){ 
       return false; 
      } 
     } 

     return true; 
    } 

    public void removeSelectionPaths(TreePath[] paths){ 
     for(int i = 0; i<paths.length; i++){ 
      TreePath path = paths[i]; 
      if(path.getPathCount()==1) 
       super.removeSelectionPaths(new TreePath[]{ path}); 
      else 
       toggleRemoveSelection(path); 
     } 
    } 

    /** if any ancestor node of given path is selected then unselect it 
    * and selection all its descendants except given path and descendants. 
    * otherwise just unselect the given path */ 
    private void toggleRemoveSelection(TreePath path){ 

     Stack<TreePath> stack = new Stack<TreePath>(); 
     TreePath parent = path.getParentPath(); 

     Boolean isParameters = false; 
     Boolean isDescription = false; 

     while(parent!=null && !isPathSelected(parent)){ 
      stack.push(parent); 
      parent = parent.getParentPath(); 
     } 
     if(parent!=null) 
      stack.push(parent); 
     else{ 
      super.removeSelectionPaths(new TreePath[]{path}); 
      return; 
     } 

     while(!stack.isEmpty()){ 
      TreePath temp = (TreePath)stack.pop(); 

      TreePath peekPath = stack.isEmpty() ? path : (TreePath)stack.peek(); 

      Object node = temp.getLastPathComponent(); 
      Object peekNode = peekPath.getLastPathComponent(); 
      int childCount = model.getChildCount(node); 


      for(int i = 0; i<childCount; i++){ 
       Object childNode = model.getChild(node, i); 

       if(childNode.toString().equals("parameters") && model.isLeaf(childNode)) 
       { 
        isParameters = true; 
       } 
       if(childNode.toString().equals("description") && model.isLeaf(childNode)) 
       { 
        isDescription = true; 
       } 


       if(childNode!=peekNode) 
       { 
        if(!isParameters && !isDescription) 
        super.addSelectionPaths(new TreePath[]{temp.pathByAddingChild(childNode)}); 
       } 
      } 
     } 

     super.removeSelectionPaths(new TreePath[]{parent}); 
    } 

    public TreeModel getModel() { 
     return model; 
    } 
} 


public class CheckTreeCellRenderer extends JPanel implements TreeCellRenderer { 

    static final long serialVersionUID =0; 

    CheckTreeSelectionModel selectionModel; 
    private TreeCellRenderer delegate; 
    TristateCheckBox checkBox = new TristateCheckBox(); 





    public CheckTreeCellRenderer(TreeCellRenderer delegate, CheckTreeSelectionModel selectionModel){ 
     this.delegate = delegate; 
     this.selectionModel = selectionModel; 

     setLayout(new BorderLayout()); 
     setOpaque(false); 
     checkBox.setOpaque(false);  

    } 


    public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus){ 
     Component renderer = delegate.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus); 


     TreePath path = tree.getPathForRow(row);    


     if(path!=null) 
     {     
      if(selectionModel.isPathSelected(path, true)) 
      {     
       checkBox.setState(checkBox.SELECTED); 
       //System.out.println(">>>>>>  selected "); 
      } 
      else 
      {      
       checkBox.setState(checkBox.NOT_SELECTED); 
       //System.out.println("not selected "); 
      } 

      if(selectionModel.isPartiallySelected(path)) 
      { 
       checkBox.setState(checkBox.DONT_CARE);     
      } 
     } 

     removeAll();   

      add(checkBox, BorderLayout.WEST); 
      add(renderer, BorderLayout.CENTER);  


     return this; 
    } 


    public TreeCellRenderer getDelegate() { 
     return delegate; 
    } 


    public void setDelegate(TreeCellRenderer delegate) { 
     this.delegate = delegate; 
    } 
} 


public class CheckTreeManager extends MouseAdapter implements TreeSelectionListener{ 
    CheckTreeSelectionModel selectionModel; 
    private JTree tree = new JTree(); 

    int hotspot = new JCheckBox().getPreferredSize().width; 

    public CheckTreeManager(JTree tree, CheckTreeSelectionModel checkTreeSelectionModel){ 
     this.tree = tree;   


     if(checkTreeSelectionModel != null) 
     { 
      //selectionModel = new CheckTreeSelectionModel(tree.getModel()); 
      selectionModel = checkTreeSelectionModel; 

     } 
     else 
     { 
      selectionModel = new CheckTreeSelectionModel(tree.getModel()); 
      //System.out.println(selectionModel.getSelectionPath()); 
     } 



     tree.setCellRenderer(new CheckTreeCellRenderer(tree.getCellRenderer(), selectionModel)); 

     tree.addMouseListener(this); 
     selectionModel.addTreeSelectionListener(this); 
    } 

    public void mouseClicked(MouseEvent me){ 
     //System.out.println("start..."); 

     TreePath path = tree.getPathForLocation(me.getX(), me.getY()); 
     //System.out.println(Arrays.asList(path)); 


     if(path==null) 
     { 
      //System.out.println("path==null"); 
      return;  
     } 

     if(me.getX()/1.2>tree.getPathBounds(path).x+hotspot) 
     { 
      //System.out.println("me.getX()/1.2>tree.getPathBounds(path).x+hotspot"); 
      return; 
     } 


     boolean selected = selectionModel.isPathSelected(path, true); 
     selectionModel.removeTreeSelectionListener(this); 

     try{ 
      if(selected) 
      { 
       //System.out.println("selected"); 
       selectionModel.removeSelectionPath(path); 
      } 
      else 
      { 
       //System.out.println("not selected"); 
       selectionModel.addSelectionPath(path); 
      } 
     } 
     finally 
     { 
      //System.out.println("finally"); 
      selectionModel.addTreeSelectionListener(this); 
      tree.treeDidChange(); 
     } 
    } 

    public CheckTreeSelectionModel getSelectionModel(){ 
     return selectionModel; 
    } 

    public void setSelectionModel(CheckTreeSelectionModel selectionModel) { 
     this.selectionModel = selectionModel; 
    } 

    public void valueChanged(TreeSelectionEvent e){ 
     tree.treeDidChange(); 
    }  
}  
} 

Các phương pháp bất lực nhất là:

boolean com.demo.tree.checkbox.AddCheckBoxToTree.CheckTreeSelectionModel.isPartiallySelected 

kiểm tra xem có một y chưa được chọn trong cây con của đường dẫn đã cho (DONT_CARE).

Và đây là kết quả của những gì chúng tôi đã làm: And this is the result of what we did:


Câu trả lời này được dựa trên Santhosh Kumar's Weblog bài với sửa chữa nhỏ.

+3

hãy cẩn thận: expandListener của bạn sửa đổi dữ liệu cơ bản của mô hình _off_ the EDT! Xảy ra trong fileNode.expand bằng cách loại bỏ/thêm trẻ em từ treeNode chứa fileNode (như userObject) – kleopatra

+0

Các biểu tượng trông tự nhiên hơn bằng cách sử dụng PLAF gốc .. –

+0

@AndrewThompson có, cảm ơn, Q và A này là cái đầu tiên của tôi trên SO ; D –

Các vấn đề liên quan