Quiero construir JTree
que tenga nodos que contengan casilla de verificación + icono + datos y algoritmo de selección de árbol.¿Cómo agregar casilla de verificación al nodo JTree para administrar la multiselección?
Respuesta
Este es un ejemplo completo que muestra cómo agregar una casilla de verificación al nodo Jtree. Usé JTree con nodos basados en el contenido del sistema de archivos.
Usé también la clase AddCheckBoxToTree.CheckTreeManager
para administrar las opciones de selección o semi selección.
Uso
public AddCheckBoxToTree.CheckTreeManager getCheckTreeManager() {
return checkTreeManager;
}
método para jugar con el camino de árbol de selección.
por ejemplo:
// clear all selected path in order
TreePath[] paths=getCheckTreeManager().getSelectionModel().getSelectionPaths();
if(paths != null){
for(TreePath tp : paths){
getCheckTreeManager().getSelectionModel().removeSelectionPath(tp);
}
}
aquí me pegan todo el código que hacen eso:
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;
}
}
}
Hasta ahora todo era bueno y claro. Ahora voy a pegar Controlador de selección, aquí vamos:
Aquí creamos elemento de opción para añadir después a nodo del árbol
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);}
}
}
Después añadimos 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();
}
}
}
El el método más impotente es:
boolean com.demo.tree.checkbox.AddCheckBoxToTree.CheckTreeSelectionModel.isPartiallySelected
que comprueba si hay una y nodo no seleccionado en el subárbol de la ruta determinada (DONT_CARE).
Y este es el resultado de lo que hemos hecho:
Esta respuesta se basa en Santhosh Kumar's Weblog post con correcciones menores.
- 1. JTree con casillas de verificación
- 2. Obteniendo un nodo en JTree
- 3. Cómo puedo agregar una casilla de verificación en un encabezado jQgrid
- 4. casilla de verificación como alternativa al captcha?
- 5. Creando JTable dentro del nodo de JTree
- 6. cómo borrar la casilla de verificación
- 7. ¿Cómo obtener la profundidad del nodo actual en JTree?
- 8. jQuery: Al seleccionar la casilla de verificación marcada
- 9. C# Agregar casilla de verificación a WinForms Menú contextual
- 10. Casilla de verificación Grails
- 11. JQuery La verificación de la casilla de verificación está marcada
- 12. ¿Cómo agregar un atributo al nodo Nokogiri?
- 13. cambiando cómo maneja Nimbus LaF JTree nodo resaltado
- 14. jQuery selector para la etiqueta de una casilla de verificación
- 15. personalizar la casilla de verificación preferencia
- 16. QT - casilla de verificación desmarque
- 17. Cómo agregar la casilla de verificación a la cuadrícula de datos en Windows Mobile 6.0?
- 18. Cómo agregar la casilla de verificación en la cuadrícula de datos WPF C#
- 19. FDF: cómo marcar una casilla de verificación?
- 20. usando el manillar bindAttr para la casilla de verificación
- 21. jsTree Ocultar casilla de verificación
- 22. ¿Cómo agotar una casilla de verificación html?
- 23. ¿Cómo desactivo una casilla de verificación?
- 24. Control de casilla de verificación para la aplicación iOS
- 25. Marque la casilla de verificación deshabilitada (Jquery)
- 26. Winforms Casilla de verificación Enfoque Problema si no se aplica texto en la casilla de verificación
- 27. cómo agregar una casilla de verificación a la cuadrícula de Extjs
- 28. Cómo aplicar a la imagen personalizada casilla de verificación androide
- 29. Casilla de verificación en ExpandableListView
- 30. Android Casilla de verificación Grupo
cuidado: your expansionListener modifica los datos subyacentes del modelo _off_ el EDT! Ocurre en fileNode.expand al eliminar/agregar elementos secundarios de treeNode que contiene el fileNode (como userObject) – kleopatra
Los iconos se ven más naturales usando el PLAF nativo. –
@AndrewThompson Sí, gracias, esta Q y A fue mi primera vez en SO ; D –