如何将复选框添加到 JTree 节点以管理多选?
Posted
技术标签:
【中文标题】如何将复选框添加到 JTree 节点以管理多选?【英文标题】:How to add checkbox to JTree node to manage multiselection? 【发布时间】:2012-10-03 23:13:59 【问题描述】:我想构建JTree
,它的节点包含复选框+图标+数据和树选择算法。
【问题讨论】:
【参考方案1】:这是演示如何将复选框添加到 Jtree 节点的完整示例。我将 JTree 与基于文件系统内容的节点一起使用。
我还使用AddCheckBoxToTree.CheckTreeManager
类来管理选择或半选择选项。
使用
public AddCheckBoxToTree.CheckTreeManager getCheckTreeManager()
return checkTreeManager;
使用选择树路径的方法。
例如:
// clear all selected path in order
TreePath[] paths=getCheckTreeManager().getSelectionModel().getSelectionPaths();
if(paths != null)
for(TreePath tp : paths)
getCheckTreeManager().getSelectionModel().removeSelectionPath(tp);
我在这里粘贴了所有执行此操作的代码:
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;
到目前为止,一切都很好而且很清楚。 现在我要粘贴选择控制器,我们开始:
这里我们创建复选框元素以添加到树节点之后
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);
我们添加 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();
最无能为力的方法是:
boolean com.demo.tree.checkbox.AddCheckBoxToTree.CheckTreeSelectionModel.isPartiallySelected
检查给定路径(DONT_CARE)的子树中是否有任何未选择的节点。
这是我们所做的结果:
此答案基于 Santhosh Kumar's Weblog 帖子并进行了一些小修复。
【讨论】:
当心:您的扩展监听器修改了模型的基础数据关闭 EDT!通过从包含 fileNode(作为 userObject)的 treeNode 中删除/添加子节点,在 fileNode.expand 中发生 @AndrewThompson 是的,谢谢,这个 Q 和 A 是我在 SO 上的第一个问题;D @Desolator 查看上面发布的所有代码,它也包含FileTreeViewer
@MaximShoustin 我如何setSelected(true)
一些复选框?我想写一个selectAll\deSelectAll
方法
我没有在 JTree 上覆盖 getToolTipText(),而是尝试在 CheckTreeCellRenderer#getTreeCellRendererComponent() 方法中设置工具提示文本,因为我想根据某些条件设置工具提示。但它不起作用。有人可以帮我吗?以上是关于如何将复选框添加到 JTree 节点以管理多选?的主要内容,如果未能解决你的问题,请参考以下文章
Java Swing:需要具有复选框的高质量开发 JTree