Tôi muốn xây dựng JTree
có các nút chứa hộp kiểm + biểu tượng + dữ liệu và thuật toán chọn cây.Cách thêm hộp kiểm vào nút JTree để quản lý đa lựa chọn?
Trả lời
Đâ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:
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ỏ.
- 1. JTree với hộp kiểm
- 2. Hộp kiểm chuyển đổi (nhiều lựa chọn) thành nút radio hoặc hộp kiểm có lựa chọn duy nhất?
- 3. django lựa chọn mô hình lựa chọn như một hộp chọn đa
- 4. Quản lý nhiều lựa chọn với MVVM
- 5. QT - đa lựa chọn
- 6. Thêm hoạt ảnh lựa chọn vào UIButton
- 7. Cách thêm hộp kiểm vào UITableViewCell ??
- 8. Formtastic/ActiveAdmin đa lựa chọn nhiều đến nhiều vấn đề liên kết hộp kiểm
- 9. Làm cách nào để thêm hộp kiểm/nút radio vào QTableWidget
- 10. Tắt đa lựa chọn?
- 11. làm thế nào để tạo một hộp chọn đa với ra các lựa chọn hiện CodeIgniter
- 12. Làm cách nào để tạo danh sách lựa chọn bằng các hộp kiểm trong ASP.NET MVC?
- 13. Trình xử lý sự kiện đa lựa chọn Jquery
- 14. Thêm nút vào hộp thoại jquery ui
- 15. Thêm nút tích cực vào Hộp thoại
- 16. Cách thêm nút bên cạnh nút Thêm Người dùng trong Trang web Quản trị Django
- 17. cách đặt chế độ lựa chọn JTree "ctrl" luôn được bật
- 18. Java: Làm thế nào để lập trình lựa chọn và mở rộng nhiều nút trong một JTree?
- 19. HTML Hộp kiểm trong danh sách lựa chọn
- 20. Bật/tắt hộp văn bản dựa trên lựa chọn hộp kiểm trong WPF bằng cách sử dụng MVVM
- 21. cách ẩn lựa chọn nút trong iphone
- 22. Cách tạo hộp kết hợp đa lựa chọn, không hoàn thành như trong Atlassian Jira
- 23. JTree: Chọn tất cả các nút theo chương trình
- 24. Đặt chiều cao của hộp chọn nhiều lựa chọn
- 25. Tạo JTable bên trong nút của JTree
- 26. Cách bỏ chọn hộp kiểm Android đã chọn
- 27. Cách gửi hộp kiểm không chọn cũng
- 28. Xóa lựa chọn kiểm soát uisegmented sau khi nhấp vào nút lưu
- 29. Kendo ui Xác thực đa lựa chọn
- 30. Thêm tham số mới vào hoạt động WCF: lựa chọn?
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
Các biểu tượng trông tự nhiên hơn bằng cách sử dụng PLAF gốc .. –
@AndrewThompson có, cảm ơn, Q và A này là cái đầu tiên của tôi trên SO ; D –