I want to make it like when I click a button, it will create a new file. Then the jTree will highlight the new file. Below are my code. Currently I create new file, i will show the new file but no highlight the file.
class FileTreeModel implements TreeModel {
private FileNode root;
public FileTreeModel(String directory) {
root = new FileNode(directory);
}
public Object getRoot() {
return root;
}
public Object getChild(Object parent, int index) {
FileNode parentNode = (FileNode) parent;
return new FileNode(parentNode, parentNode.listFiles()[index].getName());
}
public int getChildCount(Object parent) {
FileNode parentNode = (FileNode) parent;
if (parent == null || !parentNode.isDirectory()
|| parentNode.listFiles() == null) {
return 0;
}
return parentNode.listFiles().length;
}
public boolean isLeaf(Object node) {
return (getChildCount(node) == 0);
}
public int getIndexOfChild(Object parent, Object child) {
FileNode parentNode = (FileNode) parent;
FileNode childNode = (FileNode) child;
return Arrays.asList(parentNode.list()).indexOf(childNode.getName());
}
public void valueForPathChanged(TreePath path, Object newValue) {
}
public void addTreeModelListener(TreeModelListener l) {
}
public void removeTreeModelListener(TreeModelListener l) {
}
}
class FileNode extends java.io.File {
public FileNode(String directory) {
super(directory);
}
public FileNode(FileNode parent, String child) {
super(parent, child);
}
#Override
public String toString() {
return getName();
}
}
jTree = new JTree();
jTree.setBounds(new Rectangle(164, 66, 180, 421));
jTree.setBackground(SystemColor.inactiveCaptionBorder);
jTree.setBorder(BorderFactory.createTitledBorder(null, "",
TitledBorder.LEADING, TitledBorder.TOP, new Font("Arial",
Font.BOLD, 12), new Color(0, 0, 0)));
FileTreeModel model = new FileTreeModel(root);
jTree.setRootVisible(false);
jTree.setModel(model);
expandAll(jTree);
public void expandAll(JTree tree) {
int row = 0;
while (row < tree.getRowCount()) {
tree.expandRow(row);
row++;
}
}
you can do this by calling JTree.setSelectionPath(TreePath path);
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
Guys i created two trees. I wrote a method but it does not work correctly.
My method does not work recursively and prints only "false".
In general, I need to recurse through the elements of a tree, and If two trees are similar, then it should output - "true". If two rees not similar, then it should output - false. Please help me write code eqauls method in my trees
My code:
public class TreePrint {
public static void main(String[] args) {
Tree<String> rootFolder = new Tree<>("RootFolder");
Node<String> video = rootFolder.addChild("Video");
Node<String> music = rootFolder.addChild("Music");
Node<String> picture = rootFolder.addChild("Picture");
video.addChild("Terminator");
video.addChild("Die Hard");
video.addChild("Rocky");
music.addChild("Eminem");
Node<String> picture01 = picture.addChild("Picasso");
picture01.addChild("Do Vinci");
Node<String> picture02 = picture01.addChild("NN");
picture02.addChild("Cartoon");
picture02.addChild("Comics");
Tree2<String> rootFolder1 = new Tree2<>("RootFolder");
printTree(rootFolder);
printTree(rootFolder1);
boolean b1 = rootFolder.contains("P0");
//System.out.println(b1);
boolean b2 = rootFolder1.contains("Eminem");
//System.out.println(b2);
System.out.println(rootFolder.equals(rootFolder1));
}
private static <T> void printTree(Node<T> node) {
printTree(node, 0);
}
private static <T> void printTree(Node<T> node, int level) {
printNode(node, level);
if (node.getChildren() != null) {
for (Node childNode : node.getChildren()) {
printTree(childNode, level + 1);
}
}
}
private static <T> void printNode(Node<T> kid, int level) {
for (int i = 0; i < level; i++) {
System.out.print(" ");
}
System.out.println(kid.getData());
}
}
public class Tree<T> extends Node<T> {
public Tree(T data) {
super(data, null);
}
public boolean contains(T value) {
return recurse(iterate(), value);
}
private boolean recurse(List<Node<T>> children, T value) {
return children.stream()
.anyMatch(item -> item.getData().equals(value) || item.iterate().size() > 0 && recurse(item.iterate(), value));
}
public boolean equals(Object obj) {
return isEquals(obj);
}
private boolean isEquals(Object obj
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
Node other = (Node) obj;
if (children == null) {
if (other.children != null) {
return false;
}
} else if (!children.equals(other.children)) {
return false;
}
if (data == null) {
if (other.data != null) {
return false;
}
} else if (!data.equals(other.data)) {
return false;
}
return true;
}
}
public class Node<T> {
private T data;
private final List<Node<T>> children = new ArrayList<>();
private final Node<T> parent;
public Node(T data, Node<T> parent) {
this.data = data;
this.parent = parent;
}
public void addChild(Node<T> node) {
children.add(node);
}
public Node<T> addChild(T nodeData) {
Node<T> newNode = new Node<T>(nodeData, this);
children.add(newNode);
return newNode;
}
public List<Node<T>> iterate() {
return children;
}
public void remove(Node<T> node) {
children.remove(node);
}
public List<Node<T>> getChildren() {
return children;
}
public Node getParent() {
return parent;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
public class Tree2<T> extends Node<T> {
public Tree2(T data) {
super(data, null);
}
public boolean contains(T value) {
return recurse(iterate(), value);
}
private boolean recurse(List<Node<T>> children, T value) {
return children.stream()
.anyMatch(item -> item.getData().equals(value) || item.iterate().size() > 0 && recurse(item.iterate(), value));
}
}
The problem is is this line
if (getClass() != obj.getClass()) {
return false;
}
As one object is of class Tree and other is of Tree2
I have no idea why do you need two classes Tree and Tree2 but:
TreePoint
public class TreePoint {
public static void main(String[] args) {
Tree<String> rootFolder = new Tree<>("RootFolder");
Node<String> video = rootFolder.addChild("Video");
Node<String> music = rootFolder.addChild("Music");
Node<String> picture = rootFolder.addChild("Picture");
video.addChild("Terminator");
video.addChild("Die Hard");
video.addChild("Rocky");
music.addChild("Eminem");
Node<String> picture01 = picture.addChild("Picasso");
picture01.addChild("Do Vinci");
Node<String> picture02 = picture01.addChild("NN");
picture02.addChild("Cartoon");
picture02.addChild("Comics");
Tree2<String> rootFolder1 = new Tree2<>("RootFolder");
Node<String> video1 = rootFolder1.addChild("Video");
Node<String> music1 = rootFolder1.addChild("Music");
Node<String> picture1 = rootFolder1.addChild("Picture");
video1.addChild("Terminator");
video1.addChild("Die Hard");
video1.addChild("Rocky");
music1.addChild("Eminem");
Node<String> picture011 = picture1.addChild("Picasso");
picture011.addChild("Do Vinci");
Node<String> picture021 = picture011.addChild("NN");
picture021.addChild("Cartoon");
picture021.addChild("Comics");
printTree(rootFolder);
printTree(rootFolder1);
System.out.println(rootFolder.equals(rootFolder1));
}
private static <T> void printTree(Node<T> node) {
printTree(node, 0);
}
private static <T> void printTree(Node<T> node, int level) {
printNode(node, level);
if (node.getChildren() != null) {
for (Node childNode : node.getChildren()) {
printTree(childNode, level + 1);
}
}
}
private static <T> void printNode(Node<T> kid, int level) {
for (int i = 0; i < level; i++) {
System.out.print(" ");
}
System.out.println(kid.getData());
}
}
Tree
import java.util.List;
public class Tree<T> extends Node<T> {
public Tree(T data) {
super(data, null);
}
public boolean contains(T value) {
return recurse(iterate(), value);
}
private boolean recurse(List<Node<T>> children, T value) {
return children.stream()
.anyMatch(item -> item.getData().equals(value) || item.iterate().size() > 0 && recurse(item.iterate(), value));
}
}
Node
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class Node<T> {
public T data;
public final List<Node<T>> children = new ArrayList<>();
public final Node<T> parent;
public Node(T data, Node<T> parent) {
this.data = data;
this.parent = parent;
}
public void addChild(Node<T> node) {
children.add(node);
}
public Node<T> addChild(T nodeData) {
Node<T> newNode = new Node<T>(nodeData, this);
children.add(newNode);
return newNode;
}
public List<Node<T>> iterate() {
return children;
}
public void remove(Node<T> node) {
children.remove(node);
}
public List<Node<T>> getChildren() {
return children;
}
public Node getParent() {
return parent;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
Node<?> node = (Node<?>) o;
return Objects.equals(data, node.data) &&
Objects.equals(children, node.children);
}
#Override
public int hashCode() {
return Objects.hash(data, children, parent);
}
}
Tree2
import java.util.List;
public class Tree2<T> extends Node<T> {
public Tree2(T data) {
super(data, null);
}
public boolean contains(T value) {
return recurse(iterate(), value);
}
private boolean recurse(List<Node<T>> children, T value) {
return children.stream()
.anyMatch(item -> item.getData().equals(value) || item.iterate().size() > 0 && recurse(item.iterate(), value));
}
}
I have a customized JTree that shows file and folders of a directory, currently it only pick the desktop directory. I could not fine any line to modify it. also fileSystemView only has getters and not setter.
Here is my working code with default 'desktop' parent directory.
public final class MainPanel extends JPanel {
private MainPanel() {
super(new BorderLayout());
final FileSystemView fileSystemView = FileSystemView.getFileSystemView();
DefaultMutableTreeNode root = new DefaultMutableTreeNode();
final DefaultTreeModel treeModel = new DefaultTreeModel(root);
for (File fileSystemRoot: fileSystemView.getRoots()) {
DefaultMutableTreeNode node = new DefaultMutableTreeNode(new CheckBoxNode(fileSystemRoot, Status.DESELECTED));
root.add(node);
for (File file: fileSystemView.getFiles(fileSystemRoot, true)) {
if (file.isDirectory()) {
node.add(new DefaultMutableTreeNode(new CheckBoxNode(file, Status.DESELECTED)));
}
}
}
treeModel.addTreeModelListener(new CheckBoxStatusUpdateListener());
final JTree tree = new JTree(treeModel) {
#Override public void updateUI() {
setCellRenderer(null);
setCellEditor(null);
super.updateUI();
//???#1: JDK 1.6.0 bug??? Nimbus LnF
setCellRenderer(new FileTreeCellRenderer(fileSystemView));
setCellEditor(new CheckBoxNodeEditor(fileSystemView));
}
};
tree.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
tree.setRootVisible(false);
tree.addTreeSelectionListener(new FolderSelectionListener(fileSystemView));
//tree.setCellRenderer(new FileTreeCellRenderer(fileSystemView));
//tree.setCellEditor(new CheckBoxNodeEditor(fileSystemView));
tree.setEditable(true);
tree.expandRow(0);
//tree.setToggleClickCount(1);
setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
add(new JScrollPane(tree));
add(new JButton(new AbstractAction("test") {
#Override public void actionPerformed(ActionEvent ae) {
System.out.println("------------------");
searchTreeForCheckedNode(tree.getPathForRow(0));
// DefaultMutableTreeNode root = (DefaultMutableTreeNode) treeModel.getRoot();
// Enumeration e = root.breadthFirstEnumeration();
// while (e.hasMoreElements()) {
// DefaultMutableTreeNode node = (DefaultMutableTreeNode) e.nextElement();
// CheckBoxNode check = (CheckBoxNode) node.getUserObject();
// if (check != null && check.status == Status.SELECTED) {
// System.out.println(check.file.toString());
// }
// }
}
}), BorderLayout.SOUTH);
setPreferredSize(new Dimension(320, 240));
}
private static void searchTreeForCheckedNode(TreePath path) {
Object o = path.getLastPathComponent();
if (!(o instanceof DefaultMutableTreeNode)) {
return;
}
DefaultMutableTreeNode node = (DefaultMutableTreeNode) o;
o = node.getUserObject();
if (!(o instanceof CheckBoxNode)) {
return;
}
CheckBoxNode check = (CheckBoxNode) o;
if (check.status == Status.SELECTED) {
System.out.println(check.file.toString());
} else if (check.status == Status.INDETERMINATE && !node.isLeaf() && node.getChildCount() >= 0) {
Enumeration e = node.children();
while (e.hasMoreElements()) {
searchTreeForCheckedNode(path.pathByAddingChild(e.nextElement()));
}
}
}
public static void main(String... args) {
EventQueue.invokeLater(new Runnable() {
#Override public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException
| IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("FileSystemTreeWithCheckBox");
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
//frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.getContentPane().add(new MainPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
class TriStateCheckBox extends JCheckBox {
private Icon currentIcon;
#Override public void updateUI() {
currentIcon = getIcon();
setIcon(null);
super.updateUI();
EventQueue.invokeLater(new Runnable() {
#Override public void run() {
if (currentIcon != null) {
setIcon(new IndeterminateIcon());
}
setOpaque(false);
}
});
}
}
class IndeterminateIcon implements Icon {
private static final Color FOREGROUND = new Color(50, 20, 255, 200); //TEST: UIManager.getColor("CheckBox.foreground");
private static final int SIDE_MARGIN = 4;
private static final int HEIGHT = 2;
private final Icon icon = UIManager.getIcon("CheckBox.icon");
#Override public void paintIcon(Component c, Graphics g, int x, int y) {
icon.paintIcon(c, g, x, y);
int w = getIconWidth();
int h = getIconHeight();
Graphics2D g2 = (Graphics2D) g.create();
g2.setPaint(FOREGROUND);
g2.translate(x, y);
g2.fillRect(SIDE_MARGIN, (h - HEIGHT) / 2, w - SIDE_MARGIN - SIDE_MARGIN, HEIGHT);
//g2.translate(-x, -y);
g2.dispose();
}
#Override public int getIconWidth() {
return icon.getIconWidth();
}
#Override public int getIconHeight() {
return icon.getIconHeight();
}
}
enum Status { SELECTED, DESELECTED, INDETERMINATE }
class CheckBoxNode {
public final File file;
public final Status status;
public CheckBoxNode(File file) {
this.file = file;
status = Status.INDETERMINATE;
}
public CheckBoxNode(File file, Status status) {
this.file = file;
this.status = status;
}
#Override public String toString() {
return file.getName();
}
}
class FolderSelectionListener implements TreeSelectionListener {
private final FileSystemView fileSystemView;
public FolderSelectionListener(FileSystemView fileSystemView) {
this.fileSystemView = fileSystemView;
}
#Override public void valueChanged(TreeSelectionEvent e) {
final JTree tree = (JTree) e.getSource();
final DefaultMutableTreeNode node = (DefaultMutableTreeNode) e.getPath().getLastPathComponent();
if (!node.isLeaf()) {
return;
}
CheckBoxNode check = (CheckBoxNode) node.getUserObject();
if (check == null) {
return;
}
final File parent = check.file;
if (!parent.isDirectory()) {
return;
}
final Status parentStatus = check.status == Status.SELECTED ? Status.SELECTED : Status.DESELECTED;
final DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
Task worker = new Task(fileSystemView, parent) {
#Override protected void process(List<File> chunks) {
if (!tree.isDisplayable()) {
System.out.println("process: DISPOSE_ON_CLOSE");
cancel(true);
return;
}
for (File file: chunks) {
model.insertNodeInto(new DefaultMutableTreeNode(new CheckBoxNode(file, parentStatus)), node, node.getChildCount());
//node.add(new DefaultMutableTreeNode(new CheckBoxNode(file, parentStatus)));
}
//model.reload(parent); //= model.nodeStructureChanged(parent);
}
};
worker.execute();
}
}
class Task extends SwingWorker<String, File> {
private final FileSystemView fileSystemView;
private final File parent;
public Task(FileSystemView fileSystemView, File parent) {
super();
this.fileSystemView = fileSystemView;
this.parent = parent;
}
#Override public String doInBackground() {
File[] children = fileSystemView.getFiles(parent, true);
for (File child: children) {
if (child.isDirectory()) {
publish(child);
}
}
return "done";
}
}
class FileTreeCellRenderer extends TriStateCheckBox implements TreeCellRenderer {
private final FileSystemView fileSystemView;
private final JPanel panel = new JPanel(new BorderLayout());
private final DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();
public FileTreeCellRenderer(FileSystemView fileSystemView) {
super();
String uiName = getUI().getClass().getName();
if (uiName.contains("Synth") && System.getProperty("java.version").startsWith("1.7.0")) {
System.out.println("XXX: FocusBorder bug?, JDK 1.7.0, Nimbus start LnF");
renderer.setBackgroundSelectionColor(new Color(0, 0, 0, 0));
}
this.fileSystemView = fileSystemView;
panel.setFocusable(false);
panel.setRequestFocusEnabled(false);
panel.setOpaque(false);
panel.add(this, BorderLayout.WEST);
this.setOpaque(false);
}
#Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
JLabel l = (JLabel) renderer.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
l.setFont(tree.getFont());
if (value instanceof DefaultMutableTreeNode) {
this.setEnabled(tree.isEnabled());
this.setFont(tree.getFont());
Object userObject = ((DefaultMutableTreeNode) value).getUserObject();
if (userObject instanceof CheckBoxNode) {
CheckBoxNode node = (CheckBoxNode) userObject;
if (node.status == Status.INDETERMINATE) {
setIcon(new IndeterminateIcon());
} else {
setIcon(null);
}
setText("");
File file = (File) node.file;
l.setIcon(fileSystemView.getSystemIcon(file));
l.setText(fileSystemView.getSystemDisplayName(file));
l.setToolTipText(file.getPath());
setSelected(node.status == Status.SELECTED);
}
//panel.add(this, BorderLayout.WEST);
panel.add(l);
return panel;
}
return l;
}
#Override public void updateUI() {
super.updateUI();
if (panel != null) {
//panel.removeAll(); //??? Change to Nimbus LnF, JDK 1.6.0
panel.updateUI();
//panel.add(this, BorderLayout.WEST);
}
setName("Tree.cellRenderer");
//???#1: JDK 1.6.0 bug??? #see 1.7.0 DefaultTreeCellRenderer#updateUI()
//if (System.getProperty("java.version").startsWith("1.6.0")) {
// renderer = new DefaultTreeCellRenderer();
//}
}
}
class CheckBoxNodeEditor extends TriStateCheckBox implements TreeCellEditor {
private final FileSystemView fileSystemView;
private final JPanel panel = new JPanel(new BorderLayout());
private final DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();
private File file;
public CheckBoxNodeEditor(FileSystemView fileSystemView) {
super();
this.fileSystemView = fileSystemView;
this.addActionListener(new ActionListener() {
#Override public void actionPerformed(ActionEvent e) {
stopCellEditing();
}
});
panel.setFocusable(false);
panel.setRequestFocusEnabled(false);
panel.setOpaque(false);
panel.add(this, BorderLayout.WEST);
this.setOpaque(false);
}
#Override public Component getTreeCellEditorComponent(JTree tree, Object value, boolean isSelected, boolean expanded, boolean leaf, int row) {
//JLabel l = (JLabel) renderer.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
JLabel l = (JLabel) renderer.getTreeCellRendererComponent(tree, value, true, expanded, leaf, row, true);
l.setFont(tree.getFont());
setOpaque(false);
if (value instanceof DefaultMutableTreeNode) {
this.setEnabled(tree.isEnabled());
this.setFont(tree.getFont());
Object userObject = ((DefaultMutableTreeNode) value).getUserObject();
if (userObject instanceof CheckBoxNode) {
CheckBoxNode node = (CheckBoxNode) userObject;
if (node.status == Status.INDETERMINATE) {
setIcon(new IndeterminateIcon());
} else {
setIcon(null);
}
file = node.file;
l.setIcon(fileSystemView.getSystemIcon(file));
l.setText(fileSystemView.getSystemDisplayName(file));
setSelected(node.status == Status.SELECTED);
}
//panel.add(this, BorderLayout.WEST);
panel.add(l);
return panel;
}
return l;
}
#Override public Object getCellEditorValue() {
return new CheckBoxNode(file, isSelected() ? Status.SELECTED : Status.DESELECTED);
}
#Override public boolean isCellEditable(EventObject e) {
if (e instanceof MouseEvent && e.getSource() instanceof JTree) {
MouseEvent me = (MouseEvent) e;
JTree tree = (JTree) e.getSource();
TreePath path = tree.getPathForLocation(me.getX(), me.getY());
Rectangle r = tree.getPathBounds(path);
if (r == null) {
return false;
}
Dimension d = getPreferredSize();
r.setSize(new Dimension(d.width, r.height));
if (r.contains(me.getX(), me.getY())) {
if (file == null && System.getProperty("java.version").startsWith("1.7.0")) {
System.out.println("XXX: Java 7, only on first run\n" + getBounds());
setBounds(new Rectangle(0, 0, d.width, r.height));
}
//System.out.println(getBounds());
return true;
}
}
return false;
}
#Override public void updateUI() {
super.updateUI();
setName("Tree.cellEditor");
if (panel != null) {
//panel.removeAll(); //??? Change to Nimbus LnF, JDK 1.6.0
panel.updateUI();
//panel.add(this, BorderLayout.WEST);
}
//???#1: JDK 1.6.0 bug??? #see 1.7.0 DefaultTreeCellRenderer#updateUI()
//if (System.getProperty("java.version").startsWith("1.6.0")) {
// renderer = new DefaultTreeCellRenderer();
//}
}
//Copied from AbstractCellEditor
// protected EventListenerList listenerList = new EventListenerList();
// protected transient ChangeEvent changeEvent;
#Override public boolean shouldSelectCell(EventObject anEvent) {
return true;
}
#Override public boolean stopCellEditing() {
fireEditingStopped();
return true;
}
#Override public void cancelCellEditing() {
fireEditingCanceled();
}
#Override public void addCellEditorListener(CellEditorListener l) {
listenerList.add(CellEditorListener.class, l);
}
#Override public void removeCellEditorListener(CellEditorListener l) {
listenerList.remove(CellEditorListener.class, l);
}
public CellEditorListener[] getCellEditorListeners() {
return listenerList.getListeners(CellEditorListener.class);
}
protected void fireEditingStopped() {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length - 2; i >= 0; i -= 2) {
if (listeners[i] == CellEditorListener.class) {
// Lazily create the event:
if (changeEvent == null) {
changeEvent = new ChangeEvent(this);
}
((CellEditorListener) listeners[i + 1]).editingStopped(changeEvent);
}
}
}
protected void fireEditingCanceled() {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length - 2; i >= 0; i -= 2) {
if (listeners[i] == CellEditorListener.class) {
// Lazily create the event:
if (changeEvent == null) {
changeEvent = new ChangeEvent(this);
}
((CellEditorListener) listeners[i + 1]).editingCanceled(changeEvent);
}
}
}
}
class CheckBoxStatusUpdateListener implements TreeModelListener {
private boolean adjusting;
#Override public void treeNodesChanged(TreeModelEvent e) {
if (adjusting) {
return;
}
adjusting = true;
Object[] children = e.getChildren();
DefaultTreeModel model = (DefaultTreeModel) e.getSource();
DefaultMutableTreeNode node;
CheckBoxNode c; // = (CheckBoxNode) node.getUserObject();
if (children != null && children.length == 1) {
node = (DefaultMutableTreeNode) children[0];
c = (CheckBoxNode) node.getUserObject();
TreePath parent = e.getTreePath();
DefaultMutableTreeNode n = (DefaultMutableTreeNode) parent.getLastPathComponent();
while (n != null) {
updateParentUserObject(n);
DefaultMutableTreeNode tmp = (DefaultMutableTreeNode) n.getParent();
if (tmp == null) {
break;
} else {
n = tmp;
}
}
model.nodeChanged(n);
} else {
node = (DefaultMutableTreeNode) model.getRoot();
c = (CheckBoxNode) node.getUserObject();
}
updateAllChildrenUserObject(node, c.status);
model.nodeChanged(node);
adjusting = false;
}
private void updateParentUserObject(DefaultMutableTreeNode parent) {
Object userObject = parent.getUserObject();
if (userObject instanceof CheckBoxNode) {
File file = ((CheckBoxNode) userObject).file;
int selectedCount = 0;
int indeterminateCount = 0;
Enumeration children = parent.children();
while (children.hasMoreElements()) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode) children.nextElement();
CheckBoxNode check = (CheckBoxNode) node.getUserObject();
if (check.status == Status.INDETERMINATE) {
indeterminateCount++;
break;
}
if (check.status == Status.SELECTED) {
selectedCount++;
}
}
if (indeterminateCount > 0) {
parent.setUserObject(new CheckBoxNode(file));
} else if (selectedCount == 0) {
parent.setUserObject(new CheckBoxNode(file, Status.DESELECTED));
} else if (selectedCount == parent.getChildCount()) {
parent.setUserObject(new CheckBoxNode(file, Status.SELECTED));
} else {
parent.setUserObject(new CheckBoxNode(file));
}
}
}
private void updateAllChildrenUserObject(DefaultMutableTreeNode root, Status status) {
Enumeration breadth = root.breadthFirstEnumeration();
while (breadth.hasMoreElements()) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode) breadth.nextElement();
if (root.equals(node)) {
continue;
}
CheckBoxNode check = (CheckBoxNode) node.getUserObject();
node.setUserObject(new CheckBoxNode(check.file, status));
}
}
#Override public void treeNodesInserted(TreeModelEvent e) { /* not needed */ }
#Override public void treeNodesRemoved(TreeModelEvent e) { /* not needed */ }
#Override public void treeStructureChanged(TreeModelEvent e) { /* not needed */ }
}
Any idea to change its directory ?
Use a File instead of FileSystemView to define the root.
Use File#listFiles to list the files within a specified directory instead of FileSystemView#getFiles
Something like...
File rootPath = new File(".");
DefaultMutableTreeNode root = new DefaultMutableTreeNode();
final DefaultTreeModel treeModel = new DefaultTreeModel(root);
DefaultMutableTreeNode node = new DefaultMutableTreeNode(new CheckBoxNode(rootPath, Status.DESELECTED));
root.add(node);
for (File file : rootPath.listFiles()) {
if (file.isDirectory()) {
node.add(new DefaultMutableTreeNode(new CheckBoxNode(file, Status.DESELECTED)));
}
}
for example.
Take a look at java.io.File for more details
I have two java class under same package 1. mrbpdf.java and FileTreeDemo.java, I want set the JTree functionalities from FileTreeDemo.java to mrbpdf.java JTree, since I am newbie! finding difficulties to do it. Please give me directions, thanks, if my question is unclear please comment it, will change it accordingly.
Basically I want show the root (for example c:/ ) file directory in mrbpdf.java;
mrbpdf.java
public class mrbpdf {
private JFrame frmViperManufacturingRecord;
private JTextField txtText; //declearing here for global variable
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
mrbpdf window = new mrbpdf();
window.frmViperManufacturingRecord.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public mrbpdf() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
public void initialize() {
frmViperManufacturingRecord = new JFrame();
frmViperManufacturingRecord.setBackground(Color.GRAY);
frmViperManufacturingRecord.setTitle("Manufacturing Record Book");
frmViperManufacturingRecord.setBounds(100, 100, 1026, 702);
frmViperManufacturingRecord.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frmViperManufacturingRecord.getContentPane().setLayout(null);
JButton btnGeneratePdfHeader = new JButton("Generate PDF Header");
btnGeneratePdfHeader.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
//JOptionPane.showMessageDialog(null, "Welcome to viper");
txtText.setText("Hi User....");
}
});
btnGeneratePdfHeader.setFont(new Font("Calibri", Font.BOLD, 12));
btnGeneratePdfHeader.setBounds(786, 183, 156, 23);
frmViperManufacturingRecord.getContentPane().add(btnGeneratePdfHeader);
txtText = new JTextField();
txtText.setText("text1");
txtText.setBounds(678, 182, 98, 23);
frmViperManufacturingRecord.getContentPane().add(txtText);
txtText.setColumns(10);
JTree tree = new JTree();
tree.setBounds(10, 11, 304, 624);
//tree.setModel("FileTreeDemo");
JScrollPane scrollpane = new JScrollPane(tree);
frmViperManufacturingRecord.getContentPane().add(tree);
}
}
FileTreeDemo.java
public class FileTreeDemo {
public static void main(String[] args) {
File root;
if (args.length > 0) root = new File(args[0]);
else root = new File(System.getProperty("user.home"));
FileTreeModel model = new FileTreeModel(root);
JTree tree = new JTree();
tree.setModel(model);
// The JTree can get big, so allow it to scroll.
JScrollPane scrollpane = new JScrollPane(tree);
// Display it all in a window and make the window appear
JFrame frame = new JFrame("FileTreeDemo");
frame.getContentPane().add(scrollpane, "Center");
frame.setSize(400,600);
frame.setVisible(true);
}
}
class FileTreeModel implements TreeModel {
// We specify the root directory when we create the model.
protected File root;
public FileTreeModel(File root) { this.root = root; }
// The model knows how to return the root object of the tree
public Object getRoot() { return root; }
// Tell JTree whether an object in the tree is a leaf or not
public boolean isLeaf(Object node) { return ((File)node).isFile(); }
// Tell JTree how many children a node has
public int getChildCount(Object parent) {
String[] children = ((File)parent).list();
if (children == null) return 0;
return children.length;
}
public Object getChild(Object parent, int index) {
String[] children = ((File)parent).list();
if ((children == null) || (index >= children.length)) return null;
return new File((File) parent, children[index]);
}
public int getIndexOfChild(Object parent, Object child) {
String[] children = ((File)parent).list();
if (children == null) return -1;
String childname = ((File)child).getName();
for(int i = 0; i < children.length; i++) {
if (childname.equals(children[i])) return i;
}
return -1;
}
public void valueForPathChanged(TreePath path, Object newvalue) {}
public void addTreeModelListener(TreeModelListener l) {}
public void removeTreeModelListener(TreeModelListener l) {}
}
If you want to use the FileTreeModel tree model in the mrbpdf class, you can use this code in the mrbpdf.initialize method:
//JTree tree = new JTree();
File root = new File(System.getProperty("user.home"));
FileTreeModel model = new FileTreeModel(root);
JTree tree = new JTree(model);
To add scrolling as well, this code could help you (in the same method as above):
//tree.setBounds(10, 11, 304, 624);
JScrollPane scrollpane = new JScrollPane(tree);
scrollpane.setBounds(10, 11, 304, 624);
//frmViperManufacturingRecord.getContentPane().add(tree);
frmViperManufacturingRecord.getContentPane().add(scrollpane);
Edit - to support multiple roots, you could use a different tree model, like for example:
class MultipleDirectoriesTreeModel implements TreeModel {
protected List<File> roots;
public MultipleDirectoriesTreeModel(File... roots) {
this.roots = Arrays.asList(roots);
}
public Object getRoot() { return this; }
public boolean isLeaf(Object node) {
return node instanceof File && ((File)node).isFile();
}
public int getChildCount(Object parent) {
if (parent == this)
return roots.size();
else {
String[] children = ((File) parent).list();
if (children == null)
return 0;
return children.length;
}
}
public Object getChild(Object parent, int index) {
if (parent == this)
return index >= 0 && index < roots.size() ? roots.get(index) : null;
else {
String[] children = ((File) parent).list();
if ((children == null) || (index >= children.length))
return null;
return new File((File) parent, children[index]);
}
}
public int getIndexOfChild(Object parent, Object child) {
String childname = ((File) child).getName();
if (parent == this) {
for (int rootIndex = 0; rootIndex < roots.size(); rootIndex++)
if (childname.equals(roots.get(rootIndex).getName()))
return rootIndex;
return -1;
} else {
String[] children = ((File) parent).list();
if (children == null)
return -1;
for (int i = 0; i < children.length; i++) {
if (childname.equals(children[i]))
return i;
}
return -1;
}
}
#Override
public String toString() {
return "My Computer";
}
public void valueForPathChanged(TreePath path, Object newvalue) {}
public void addTreeModelListener(TreeModelListener l) {}
public void removeTreeModelListener(TreeModelListener l) {}
}
This tree model could be initialized like this:
MultipleDirectoriesTreeModel model
= new MultipleDirectoriesTreeModel(new File("C:\\"), new File("D:\\"));
I want to create a tree with given nodes and children. The required behavior is as follows:
"when a node's checkbox is toggled, it's new value (checked/unchecked) should be reflected to all of it's descendants"
Following is the full code, which is not giving expected behavior:
public class CheckBoxTree {
Map<String, DefaultMutableTreeNode> nodes = new HashMap<String, DefaultMutableTreeNode>();
public static void main(final String args[]) {
final CheckBoxTree cbt = new CheckBoxTree();
DefaultMutableTreeNode root = cbt.addNodeWithoutCheckbox(null, "Select divisions");
DefaultMutableTreeNode nodeSTD1 = cbt.addNodeWithCheckbox(root, "STD1", false);
cbt.nodes.put("STD1", nodeSTD1);
DefaultMutableTreeNode nodeDiv1 = cbt.addNodeWithCheckbox(nodeSTD1, "DIV1", false);
cbt.nodes.put("DIV1", nodeDiv1);
DefaultMutableTreeNode nodeDiv2 = cbt.addNodeWithCheckbox(nodeSTD1, "DIV2", false);
cbt.nodes.put("DIV2", nodeDiv2);
root.add(nodeSTD1);
DefaultMutableTreeNode nodeSTD2 = cbt.addNodeWithCheckbox(root, "STD2", false);
cbt.nodes.put("STD2", nodeSTD2);
DefaultMutableTreeNode nodeDiv3 = cbt.addNodeWithCheckbox(nodeSTD2, "DIV3", false);
cbt.nodes.put("DIV3", nodeDiv3);
DefaultMutableTreeNode nodeDiv4 = cbt.addNodeWithCheckbox(nodeSTD2, "DIV4", false);
cbt.nodes.put("DIV4", nodeDiv4);
root.add(nodeSTD2);
final JTree tree = cbt.createCheckBoxTree(root);
// show the tree onscreen
final JFrame frame = new JFrame("CheckBox Tree");
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.add(tree, BorderLayout.CENTER);
JButton button = new JButton("Submit");
panel.add(button, BorderLayout.SOUTH);
final JScrollPane scrollPane = new JScrollPane(panel);
frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 150);
frame.setVisible(true);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
/*TreePath[] selectionPaths = tree.getSelectionModel().getSelectionPaths();
// TreePath[] selectionPaths = tree.getSelectionPaths();
if (selectionPaths != null) {
System.out.println("Selected paths:");
for (TreePath tp : selectionPaths) {
System.out.println(tp);
}
}*/
System.out.println("Selected paths:");
for (DefaultMutableTreeNode n : cbt.nodes.values()) {
Object obj = n.getUserObject();
if (obj instanceof CheckBoxNode) {
if (((CheckBoxNode) obj).isSelected()) {
System.out.println(n.toString());
}
}
}
}
});
}
private JTree createCheckBoxTree(final DefaultMutableTreeNode root) {
final DefaultTreeModel treeModel = new DefaultTreeModel(root);
final JTree tree = new JTree(treeModel);
final CheckBoxNodeRenderer renderer = new CheckBoxNodeRenderer();
tree.setCellRenderer(renderer);
final CheckBoxNodeEditor editor = new CheckBoxNodeEditor(tree);
tree.setCellEditor(editor);
tree.setEditable(true);
// listen for changes in the model (including check box toggles)
treeModel.addTreeModelListener(new TreeModelListener() {
#Override
public void treeNodesChanged(final TreeModelEvent e) {
System.out.println(System.currentTimeMillis() + ": nodes changed");
DefaultMutableTreeNode node =
(DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
if (node == null) {
return;
}
changeSubTreeSelections(node, null);
}
#Override
public void treeNodesInserted(final TreeModelEvent e) {
System.out.println(System.currentTimeMillis() + ": nodes inserted");
}
#Override
public void treeNodesRemoved(final TreeModelEvent e) {
System.out.println(System.currentTimeMillis() + ": nodes removed");
}
#Override
public void treeStructureChanged(final TreeModelEvent e) {
System.out.println(System.currentTimeMillis() + ": structure changed");
}
});
// listen for changes in the selection
tree.addTreeSelectionListener(new TreeSelectionListener() {
#Override
public void valueChanged(TreeSelectionEvent arg0) {
System.out.println(System.currentTimeMillis() + ": value changed");
/*DefaultMutableTreeNode node =
(DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
if (node == null) {
return;
}
changeSubTreeSelections(node, null);*/
}
});
return tree;
}
protected void changeSubTreeSelections(DefaultMutableTreeNode node, Boolean selected) {
/*change all subtree selection if applicable*/
Object obj = node.getUserObject();
Boolean isSelected = selected;
if (obj instanceof CheckBoxNode) {
CheckBoxNode cbn = (CheckBoxNode) obj;
if (isSelected == null) {
isSelected = cbn.isSelected();
} else {
cbn.setSelected(isSelected);
}
} else {
return;
}
int count = node.getChildCount();
for (int i = 0; i < count; i++) {
DefaultMutableTreeNode child = (DefaultMutableTreeNode) node.getChildAt(i);
changeSubTreeSelections(child, isSelected);
}
}
public DefaultMutableTreeNode addNodeWithCheckbox(
final DefaultMutableTreeNode parent, final String text, final boolean checked) {
final CheckBoxNode data = new CheckBoxNode(text, checked);
final DefaultMutableTreeNode node = new DefaultMutableTreeNode(data);
if (parent != null) {
parent.add(node);
}
return node;
}
public DefaultMutableTreeNode addNodeWithoutCheckbox(
final DefaultMutableTreeNode parent, final String text) {
final DefaultMutableTreeNode node = new DefaultMutableTreeNode(text);
if (parent != null) {
parent.add(node);
}
return node;
}
/*private static DefaultMutableTreeNode add(
final DefaultMutableTreeNode parent, final String text, final boolean checked) {
final CheckBoxNode data = new CheckBoxNode(text, checked);
final DefaultMutableTreeNode node = new DefaultMutableTreeNode(data);
parent.add(node);
nodes.put(text, node);
return node;
}*/
}
class CheckBoxNodeRenderer implements TreeCellRenderer {
private JCheckBox checkBoxNodeRenderer = new JCheckBox();
private DefaultTreeCellRenderer nonCheckBoxNodeRenderer = new DefaultTreeCellRenderer();
private Color selectionBorderColor, selectionForegroundColor, selectionBackgroundColor,
textForegroundColor, textBackgroundColor;
protected JCheckBox getLeafCheckBox() {
return checkBoxNodeRenderer;
}
public CheckBoxNodeRenderer() {
Font fontValue;
fontValue = UIManager.getFont("Tree.font");
if (fontValue != null) {
checkBoxNodeRenderer.setFont(fontValue);
}
Boolean booleanValue = (Boolean) UIManager.get("Tree.drawsFocusBorderAroundIcon");
checkBoxNodeRenderer.setFocusPainted((booleanValue != null)
&& (booleanValue.booleanValue()));
selectionBorderColor = UIManager.getColor("Tree.selectionBorderColor");
selectionForegroundColor = UIManager.getColor("Tree.selectionForeground");
selectionBackgroundColor = UIManager.getColor("Tree.selectionBackground");
textForegroundColor = UIManager.getColor("Tree.textForeground");
textBackgroundColor = UIManager.getColor("Tree.textBackground");
}
#Override
public Component getTreeCellRendererComponent(
JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row,
boolean hasFocus) {
Component returnValue;
/*check if it is checkbox object*/
boolean isCheckboxObject = false;
if ((value != null) && (value instanceof DefaultMutableTreeNode)) {
Object userObject = ((DefaultMutableTreeNode) value).getUserObject();
if (userObject instanceof CheckBoxNode) {
isCheckboxObject = true;
CheckBoxNode node = (CheckBoxNode) userObject;
checkBoxNodeRenderer.setText(node.getText());
checkBoxNodeRenderer.setSelected(node.isSelected());
}
} else {
String stringValue =
tree.convertValueToText(value, selected, expanded, leaf, row, false);
checkBoxNodeRenderer.setText(stringValue);
checkBoxNodeRenderer.setSelected(false);
}
if (isCheckboxObject) {
checkBoxNodeRenderer.setEnabled(tree.isEnabled());
if (selected) {
checkBoxNodeRenderer.setForeground(selectionForegroundColor);
checkBoxNodeRenderer.setBackground(selectionBackgroundColor);
} else {
checkBoxNodeRenderer.setForeground(textForegroundColor);
checkBoxNodeRenderer.setBackground(textBackgroundColor);
}
returnValue = checkBoxNodeRenderer;
} else {
returnValue =
nonCheckBoxNodeRenderer.getTreeCellRendererComponent(tree, value, selected,
expanded, leaf, row, hasFocus);
}
return returnValue;
}
}
class CheckBoxNodeEditor extends AbstractCellEditor implements TreeCellEditor {
private static final long serialVersionUID = 1L;
private CheckBoxNodeRenderer renderer = new CheckBoxNodeRenderer();
private ChangeEvent changeEvent = null;
private JTree tree;
public CheckBoxNodeEditor(JTree tree) {
this.tree = tree;
}
#Override
public Object getCellEditorValue() {
JCheckBox checkbox = renderer.getLeafCheckBox();
CheckBoxNode checkBoxNode = new CheckBoxNode(checkbox.getText(), checkbox.isSelected());
return checkBoxNode;
}
#Override
public boolean isCellEditable(EventObject event) {
/*uncomment following code to make all nodes editable*/
// return true;
// make all nodes, which are instance of CheckBoxNode, editable
boolean returnValue = false;
if (event instanceof MouseEvent) {
MouseEvent mouseEvent = (MouseEvent) event;
TreePath path = tree.getPathForLocation(mouseEvent.getX(), mouseEvent.getY());
if (path != null) {
Object node = path.getLastPathComponent();
if ((node != null) && (node instanceof DefaultMutableTreeNode)) {
DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) node;
Object userObject = treeNode.getUserObject();
returnValue = (userObject instanceof CheckBoxNode);
// returnValue = ((treeNode.isLeaf()) && (userObject
// instanceof CheckBoxNode));
}
}
}
return returnValue;
}
#Override
public Component getTreeCellEditorComponent(
JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row) {
Component editor =
renderer.getTreeCellRendererComponent(tree, value, false, expanded, leaf, row, true);
// editor always selected / focused
ItemListener itemListener = new ItemListener() {
public void itemStateChanged(ItemEvent itemEvent) {
if (stopCellEditing()) {
fireEditingStopped();
}
}
};
if (editor instanceof JCheckBox) {
((JCheckBox) editor).addItemListener(itemListener);
}
return editor;
}
}
class CheckBoxNode {
private String text;
private boolean selected;
public CheckBoxNode(String text, boolean selected) {
this.text = text;
this.selected = selected;
}
public boolean isSelected() {
return selected;
}
public void setSelected(boolean newValue) {
selected = newValue;
}
public String getText() {
return text;
}
public void setText(String newValue) {
text = newValue;
}
/*#Override
public String toString() {
return getClass().getName() + "[" + text + "/" + selected + "]";
}*/
#Override
public String toString() {
return text;
}
}
class NamedVector extends Vector<Object> {
private static final long serialVersionUID = 1L;
private String name;
public NamedVector(String name) {
this.name = name;
}
public NamedVector(String name, Object elements[]) {
this.name = name;
for (int i = 0, n = elements.length; i < n; i++) {
add(elements[i]);
}
}
#Override
public String toString() {
return "[" + name + "]";
}
}
The toggling of any parent nodes' checkbox not reflecting correctly in children nodes.
Please help me to understand where the problem is.
add treeDidChange to repaint the tree.
#Override
public void treeNodesChanged(final TreeModelEvent e) {
System.out.println(System.currentTimeMillis() + ": nodes changed");
DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
if (node == null) {
return;
}
changeSubTreeSelections(node, null);
tree.treeDidChange();
}
What's more, I found that in the function changeSubTreeSelections, this line isSelected = !(cbn.isSelected()); is incorrect. You shouldn't use ! to get an opposite value.
And maybe it's better that you expand the whole descendants' path, if the parent node is selected.
I have a JTree with a custom model and custom renderer. They seem to work fine, except that when I expand a node that has multiple child nodes, it draws all child nodes to the same rectangle so only the last node is visible. I can iterate through the child nodes and I can print them to the console, but the UI is different.
This is a sketch of the UI:
// for 1 child node:
ROOT
-- <rendered node>
//for 2 child nodes:
ROOT
|
-- <rendered node - the data of the 2nd node>
//for 3 child nodes:
ROOT
|
|
-- <rendered node - the data of the 3rd node>
I figured out that the BasicTreeUI uses getPathBounds() to determine the bounds of a certain node. Here is how I check it:
doStuffWithTree(JTree tree) {
tree.expandNode(0);
for (int i = 0; i < tree.getRowCount(); i++) {
TreePath tp = tree.getPathForRow(i);
tree.makeVisible(tp);
System.out.println("Bounds of row " + i + ": " + tree.getPathBounds(tp));
}
}
With this check I get that all the nodes - except the node 0 - have the same bounds.
I tried a few tricks with expanding the tree, e.g. expanding all nodes starting from the first; then starting from the last - they all have the same effect.
Finally, the question: what class could I modify to fix this behavior? Are there any known workarounds?
UPDATE
Apparently, something needs to be fixed on the TreeNode implementation. Also, I need to correct myself: I didn't have a custom model, but a cusomtom TreeNode. Here is the SSCCE:
package com.example.jtree;
//lots of obvious imports
public class JTreeBoundsExample extends JFrame {
public static void main(String... args) {
JTreeBoundsExample m = new JTreeBoundsExample();
m.setSize(275, 300);
m.setDefaultCloseOperation(EXIT_ON_CLOSE);
m.setVisible(true);
}
public JTreeBoundsExample() {
ValueTreeNode root = new ValueTreeNode(null, "root");
ValueTreeNode category = new ValueTreeNode(root, "category");
category.put("k1", new ValueTreeNode(category, "v1"));
category.put("k2", new ValueTreeNode(category, "v2"));
category.put("k3", new ValueTreeNode(category, "v3"));
root.put("category", category);
JTree tree = new JTree(root);
tree.setCellRenderer(new ValueCellRenderer());
tree.setRootVisible(false);
tree.expandRow(0);
for (int i = 0; i < tree.getRowCount(); i++) {
TreePath tp = tree.getPathForRow(i);
tree.makeVisible(tp);
System.out.println("Bounds of row " + i + ": " + tree.getPathBounds(tp));
}
Container content = getContentPane();
content.add(new JScrollPane(tree), BorderLayout.CENTER);
}
private static class ValueTreeNode extends HashMap<String, ValueTreeNode> implements TreeNode {
private List<String> keys = new ArrayList<String>();
private TreeNode parent;
private String value;
public ValueTreeNode(TreeNode parent, String value) {
this.parent = parent;
this.value = value;
}
#Override
public ValueTreeNode put(String key, ValueTreeNode val) {
ValueTreeNode old = super.put(key, val);
if (old == null) {
sortKeys();
}
return old;
}
private void sortKeys() {
keys.clear();
keys.addAll(keySet());
Collections.sort(keys);
}
#Override
public Enumeration children() {
final Iterator<String> it = keys.iterator();
return new Enumeration() {
#Override
public boolean hasMoreElements() {
return it.hasNext();
}
#Override
public Object nextElement() {
return it.next();
}
};
}
#Override
public boolean getAllowsChildren() {
return true;
}
#Override
public TreeNode getChildAt(int pos) {
return get(keys.get(pos));
}
#Override
public int getChildCount() {
return size();
}
#Override
public int getIndex(TreeNode arg0) {
return -1;
}
#Override
public TreeNode getParent() {
return parent;
}
#Override
public boolean isLeaf() {
return size() == 0;
}
}
private static class ValueCellRenderer extends DefaultTreeCellRenderer {
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded,
boolean leaf, int row, boolean hasFocus) {
super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
if (value instanceof ValueTreeNode) {
ValueTreeNode vtn = (ValueTreeNode) value;
setText(vtn.value);
}
return this;
}
}
}