I have a class structure as follows:
DefaultMutableTreeNode
|_
BCStructure
|_
| Module
|_
| Section
|_
Page
Module, Section, and Page are what I actually use in my JTree. If you run the sample code below, the drag and drop works. Notice it is using DefaultMutableTreeNodes. If however, I place the code in my real applicaiont which uses the subclasses of DefualtMutableTreeNode, it does not work.
While stepping through the code, I have noticed two areas of interest. The first is this:
class TreeTransferHandler extends TransferHandler {
DataFlavor nodesFlavor;
DataFlavor[] flavors = new DataFlavor[1];
DefaultMutableTreeNode[] nodesToRemove;
public TreeTransferHandler() {
try {
String mimeType = DataFlavor.javaJVMLocalObjectMimeType
+ ";class=\""
+ javax.swing.tree.DefaultMutableTreeNode[].class.getName()
+ "\"";
nodesFlavor = new DataFlavor(mimeType);
flavors[0] = nodesFlavor;
} catch (ClassNotFoundException e) {
System.out.println("ClassNotFound: " + e.getMessage());
}
}
This is where it sets the DataFlavor. It is setting it to a DefualtMutableTreeNode array which I assume is correct since DefaultMutableTreeNode is the super class of my nodes. But this was one area where I thought the problem could lie.
The other point is while debugging this code, I get as far as:
public DataFlavor[] getTransferDataFlavors() {
return flavors;
}
before the drag and drop fails. I assume that it returns a DataFlavor that is not liked to well. This is why I think there is something wrong with the DataFlavor. Is there something more I need to do/modify in order for this to work with subclasses? Any ideas or suggestions?
Thanks!
Complete sample code:
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.dnd.*;
import java.util.*;
import java.util.List;
import javax.swing.*;
import javax.swing.tree.*;
public class TreeDragAndDrop {
private JScrollPane getContent() {
JTree tree = new JTree();
tree.setDragEnabled(true);
tree.setDropMode(DropMode.ON_OR_INSERT);
tree.setTransferHandler(new TreeTransferHandler());
tree.getSelectionModel().setSelectionMode(
TreeSelectionModel.CONTIGUOUS_TREE_SELECTION);
expandTree(tree);
return new JScrollPane(tree);
}
private void expandTree(JTree tree) {
DefaultMutableTreeNode root =
(DefaultMutableTreeNode)tree.getModel().getRoot();
Enumeration e = root.breadthFirstEnumeration();
while(e.hasMoreElements()) {
DefaultMutableTreeNode node =
(DefaultMutableTreeNode)e.nextElement();
if(node.isLeaf()) continue;
int row = tree.getRowForPath(new TreePath(node.getPath()));
tree.expandRow(row);
}
}
public static void main(String[] args) {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new TreeDragAndDrop().getContent());
f.setSize(400,400);
f.setLocation(200,200);
f.setVisible(true);
}
}
class TreeTransferHandler extends TransferHandler {
DataFlavor nodesFlavor;
DataFlavor[] flavors = new DataFlavor[1];
DefaultMutableTreeNode[] nodesToRemove;
public TreeTransferHandler() {
try {
String mimeType = DataFlavor.javaJVMLocalObjectMimeType +
";class=\"" +
javax.swing.tree.DefaultMutableTreeNode[].class.getName() +
"\"";
nodesFlavor = new DataFlavor(mimeType);
flavors[0] = nodesFlavor;
} catch(ClassNotFoundException e) {
System.out.println("ClassNotFound: " + e.getMessage());
}
}
public boolean canImport(TransferHandler.TransferSupport support) {
if(!support.isDrop()) {
return false;
}
support.setShowDropLocation(true);
if(!support.isDataFlavorSupported(nodesFlavor)) {
return false;
}
// Do not allow a drop on the drag source selections.
JTree.DropLocation dl =
(JTree.DropLocation)support.getDropLocation();
JTree tree = (JTree)support.getComponent();
int dropRow = tree.getRowForPath(dl.getPath());
int[] selRows = tree.getSelectionRows();
for(int i = 0; i 0 &&
target.getLevel() 0 && selRows.length == 1)
return false;
// first may have children.
for(int i = 1; i selRows.length-1) {
// Not all children of first are selected.
return false;
}
}
}
return true;
}
protected Transferable createTransferable(JComponent c) {
JTree tree = (JTree)c;
TreePath[] paths = tree.getSelectionPaths();
if(paths != null) {
// Make up a node array of copies for transfer and
// another for/of the nodes that will be removed in
// exportDone after a successful drop.
List copies =
new ArrayList();
List toRemove =
new ArrayList();
DefaultMutableTreeNode node =
(DefaultMutableTreeNode)paths[0].getLastPathComponent();
DefaultMutableTreeNode copy = copy(node);
copies.add(copy);
toRemove.add(node);
for(int i = 1; i node.getLevel()) { // child node
copy.add(copy(next));
// node already contains child
} else { // sibling
copies.add(copy(next));
toRemove.add(next);
}
}
DefaultMutableTreeNode[] nodes =
copies.toArray(new DefaultMutableTreeNode[copies.size()]);
nodesToRemove =
toRemove.toArray(new DefaultMutableTreeNode[toRemove.size()]);
return new NodesTransferable(nodes);
}
return null;
}
/** Defensive copy used in createTransferable. */
private DefaultMutableTreeNode copy(TreeNode node) {
return new DefaultMutableTreeNode(node);
}
protected void exportDone(JComponent source, Transferable data, int action) {
if((action & MOVE) == MOVE) {
JTree tree = (JTree)source;
DefaultTreeModel model = (DefaultTreeModel)tree.getModel();
// Remove nodes saved in nodesToRemove in createTransferable.
for(int i = 0; i
If you think the problem is that you subclass the DefaultMutableTreeNode, try making your DataFlavor to be an array of Object, or even better, an ArrayList:
DataFlavor.javaJVMLocalObjectMimeType + ";class=java.util.ArrayList"
This way you can return your copies list along with your transferable. Maybe it will avoid the problem.
here's a rough scetch of how to do this with lists:
import javax.swing.*;
import javax.swing.tree.*;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
import java.util.*;
import java.util.List;
/**
* Author: Denis Tulskiy
* Date: 1/5/11
*/
public class Test extends JFrame {
class NodeA extends DefaultMutableTreeNode {
NodeA(Object userObject) {
super(userObject);
}
}
class NodeB extends DefaultMutableTreeNode {
NodeB(Object userObject) {
super(userObject);
}
}
class NodeC extends DefaultMutableTreeNode {
NodeC(Object userObject) {
super(userObject);
}
}
private static class MyTransferHandler extends TransferHandler {
#Override
public int getSourceActions(JComponent c) {
return MOVE;
}
#Override
protected Transferable createTransferable(JComponent c) {
JTree tree = (JTree) c;
ArrayList<TreeNode> nodes = new ArrayList<TreeNode>();
for (TreePath path : tree.getSelectionPaths()) {
DefaultMutableTreeNode component = (DefaultMutableTreeNode) path.getLastPathComponent();
nodes.add(component);
}
return new NodesTransferable(nodes);
}
#Override
public boolean canImport(TransferSupport support) {
return support.isDataFlavorSupported(NodesTransferable.getDataFlavor());
}
#Override
public boolean importData(TransferSupport support) {
if (!canImport(support)) {
return false;
}
JTree tree = (JTree) support.getComponent();
List<DefaultMutableTreeNode> data = null;
try {
data = (List<DefaultMutableTreeNode>) support.getTransferable().getTransferData(NodesTransferable.getDataFlavor());
} catch (UnsupportedFlavorException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
if (data != null) {
Point dropPoint = support.getDropLocation().getDropPoint();
TreePath path = tree.getPathForLocation(dropPoint.x, dropPoint.y);
DefaultMutableTreeNode parent = (DefaultMutableTreeNode) path.getLastPathComponent();
for (DefaultMutableTreeNode node : data) {
node.removeFromParent();
parent.add(node);
}
DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
model.reload();
}
return true;
}
}
static class NodesTransferable implements Transferable {
private static DataFlavor dataFlavor;
public static DataFlavor getDataFlavor() {
if (dataFlavor == null) {
try {
dataFlavor = new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType + ";class=java.util.ArrayList");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
return dataFlavor;
}
private java.util.List<TreeNode> nodes;
NodesTransferable(List<TreeNode> nodes) {
this.nodes = nodes;
}
#Override
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[]{getDataFlavor()};
}
#Override
public boolean isDataFlavorSupported(DataFlavor flavor) {
return flavor.match(dataFlavor);
}
#Override
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
return nodes;
}
}
public Test() {
JTree tree = new JTree();
tree.setDragEnabled(true);
tree.setDropMode(DropMode.ON_OR_INSERT);
DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root");
NodeA child = new NodeA("nodea");
root.add(child);
child.add(new NodeB("nodeb"));
child.add(new NodeC("nodec"));
tree.setModel(new DefaultTreeModel(root));
tree.setTransferHandler(new MyTransferHandler());
setLayout(new BorderLayout());
add(tree, BorderLayout.CENTER);
setSize(300, 400);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void main(String[] args) {
new Test().setVisible(true);
}
}
Related
I'm exploring How to do the implementation of the Copy & Paste of JTree.
Because, I want Copy from DefaultMutableTreeNode like toString() to paste in another application like Sublime Text.
I was viewing the code in order to view how copy & paste is implemented and how is used drag and drop in JTree.
My first thougth was, Copy and Paste between DefaultMutableTreeNode of JTree must be tested, later how paste from Clipboard to another application, but my code is not working and Don't know why is failing, and I need to solve.
NOTE: Sorry my code is a bit long, because if I put only a snippet code will be non functional. For me all code here is needed to do tests.
Here my code:
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.event.ActionEvent;
import java.util.*;
import javax.swing.*;
import javax.swing.tree.*;
public class JTreeTransferHandler extends JFrame {
public JTreeTransferHandler() {
initiate();
}
private void initiate() {
setTitle("Copy from JTree");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400,400);
setLocation(200,200);
setVisible(true);
DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root");
DefaultMutableTreeNode vegetableNode = new DefaultMutableTreeNode("Vegetables");
vegetableNode.add(new DefaultMutableTreeNode("Capsicum"));
vegetableNode.add(new DefaultMutableTreeNode("Carrot"));
DefaultMutableTreeNode fruitNode = new DefaultMutableTreeNode("Fruits");
fruitNode.add(new DefaultMutableTreeNode("Mango"));
fruitNode.add(new DefaultMutableTreeNode("Apple"));
root.add(vegetableNode);
root.add(fruitNode);
JTree tree = new JTree(root);
TreeTransferHandler treeTransferHandler = new TreeTransferHandler();
tree.setTransferHandler(treeTransferHandler);
Clipboard clipboard = this.getToolkit().getSystemClipboard();
JButton copy = new JButton("Copy");
copy.addActionListener((ActionEvent e) -> {
TransferHandler handler = tree.getTransferHandler();
handler.exportToClipboard(tree, clipboard, TransferHandler.COPY);
});
JButton paste = new JButton("Paste");
paste.addActionListener((ActionEvent e) -> {
Transferable clipData = clipboard.getContents(clipboard);
if (clipData != null) {
if (clipData.isDataFlavorSupported(treeTransferHandler.nodesFlavor)) {
TransferHandler handler = tree.getTransferHandler();
handler.importData(tree, clipData);
}
}
});
JPanel buttonsPanel = new JPanel();
buttonsPanel.add(copy);
buttonsPanel.add(paste);
add(new JScrollPane(tree), BorderLayout.CENTER);
add(buttonsPanel, BorderLayout.SOUTH);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JTreeTransferHandler jTreeTransferHandler = new JTreeTransferHandler();
});
}
}
class TreeTransferHandler extends TransferHandler {
DataFlavor nodesFlavor;
DataFlavor[] flavors = new DataFlavor[1];
DefaultMutableTreeNode[] nodesToRemove;
public TreeTransferHandler() {
try {
String mimeType = DataFlavor.javaJVMLocalObjectMimeType + ";class=\"" +
DefaultMutableTreeNode[].class.getName() + "\"";
nodesFlavor = new DataFlavor(mimeType);
flavors[0] = nodesFlavor;
} catch(ClassNotFoundException e) {
System.out.println("ClassNotFound: " + e.getMessage());
}
}
//TransferHandler
#Override public int getSourceActions(JComponent c) {
return TransferHandler.COPY;
}
//TransferHandler
#Override public boolean canImport(JComponent comp, DataFlavor flavor[]) {
for (int i = 0, n = flavor.length; i < n; i++) {
for (int j = 0, m = flavors.length; j < m; j++) {
if (flavor[i].equals(flavors[j])) {
return true;
}
}
}
return false;
}
//TransferHandler
#Override protected Transferable createTransferable(JComponent c) {
JTree tree = (JTree) c;
TreePath[] paths = tree.getSelectionPaths();
if (paths != null) {
List<DefaultMutableTreeNode> copies = new ArrayList<>();
List<DefaultMutableTreeNode> toRemove = new ArrayList<>();
DefaultMutableTreeNode node =
(DefaultMutableTreeNode) paths[0].getLastPathComponent();
DefaultMutableTreeNode copy = copy(node);
copies.add(copy);
toRemove.add(node);
for (int i = 1; i < paths.length; i++) {
DefaultMutableTreeNode next =
(DefaultMutableTreeNode) paths[i].getLastPathComponent();
// Do not allow higher level nodes to be added to list.
if (next.getLevel() < node.getLevel()) {
break;
} else if (next.getLevel() > node.getLevel()) { // child node
copy.add(copy(next));
// node already contains child
} else { // sibling
copies.add(copy(next));
toRemove.add(next);
}
}
DefaultMutableTreeNode[] nodes =
copies.toArray(new DefaultMutableTreeNode[copies.size()]);
nodesToRemove =
toRemove.toArray(new DefaultMutableTreeNode[toRemove.size()]);
return new NodesTransferable(nodes);
}
return null;
}
/** Defensive copy used in createTransferable. */
private DefaultMutableTreeNode copy(TreeNode node) {
return new DefaultMutableTreeNode(node);
}
//TransferHandler
#Override public boolean importData(TransferHandler.TransferSupport support) {
if (!canImport(support)) {
return false;
}
// Extract transfer data.
DefaultMutableTreeNode[] nodes = null;
try {
Transferable t = support.getTransferable();
nodes = (DefaultMutableTreeNode[]) t.getTransferData(nodesFlavor);
} catch (UnsupportedFlavorException ufe) {
System.out.println("UnsupportedFlavor: " + ufe.getMessage());
} catch (java.io.IOException ioe) {
System.out.println("I/O error: " + ioe.getMessage());
}
// Get drop location info.
JTree.DropLocation dl
= (JTree.DropLocation) support.getDropLocation();
int childIndex = dl.getChildIndex();
TreePath dest = dl.getPath();
DefaultMutableTreeNode parent
= (DefaultMutableTreeNode) dest.getLastPathComponent();
JTree tree = (JTree) support.getComponent();
DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
// Configure for drop mode.
int index = childIndex; // DropMode.INSERT
if (childIndex == -1) { // DropMode.ON
index = parent.getChildCount();
}
// Add data to model.
for (int i = 0; i < nodes.length; i++) {
model.insertNodeInto(nodes[i], parent, index++);
}
return true;
}
//TransferHandler
public boolean importData(JComponent comp, Transferable t) {
// Extract transfer data.
DefaultMutableTreeNode[] nodes;
try {
nodes = (DefaultMutableTreeNode[]) t.getTransferData(nodesFlavor);
if (comp instanceof JTree) {
JTree tree = (JTree)comp;
DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
JTree.DropLocation dl = tree.getDropLocation();
int childIndex = dl.getChildIndex();
TreePath dest = dl.getPath();
DefaultMutableTreeNode parent =
(DefaultMutableTreeNode)dest.getLastPathComponent();
// Configure for drop mode.
int index = childIndex; // DropMode.INSERT
if (childIndex == -1) { // DropMode.ON
index = parent.getChildCount();
}
// Add data to model.
for (DefaultMutableTreeNode node : nodes) {
model.insertNodeInto(node, parent, index++);
}
return true;
}
} catch (UnsupportedFlavorException ufe) {
System.out.println("UnsupportedFlavor: " + ufe.getMessage());
} catch (java.io.IOException ioe) {
System.out.println("I/O error: " + ioe.getMessage());
}
return false;
}
public class NodesTransferable implements Transferable {
DefaultMutableTreeNode[] nodes;
public NodesTransferable(DefaultMutableTreeNode[] nodes) {
this.nodes = nodes;
}
//Transferable
#Override public Object getTransferData(DataFlavor flavor) {
if(!isDataFlavorSupported(flavor)) {
return false;
}
return nodes;
}
//Transferable
#Override public DataFlavor[] getTransferDataFlavors() {
return flavors;
}
//Transferable
#Override public boolean isDataFlavorSupported(DataFlavor flavor) {
return flavor.equals(nodesFlavor);
}
}
}
TransferHandler.TransferSupport#isDrop() method returns false in the case of via Clipboard, so switching it here seems to work fine.
// Get drop location info.
int childIndex;
TreePath dest;
if (support.isDrop()) {
JTree.DropLocation dl = (JTree.DropLocation) support.getDropLocation();
childIndex = dl.getChildIndex();
dest = dl.getPath();
} else {
childIndex = -1;
JTree tree = (JTree) support.getComponent();
dest = tree.getSelectionPath();
}
JTreeTransferHandler2.java
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.event.ActionEvent;
import java.util.*;
import java.util.List;
import javax.swing.*;
import javax.swing.tree.*;
public class JTreeTransferHandler2 extends JFrame {
public JTreeTransferHandler2() {
initiate();
}
private void initiate() {
setTitle("Copy from JTree");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400,400);
setLocation(200,200);
setVisible(true);
DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root");
DefaultMutableTreeNode vegetableNode = new DefaultMutableTreeNode("Vegetables");
vegetableNode.add(new DefaultMutableTreeNode("Capsicum"));
vegetableNode.add(new DefaultMutableTreeNode("Carrot"));
DefaultMutableTreeNode fruitNode = new DefaultMutableTreeNode("Fruits");
fruitNode.add(new DefaultMutableTreeNode("Mango"));
fruitNode.add(new DefaultMutableTreeNode("Apple"));
root.add(vegetableNode);
root.add(fruitNode);
JTree tree = new JTree(root);
TreeTransferHandler treeTransferHandler = new TreeTransferHandler();
tree.setTransferHandler(treeTransferHandler);
Clipboard clipboard = this.getToolkit().getSystemClipboard();
JButton copy = new JButton("Copy");
copy.addActionListener((ActionEvent e) -> {
TransferHandler handler = tree.getTransferHandler();
handler.exportToClipboard(tree, clipboard, TransferHandler.COPY);
});
JButton paste = new JButton("Paste");
paste.addActionListener((ActionEvent e) -> {
Transferable clipData = clipboard.getContents(null);
if (clipData != null) {
if (clipData.isDataFlavorSupported(treeTransferHandler.nodesFlavor)) {
TransferHandler handler = tree.getTransferHandler();
handler.importData(tree, clipData);
}
}
});
JPanel buttonsPanel = new JPanel();
buttonsPanel.add(copy);
buttonsPanel.add(paste);
add(new JScrollPane(tree), BorderLayout.CENTER);
add(buttonsPanel, BorderLayout.SOUTH);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JTreeTransferHandler2 jTreeTransferHandler = new JTreeTransferHandler2();
});
}
}
class TreeTransferHandler extends TransferHandler {
DataFlavor nodesFlavor;
DataFlavor[] flavors = new DataFlavor[1];
DefaultMutableTreeNode[] nodesToRemove;
public TreeTransferHandler() {
try {
String mimeType = DataFlavor.javaJVMLocalObjectMimeType + ";class=\"" +
DefaultMutableTreeNode[].class.getName() + "\"";
nodesFlavor = new DataFlavor(mimeType);
flavors[0] = nodesFlavor;
} catch(ClassNotFoundException e) {
System.out.println("ClassNotFound: " + e.getMessage());
}
}
//TransferHandler
#Override public int getSourceActions(JComponent c) {
return TransferHandler.COPY;
}
//TransferHandler
#Override public boolean canImport(JComponent comp, DataFlavor flavor[]) {
for (int i = 0, n = flavor.length; i < n; i++) {
for (int j = 0, m = flavors.length; j < m; j++) {
if (flavor[i].equals(flavors[j])) {
return true;
}
}
}
return false;
}
//TransferHandler
#Override protected Transferable createTransferable(JComponent c) {
JTree tree = (JTree) c;
TreePath[] paths = tree.getSelectionPaths();
if (paths != null) {
List<DefaultMutableTreeNode> copies = new ArrayList<>();
List<DefaultMutableTreeNode> toRemove = new ArrayList<>();
DefaultMutableTreeNode node =
(DefaultMutableTreeNode) paths[0].getLastPathComponent();
DefaultMutableTreeNode copy = copy(node);
copies.add(copy);
toRemove.add(node);
for (int i = 1; i < paths.length; i++) {
DefaultMutableTreeNode next =
(DefaultMutableTreeNode) paths[i].getLastPathComponent();
// Do not allow higher level nodes to be added to list.
if (next.getLevel() < node.getLevel()) {
break;
} else if (next.getLevel() > node.getLevel()) { // child node
copy.add(copy(next));
// node already contains child
} else { // sibling
copies.add(copy(next));
toRemove.add(next);
}
}
DefaultMutableTreeNode[] nodes =
copies.toArray(new DefaultMutableTreeNode[copies.size()]);
nodesToRemove =
toRemove.toArray(new DefaultMutableTreeNode[toRemove.size()]);
return new NodesTransferable(nodes);
}
return null;
}
/** Defensive copy used in createTransferable. */
private DefaultMutableTreeNode copy(TreeNode node) {
return new DefaultMutableTreeNode(node);
}
//TransferHandler
#Override public boolean importData(TransferHandler.TransferSupport support) {
if (!canImport(support)) {
return false;
}
// Extract transfer data.
DefaultMutableTreeNode[] nodes = null;
try {
Transferable t = support.getTransferable();
nodes = (DefaultMutableTreeNode[]) t.getTransferData(nodesFlavor);
} catch (UnsupportedFlavorException ufe) {
System.out.println("UnsupportedFlavor: " + ufe.getMessage());
} catch (java.io.IOException ioe) {
System.out.println("I/O error: " + ioe.getMessage());
}
// Get drop location info.
int childIndex;
TreePath dest;
if (support.isDrop()) {
JTree.DropLocation dl = (JTree.DropLocation) support.getDropLocation();
childIndex = dl.getChildIndex();
dest = dl.getPath();
} else {
childIndex = -1;
JTree tree = (JTree) support.getComponent();
dest = tree.getSelectionPath();
}
DefaultMutableTreeNode parent
= (DefaultMutableTreeNode) dest.getLastPathComponent();
JTree tree = (JTree) support.getComponent();
DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
// Configure for drop mode.
int index = childIndex; // DropMode.INSERT
if (childIndex == -1) { // DropMode.ON
index = parent.getChildCount();
}
// Add data to model.
for (int i = 0; i < nodes.length; i++) {
// ArrayIndexOutOfBoundsException
model.insertNodeInto(nodes[i], parent, index++);
}
return true;
}
//TransferHandler
#Override public boolean importData(JComponent comp, Transferable t) {
return importData(new TransferHandler.TransferSupport(comp, t));
}
public class NodesTransferable implements Transferable {
DefaultMutableTreeNode[] nodes;
public NodesTransferable(DefaultMutableTreeNode[] nodes) {
this.nodes = nodes;
}
//Transferable
#Override public Object getTransferData(DataFlavor flavor) {
if(!isDataFlavorSupported(flavor)) {
return false;
}
return nodes;
}
//Transferable
#Override public DataFlavor[] getTransferDataFlavors() {
return flavors;
}
//Transferable
#Override public boolean isDataFlavorSupported(DataFlavor flavor) {
return flavor.equals(nodesFlavor);
}
}
}
I am trying to show only directories in JTree but my below code is showing is directories and files both .can anyone please help me to show only directories.
//Class1
public class FileBrowser implements Runnable {
private DefaultMutableTreeNode root;
private DefaultTreeModel treeModel;
private JTree tree;
#Override
public void run() {
JFrame frame = new JFrame("File Browser");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
File fileRoot = new File("C:\\JDeveloper\\Testing");
root = new DefaultMutableTreeNode(new FileNodes(fileRoot));
treeModel = new DefaultTreeModel(root);
tree = new JTree(treeModel);
tree.setCellRenderer(new DefaultTreeCellRenderer() {
private Icon loadIcon = UIManager.getIcon("OptionPane.errorIcon");
private Icon saveIcon = UIManager.getIcon("OptionPane.informationIcon");
#Override
public Component getTreeCellRendererComponent(JTree tree,
Object value,
boolean bSelected,
boolean bExpanded,
boolean bLeaf,
int iRow,
boolean bHasFocus ) {
Component c = super.getTreeCellRendererComponent(tree, value,
bSelected, bExpanded, bLeaf, iRow, bHasFocus);
return c;
}
});
tree.setShowsRootHandles(true);
JScrollPane scrollPane = new JScrollPane(tree);
frame.add(scrollPane);
frame.setLocationByPlatform(true);
frame.setSize(640, 480);
frame.setVisible(true);
CreateChildNode ccn = new CreateChildNode(fileRoot, root);
new Thread(ccn).start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new FileBrowser());
}
}
//Class 2
class CreateChildNode implements Runnable {
private DefaultMutableTreeNode root;
private File fileRoot;
public CreateChildNode(File fileRoot, DefaultMutableTreeNode root) {
this.fileRoot = fileRoot;
this.root = root;
}
#Override
public void run() {
createChildren(fileRoot, root);
}
private void createChildren(File fileRoot,
DefaultMutableTreeNode root) {
File[] files = fileRoot.listFiles();
for (File child : files) {
System.out.println("Path :" +child.getName());
DefaultMutableTreeNode childNode =
new DefaultMutableTreeNode(new FileNodes(child));
System.out.println("Child Node :" +childNode);
System.out.println("File :" +child.getAbsoluteFile());
root.add(childNode);
if (child.isDirectory() ) {
createChildren(child, childNode);
}
}
}
}
class FileNodes {
private File file;
public FileNodes(File file) {
this.file = file;
}
public File getFile() {
return file;
}
#Override
public String toString() {
String name = file.getName();
if (name.equals("")) {
return file.getAbsolutePath();
} else {
return name;
}
}
}
Simply check for a directory before add to the tree
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import java.awt.*;
import java.io.File;
/**
* Created by keshan on 7/26/2016.
*/
public class FileBrowser implements Runnable {
private DefaultMutableTreeNode root;
private DefaultTreeModel treeModel;
private JTree tree;
#Override
public void run() {
JFrame frame = new JFrame("File Browser");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
File fileRoot = new File("C:");
root = new DefaultMutableTreeNode(new FileNodes(fileRoot));
treeModel = new DefaultTreeModel(root);
tree = new JTree(treeModel);
tree.setCellRenderer(new DefaultTreeCellRenderer() {
private Icon loadIcon = UIManager.getIcon("OptionPane.errorIcon");
private Icon saveIcon = UIManager.getIcon("OptionPane.informationIcon");
#Override
public Component getTreeCellRendererComponent( JTree tree,
Object value,
boolean bSelected,
boolean bExpanded,
boolean bLeaf,
int iRow,
boolean bHasFocus ) {
Component c = super.getTreeCellRendererComponent(tree, value,
bSelected, bExpanded, false, iRow, bHasFocus);
return c;
}
});
tree.setShowsRootHandles(true);
JScrollPane scrollPane = new JScrollPane(tree);
frame.add(scrollPane);
frame.setLocationByPlatform(true);
frame.setSize(640, 480);
frame.setVisible(true);
CreateChildNode ccn = new CreateChildNode(fileRoot, root);
new Thread(ccn).start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new FileBrowser());
}
}
class CreateChildNode implements Runnable {
private DefaultMutableTreeNode root;
private File fileRoot;
public CreateChildNode(File fileRoot, DefaultMutableTreeNode root) {
this.fileRoot = fileRoot;
this.root = root;
}
#Override
public void run() {
createChildren(fileRoot, root);
}
private void createChildren(File fileRoot, DefaultMutableTreeNode root)
{
File[] files = fileRoot.listFiles();
if ( files != null )
{
for( File child : files )
{
DefaultMutableTreeNode childNode = new DefaultMutableTreeNode( new FileNodes( child ) );
if( child.isDirectory() )
{
root.add( childNode );
createChildren( child, childNode );
}
}
}
}
}
class FileNodes {
private File file;
public FileNodes(File file) {
this.file = file;
}
public File getFile() {
return file;
}
#Override
public String toString() {
String name = file.getName();
if (name.equals("")) {
return file.getAbsolutePath();
} else {
return name;
}
}
}
You can do this in java as below
File file=new File("PATH_TO_FILE");
String directories[]=file.list(new FilenameFilter()
{
public boolean accept(File yourFile, String name) {
return new File(yourFile, name).isDirectory();
}
}
I have been using JTree to get the multiple root directories of the system, using the example FileTreeModel.java to achieve it. And also trying to get the selected leaf (path) but it throws cast error, please give me some directions on this, have posted the code so far have tried. Thanks.
import java.io.File;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.tree.*;
import java.io.File;
public class FileTreeDemo {
public static void main(String[] args) {
// Figure out where in the filesystem to start displaying
File root;
if (args.length > 0) {
root = new File(args[0]);
//System.out.println(args.length);
}
else root = new File(System.getProperty("user.home"));
//System.out.println(args.length);
// Create a TreeModel object to represent our tree of files
FileTreeModel model = new FileTreeModel(root);
// Create a JTree and tell it to display our model
JTree tree = new JTree();
tree.setModel(model);
tree.setRootVisible(true);
tree.setShowsRootHandles(true);
//tree.setShowsRootHandles(true);
// 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);
// Add a listener
tree.addTreeSelectionListener(new TreeSelectionListener() {
public void valueChanged(TreeSelectionEvent e) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode) e
.getPath().getLastPathComponent();
System.out.println("You selected " + node);
}
});
}
}
class FileTreeModel implements TreeModel {
protected File root;
public FileTreeModel(File root) { this.root = root; }
public Object getRoot() { return root; }
public boolean isLeaf(Object node) { return ((File)node).isFile(); }
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) {}
}
In your model you store File's instead of DefaultMutableTreeNode, because of you get ClassCastException here:
DefaultMutableTreeNode node = (DefaultMutableTreeNode)e.getPath().getLastPathComponent();
Change your listener like next:
tree.addTreeSelectionListener(new TreeSelectionListener() {
public void valueChanged(TreeSelectionEvent e) {
File node = (File) e.getPath().getLastPathComponent();
System.out.println("You selected " + node);
}
});
Here is the run down on my program
Lists all folders, subfolders, and files of X extension from a specified directory. You can view, edit, copy, etc the contents of the files. Each file has a .dat file associated with it that contains information such as keywords and last use date.
Right now I'm creating a filter. The way it should filter is take the inputted text and return any folders and files with the filter in its name, files which keywords contain and files which contents contain.
Easy enough, right?
My only problem is that it will do one of the following (based on location of File)
if folder matches
-> only lists to that folder, but not contents
if file matches
-> only lists file if its in JTree root
if file matches but is in a folder which doesnt match
-> doesnt display
I apologize if that is hard to understand. Below is functional code, copied and cleaned up from my real program. Uses apache commons 2.4
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.io.File;
import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.border.LineBorder;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeSelectionModel;
import org.apache.commons.io.FileUtils;
public class NGui {
JFrame frame;
private JTree tree;
private JTextField jtf;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager
.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
new NGui();
}
});
}
public NGui() {
initialize();
}
private void initialize() {
frame = new JFrame();
frame.getContentPane().setLayout(null);
frame.setSize(250, 400);
JScrollPane scrollPane = new JScrollPane();
scrollPane.setBounds(10, 50, 200, 300);
frame.getContentPane().add(scrollPane);
tree = new JTree(addNodes(new File(getWorkPath())));
tree.setRootVisible(true);
tree.setShowsRootHandles(true);
tree.setBorder(new LineBorder(new Color(0, 0, 0)));
tree.getSelectionModel().setSelectionMode(
TreeSelectionModel.SINGLE_TREE_SELECTION);
scrollPane.setViewportView(tree);
tree.getSelectionModel().addTreeSelectionListener(
new TreeSelectionListener() {
#Override
public void valueChanged(TreeSelectionEvent e) {
treeValueChanged(e);
}
});
tree.setCellRenderer(new FileTreeCellRenderer());
jtf = new JTextField();
jtf.setBorder(new LineBorder(new Color(0, 0, 0)));
jtf.setBounds(10, 10, 150, 25);
Object actionKey = jtf.getInputMap(JComponent.WHEN_FOCUSED).get(
KeyStroke.getKeyStroke("ENTER"));
jtf.getActionMap().put(actionKey, new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent ae) {
try {
filterResults(ae);
} catch (Exception e) {
e.printStackTrace();
}
}
});
frame.getContentPane().add(jtf);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private void treeValueChanged(TreeSelectionEvent e) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree
.getLastSelectedPathComponent();
log("Selected Node: " + node);
}
private void log(Object o) {
System.out.println(o);
}
private String getWorkPath() {
return ".";
}
public void filterResults(ActionEvent ae) throws Exception {
final String str = jtf.getText();
reloadTree("."); // refreshes from any previous searches
DefaultMutableTreeNode root = (DefaultMutableTreeNode) tree.getModel()
.getRoot();
reloadTree(root.toString(), str);
}
public DefaultMutableTreeNode addNodes(File dir, String filter)
throws Exception {
DefaultMutableTreeNode node = new DefaultMutableTreeNode(dir);
for (File file : dir.listFiles()) {
if (file.isDirectory()) {
if (file.getPath().contains(filter)) {
log("adding: " + file.toString());
node.add(addNodes(file));
}
} else {
// apache commons 2.4
String tmpContent = FileUtils.readFileToString(file);
if (file.getPath().contains(filter)
|| tmpContent.contains(filter)) {
log("adding: " + file.toString());
node.add(new DefaultMutableTreeNode(file));
}
}
}
return node;
}
public DefaultMutableTreeNode addNodes(File dir) {
DefaultMutableTreeNode node = new DefaultMutableTreeNode(dir);
for (File file : dir.listFiles()) {
if (file.isDirectory()) {
node.add(addNodes(file));
} else {
node.add(new DefaultMutableTreeNode(file));
}
}
return node;
}
public void reloadTree(final String path) {
DefaultMutableTreeNode dn = addNodes(new File(path));
tree.setModel(new DefaultTreeModel(dn));
}
public void reloadTree(final String path, final String filter)
throws Exception {
DefaultMutableTreeNode dn = addNodes(new File(path), filter);
tree.setModel(new DefaultTreeModel(dn));
}
public class FileTreeCellRenderer extends DefaultTreeCellRenderer {
private static final long serialVersionUID = 1L;
#Override
public Component getTreeCellRendererComponent(JTree tree, Object value,
boolean sel, boolean expanded, boolean leaf, int row,
boolean hasFocus) {
if (value instanceof DefaultMutableTreeNode) {
value = ((DefaultMutableTreeNode) value).getUserObject();
if (value instanceof File) {
value = ((File) value).getName();
}
}
return super.getTreeCellRendererComponent(tree, value, sel,
expanded, leaf, row, hasFocus);
}
}
}
The problem lies in the filtering algorithm.
You missed out to call the filter on the subcomponents again (instead of addNodes(file) you have to call addNodes(file, filter)).
Directory nodes where only added if they match, not if subcomponents match.
A quick hack to make your code working looks like this (replace the addNodes method):
public DefaultMutableTreeNode addNodes(File dir, String filter)
throws Exception {
DefaultMutableTreeNode node = new DefaultMutableTreeNode(dir);
//true iff any subcomponent matches
boolean matchFound = false;
for (File file : dir.listFiles()) {
if (file.isDirectory()) {
if (file.getName().contains(filter)) {
matchFound = true;
}
//always call addNodes on directories, because subcomponents may match
//null return value indicates no match (with Java 8 use Optional for this)
DefaultMutableTreeNode maybeNode = addNodes(file, filter);
if(maybeNode != null) {
matchFound = true;
node.add(maybeNode);
}
} else {
// apache commons 2.4
String tmpContent = FileUtils.readFileToString(file);
if (file.getName().contains(filter)
|| tmpContent.contains(filter)) {
matchFound = true;
log("adding file: " + file.toString());
node.add(new DefaultMutableTreeNode(file));
}
}
}
//only return node if node itself or subcomponent matches
if(matchFound || dir.getName().contains(filter)) {
return node;
}
//return null otherwise
return null;
}
I have a custom JTree and a custom JModel; I would for the JTree to "auto-expand" when I give it a new model. At the moment, it simply collapse all the nodes to the root.
Here is an example:
private class CustomTree extends JTree {
#Override
public boolean isExpanded(TreePath path) {
return ((Person) path.getLastPathComponent).hasChildren();
}
private class CustomTreeModel extends TreeModel {
// ... omitting various implementation details
#Override
public boolean isLeaf(Object object) {
return !((Person) object).hasChildren();
}
}
Model model = new Model();
Person bob = new Person();
Person alice = new Person();
bob.addChild(alice);
model.setRoot(bob);
JTree tree = new CustomTree(new CustomTreeModel(model));
At this point, the tree correctly displays:
- BOB
- ALICE
where Alice is a child of Bob (both in the data and in the visual tree)
However, if I call:
tree.setModel(new CustomTreeModel(model));
everything is collapsed:
+ BOB
Is there a way to "auto-expand" everything in the tree when setting a new model?
The following worked for me (called after setting the new model):
for (int i = 0; i < tree.getRowCount(); i++) {
tree.expandRow(i);
}
I had a similar problem.
Your solution (as posted https://stackoverflow.com/a/15211697/837530) seemed to work for me only for the top level tree nodes.
But I needed to expand all the a descendants node. So I solved it with the following recursive method:
private void expandAllNodes(JTree tree, int startingIndex, int rowCount){
for(int i=startingIndex;i<rowCount;++i){
tree.expandRow(i);
}
if(tree.getRowCount()!=rowCount){
expandAllNodes(tree, rowCount, tree.getRowCount());
}
}
which is invoked with
expandAllNodes(tree, 0, tree.getRowCount());
where, tree is a JTree.
Unless someone has a better solution.
There's also this non-recursive version.
private void expandAllNodes(JTree tree) {
int j = tree.getRowCount();
int i = 0;
while(i < j) {
tree.expandRow(i);
i += 1;
j = tree.getRowCount();
}
}
this worked for me..
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeNode;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.util.Enumeration;
public class JTreeNodeAutoExpandCollapse extends JFrame {
public JTreeNodeAutoExpandCollapse() throws HeadlessException {
initializeUI();
}
private void initializeUI() {
setSize(200, 200);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root");
DefaultMutableTreeNode chapter1 = new DefaultMutableTreeNode("Chapter 1");
DefaultMutableTreeNode sub1 = new DefaultMutableTreeNode("1.1");
DefaultMutableTreeNode sub2 = new DefaultMutableTreeNode("1.2");
DefaultMutableTreeNode sub3 = new DefaultMutableTreeNode("1.3");
DefaultMutableTreeNode sub31 = new DefaultMutableTreeNode("1.3.1");
DefaultMutableTreeNode sub32 = new DefaultMutableTreeNode("1.3.2");
root.add(chapter1);
chapter1.add(sub1);
chapter1.add(sub2);
chapter1.add(sub3);
sub3.add(sub31);
sub3.add(sub32);
final JTree tree = new JTree(root);
expandTree(tree, false);
JScrollPane pane = new JScrollPane(tree);
pane.setPreferredSize(new Dimension(200, 200));
JPanel buttonPanel = new JPanel(new BorderLayout());
JButton expandAll = new JButton("Expand All");
expandAll.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
expandTree(tree, true);
}
});
JButton collapseAll = new JButton("Collapse All");
collapseAll.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
expandTree(tree, false);
}
});
buttonPanel.add(expandAll, BorderLayout.WEST);
buttonPanel.add(collapseAll, BorderLayout.EAST);
getContentPane().setLayout(new BorderLayout());
getContentPane().add(pane, BorderLayout.CENTER);
getContentPane().add(buttonPanel, BorderLayout.SOUTH);
}
private void expandTree(JTree tree, boolean expand) {
TreeNode root = (TreeNode) tree.getModel().getRoot();
expandAll(tree, new TreePath(root), expand);
}
private void expandAll(JTree tree, TreePath path, boolean expand) {
TreeNode node = (TreeNode) path.getLastPathComponent();
if (node.getChildCount() >= 0) {
Enumeration enumeration = node.children();
while (enumeration.hasMoreElements()) {
TreeNode n = (TreeNode) enumeration.nextElement();
TreePath p = path.pathByAddingChild(n);
expandAll(tree, p, expand);
}
}
if (expand) {
tree.expandPath(path);
} else {
tree.collapsePath(path);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new JTreeNodeAutoExpandCollapse().setVisible(true);
}
});
}
}
public void expandTree(){
int row = 1;
while (row++ < tree.getRowCount()){
tree.expandRow(row);
}
public void collapseTree(){
int row = tree.getRowCount() - 1;
while (row-- > 0){
tree.collapseRow(row);
}
}