I am working on developing a GUI using Swing. The GUI is implemented in such a way that the when the user wants to load a set of text files, then the filechooser dialog should open and the user selects the directory in which all the files are present. Now, I want to list all the files in the selected directory into a JScrollPane using JTree. I am using this example to implement JTree in my code:
http://www.java2s.com/Code/Java/File-Input-Output/FileTreeDemo.htm
However, the JTree is not displayed in the JPanel after I select the directory. I have placed the JTree code in the actionPerformed() method. I am not sure if this is the right way.
Here is the code:
public void actionPerformed(ActionEvent e) {
//Handle open button action.
if (e.getSource() == OpenFileButton) {
int returnVal = fc.showOpenDialog(GUIMain.this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
file = fc.getSelectedFile();
System.out.println(file);
File[] filesInDirectory = file.listFiles();
SortFile sf = new SortFile();
// Calls sortByNumber method in class SortFile to list the files number wise
filesInDirectory = sf.sortByNumber(filesInDirectory);
FileTreeModel model = new FileTreeModel(file);
tree = new JTree();
tree.setModel(model);
spectralFilesScrollPane = new JScrollPane(tree);
// add(BorderLayout.CENTER, spectralFilesScrollPane);
spectralFilesScrollPane.setVerticalScrollBarPolicy(
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
spectralFilesScrollPane.setPreferredSize(new Dimension(250, 145));
spectralFilesScrollPane.setMinimumSize(new Dimension(10, 10));
spectralFilesScrollPane.setBorder(
BorderFactory.createCompoundBorder(
BorderFactory.createTitledBorder("Spectral Files"),
BorderFactory.createEmptyBorder(5, 5, 5, 5)));
content.add(spectralFilesScrollPane);
spectralFilesScrollPane.setVisible(true);
}
}
}
FileTreeModel.java class
import javax.swing.event.TreeModelListener;
import javax.swing.tree.TreeModel;
import javax.swing.*;
import javax.swing.tree.TreePath;
import java.io.File;
/**
* The methods in this class allow the JTree component to traverse
* the file system tree, and display the files and directories.
**/
class FileTreeModel implements TreeModel {
// We specify the root directory when we create the model.
protected File root;
public FileTreeModel(File root) {
System.out.println("I am in FileTree Model");
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;
System.out.println("printing child length:" + children.length);
return children.length;
}
// Fetch any numbered child of a node for the JTree.
// Our model returns File objects for all nodes in the tree. The
// JTree displays these by calling the File.toString() method.
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]);
}
// Figure out a child's position in its parent node.
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;
}
// This method is only invoked by the JTree for editable trees.
// This TreeModel does not allow editing, so we do not implement
// this method. The JTree editable property is false by default.
public void valueForPathChanged(TreePath path, Object newvalue) {}
// Since this is not an editable tree model, we never fire any events,
// so we don't actually have to keep track of interested listeners.
public void addTreeModelListener(TreeModelListener l) {}
public void removeTreeModelListener(TreeModelListener l) {}
}
After revalidating the content container, the GUI looks like this:
You haven't revalidated the containing content Container. At the end of your actionPerformed method, add the lines
//content.invalidate();
content.revalidate();
content.repaint();
Related
I'm having a lot of trouble dealing with TreeView, more specificcaly with the text shown per node.
Starting with an initializer for the Tree, where I expected a single node with the text, it might make the program more intuitive for the users:
private void defineEmpityTree(){
cbt.setModel(new DefaultTreeModel(
new DefaultMutableTreeNode("Relat\u00F3rios Individuais") {
{
}
}
));
}
and I add initialize the Tree:
cbt = new JCheckBoxTree();
defineEmpityTree();
scrollPane.setViewportView(cbt);
"Relatórios Individuais" aren't shown, Tree Ok, another bug
I ignored this problem and continued with the actual filling of the nodes, the user specifies his search and press "ok", thats when we get the Tree filled, 2nd image.
But then then another strange problem comes, if "ok" is pressed again, some texts go strange, 3rd image.
Heres the part of the cade where the nodes are created. For an array of files nodes are created for each type of report and each report lot, its not really important.
private void defineNewTree(ArrayList<File> files){
DefaultMutableTreeNode dmtRoot = new DefaultMutableTreeNode("Relat\u00F3rios Individuais");
DefaultMutableTreeNode dmtSubFolder = null;
DefaultMutableTreeNode dmtLotFolder = null;
int childsRoot = 0;
int childsSub = 0;
for(File f : files){
String subFolder = f.getName().substring(17,f.getName().length()-4);
String name = f.getName();
String lot = f.getName().substring(0, 3);
childsRoot = dmtRoot.getChildCount();
boolean subFoldExists = false;
boolean foldLotExists = false;
//creatingo folder reports:
for(int i = 0;i<childsRoot;i++){
if(dmtRoot.getChildAt(i).toString().equals(subFolder)){
dmtSubFolder = (DefaultMutableTreeNode) dmtRoot.getChildAt(i);
subFoldExists = true;
i=childsRoot;
}
}
if(!subFoldExists){
dmtSubFolder = new DefaultMutableTreeNode(subFolder);
dmtRoot.add(dmtSubFolder);
}
for(int j = 0;j<childsSub;j++){
if(dmtSubFolder.getChildAt(j).toString().equals(lot)){
dmtLotFolder = (DefaultMutableTreeNode) dmtSubFolder.getChildAt(j);
foldLotExists = true;
j=childsSub;
}
}
if(!foldLotExists){
dmtLotFolder = new DefaultMutableTreeNode("lote "+lot);
dmtSubFolder.add(dmtLotFolder);
}
dmtLotFolder.add(new DefaultMutableTreeNode(name));
}
DefaultTreeModel myTree = new DefaultTreeModel(dmtRoot);
cbt.setModel(myTree);
}
I think the real problem is that:
cbt.setModel(myTree);
Is that the correct way to define the Tree contents?
Edit.:
Button OK:
...
JButton btnOk = new JButton("OK");
btnOk.setBounds(161, 37, 49, 23);
btnOk.setActionCommand("ok");
btnOk.addActionListener(buttonListener);
panel.add(btnOk);
...
class ButtonListener implements ActionListener{
#Override
public void actionPerformed(ActionEvent a) {
switch(a.getActionCommand()){
case "ok":
search();
self.requestFocusInWindow();
break;
case "cancel":
dispose();
break;
case "print":
TreePath[] tp = cbt.getCheckedPaths();
for(TreePath t : tp){
System.out.println(t.getLastPathComponent().toString());
}
self.requestFocusInWindow();
break;
default:
break;
}
}
}
private void search(){
FileSeeker fs = new FileSeeker(textField.getText());
ArrayList<File> files = fs.getFiles();
defineNewTree(files);
}
Edit.:
CheckBoxCellRenderer:
private class CheckBoxCellRenderer extends JPanel implements TreeCellRenderer {
private static final long serialVersionUID = -7341833835878991719L;
JCheckBox checkBox;
public CheckBoxCellRenderer() {
super();
this.setLayout(new BorderLayout());
checkBox = new JCheckBox();
add(checkBox, BorderLayout.CENTER);
setOpaque(false);
}
#Override
public Component getTreeCellRendererComponent(JTree tree, Object value,
boolean selected, boolean expanded, boolean leaf, int row,
boolean hasFocus) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode)value;
Object obj = node.getUserObject();
TreePath tp = new TreePath(node.getPath());
CheckedNode cn = nodesCheckingState.get(tp);
if (cn == null) {
return this;
}
checkBox.setSelected(cn.isSelected);
checkBox.setText(obj.toString());
checkBox.setOpaque(cn.isSelected && cn.hasChildren && ! cn.allChildrenSelected);
return this;
}
}
So, for the first problem the solution is:
private void defineEmpityTree(){
DefaultMutableTreeNode dmtn = new DefaultMutableTreeNode("Relat\u00F3rios Individuais");
cbt.setModel(new DefaultTreeModel(dmtn));
((DefaultTreeModel) cbt.getModel()).nodeChanged(dmtn);
}
I simply had to notify that the node had changed.
For the truncation problem,
cbt.setLargeModel(true);
did the trick.
I have recently been working on a Java Swing project and today I get stuck when modifying childrens of a DefaultMutableTreeNode.
The following SSCCE illustrates the problem:
import java.awt.event.*;
import javax.swing.*;
import javax.swing.tree.*;
public class Test
{
private static boolean executed = false;
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//
final DefaultMutableTreeNode root = new DefaultMutableTreeNode("root");
final JTree tree = new JTree(root);
tree.addMouseListener(new MouseAdapter()
{
#Override
public void mousePressed(MouseEvent ev)
{
if (ev.getClickCount() == 2)
{
root.removeAllChildren();
for (String s: get())
{
root.add(new DefaultMutableTreeNode(s));
System.out.println(s + " added");
}
System.out.println();
tree.expandPath(tree.getSelectionPath());
}
}
});
frame.add(tree);
frame.setSize(200,200);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
static String[] get()
{
if (!executed)
{
executed = true;
return new String[]{"a","b","c"};
}
else return new String[]{"a","b","c","d"};
}
}
As you see, the first time the get() method is invoked it returns a 3-element array, and a 4-element one afterwards. When I double-click (actually press) the root node for the first time there should be three children nodes (a, b and c), and the program behaves as expected. When I double-click the root node again I suppose it would have four children nodes. However it doesn't. When you double-click for the second time there are still only three, not four children nodes.
Did I make a mistake? Thanks for help in advance.
you should notify the model about changes use reload() method
add this lines before expand path like bellow
DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
model.reload(root); // notify changes to model
tree.expandPath(tree.getSelectionPath());
I want to create a very very simple file manager with JTree, but I only saw a very hard code and I want to create this script very clean and simple.
Can you help me? How do I List the directories of my computer in JTree?
I wrote the simplest example of a file browser I could think of. It lists all of the directories and files on the C: drive on a Windows computer.
Here's the result.
And here's the code. I put everything together in one class to make it easier to paste here. You should separate the classes.
package com.ggl.testing;
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;
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 FileNode(fileRoot));
treeModel = new DefaultTreeModel(root);
tree = new JTree(treeModel);
tree.setShowsRootHandles(true);
JScrollPane scrollPane = new JScrollPane(tree);
frame.add(scrollPane);
frame.setLocationByPlatform(true);
frame.setSize(640, 480);
frame.setVisible(true);
CreateChildNodes ccn =
new CreateChildNodes(fileRoot, root);
new Thread(ccn).start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new FileBrowser());
}
public class CreateChildNodes implements Runnable {
private DefaultMutableTreeNode root;
private File fileRoot;
public CreateChildNodes(File fileRoot,
DefaultMutableTreeNode root) {
this.fileRoot = fileRoot;
this.root = root;
}
#Override
public void run() {
createChildren(fileRoot, root);
}
private void createChildren(File fileRoot,
DefaultMutableTreeNode node) {
File[] files = fileRoot.listFiles();
if (files == null) return;
for (File file : files) {
DefaultMutableTreeNode childNode =
new DefaultMutableTreeNode(new FileNode(file));
node.add(childNode);
if (file.isDirectory()) {
createChildren(file, childNode);
}
}
}
}
public class FileNode {
private File file;
public FileNode(File file) {
this.file = file;
}
#Override
public String toString() {
String name = file.getName();
if (name.equals("")) {
return file.getAbsolutePath();
} else {
return name;
}
}
}
}
This is how I solved the problem when i encountered it for my project which involved a jtree to show results of my scan.
scanner function is used to initialise the parameters and call the displayDirectoryContents function
Here are some drawbacks of the method i used
It shows empty folders as leaf nodes instead of showing them as a
leaf with no children
The model should be manually cleared by right clicking on the properties and clearing the model
Function used
public void displayDirectoryContents(File dir, DefaultMutableTreeNode root2)
throws InterruptedException {
DefaultMutableTreeNode newdir = new DefaultMutableTreeNode();
// creates array of file type for all the files found
File[] files = dir.listFiles();
for (File file : files) {
if (file == null) {
System.out.println("NUll directory found ");
continue;
}
if (file.isDirectory()) {
// file is a directory that is a folder has been dound
if (file.listFiles() == null) {
// skips null files
continue;
}
// gets the current model of the jtree
DefaultTreeModel model = (DefaultTreeModel) result.getModel();
// gets the root
DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot();
// generates a node newdir using filename
newdir = new DefaultMutableTreeNode(file.getName());
// adds a node to the root of the jtree
root2.add(newdir);
// refresh the model to show the changes
model.reload();
// recursively calls the function again to explore the contents
// folder
displayDirectoryContents(file, newdir);
} else {
// Else part File is not a directory
// gets the current model of the tree
DefaultTreeModel model = (DefaultTreeModel) result.getModel();
// selected node is the position where the new node will be
// inserted
DefaultMutableTreeNode selectednode = root2;
DefaultMutableTreeNode newfile = new DefaultMutableTreeNode(file.getName());
// inserts a node newfile under selected node which is the root
model.insertNodeInto(newfile, selectednode, selectednode.getChildCount());
// refresh the model to show the changes
model.reload();
}
}
}
Scanner Function to initialise the above function
public void scanner() throws InterruptedException {
// creates a file with the location filename
String location = "C:\\Users\\Ashish Padalkar\\Documents";
File currentDir = new File(location);
// result is the variable name for jtree
DefaultTreeModel model = (DefaultTreeModel) result.getModel();
// gets the root of the current model used only once at the starting
DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot();
// function caled
displayDirectoryContents(currentDir, root);
}
Im Trying to develop a small application that uses a gui to move files from anywhere on the system. I have the code to move the files and they do indeed move when selected and buttons pressed but I dont know how to refresh the filesystem viewer to reflect the change. The code I have to set up the system viewer is below:
public class FileMover {
//Start of Global Variables
private JTree tree;
private DefaultTreeModel treeModel;
private FileSystemView fileSystemView;
protected File currentFile;
protected LinkedList fileLocations;
protected JTree movedTree;
protected JPanel areaLeft;
protected JPanel areaRight;
protected JPanel areaMiddle;
protected final JFrame openFrame;
//end of global variables.
//Constructor for FileMover
public FileMover()
{
openFrame = new JFrame("File Mover");
createFileMover();
}
public void createFileMover(){
Container contentPane = this.openFrame.getContentPane();
fileLocations = new LinkedList();
contentPane.setLayout(new BorderLayout());
areaLeft = new JPanel();
areaRight = new JPanel();
areaMiddle = new JPanel();
contentPane.add(areaLeft, BorderLayout.WEST);
contentPane.add(areaRight, BorderLayout.EAST);
contentPane.add(areaMiddle, BorderLayout.CENTER);
areaLeft.add(createSystemView());
movedTree = new JTree(fileLocations.toArray());
JScrollPane movedPane = new JScrollPane(movedTree);
JButton moveRightButton = new JButton("->");
JButton moveLeftButton = new JButton("<-");
JButton refresh = new JButton("Refresh");
areaMiddle.setLayout(new GridLayout(1,2));
areaMiddle.add(moveRightButton);
areaMiddle.add(refresh);
areaMiddle.add(moveLeftButton);
//actualy move the file
moveRightButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
System.out.println("Moving file: "+ currentFile.getName());
fileLocations.add(currentFile);
try {
//move the file to the correct location.
moveFile(currentFile);
} catch (IOException ex) {
Logger.getLogger(FileMover.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println(fileLocations.getFirst().toString());
}
});
//refresh the gui
refresh.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
refresh();
}
});
//finish setting up the frame
openFrame.setSize(1280, 768);
openFrame.setLocationRelativeTo(null);
openFrame.setDefaultCloseOperation(3);
openFrame.setResizable(false);
openFrame.pack();
openFrame.setVisible(true);
}
/** Add the files that are contained within the directory of this node.
*/
private void showChildren(final DefaultMutableTreeNode node) {
tree.setEnabled(false);
SwingWorker<Void, File> worker = new SwingWorker<Void, File>() {
#Override
public Void doInBackground() {
File file = (File) node.getUserObject();
if (file.isDirectory()) {
File[] files = fileSystemView.getFiles(file, true); //!!
if (node.isLeaf()) {
for (File child : files) {
publish(child);
}
}
}
return null;
}
#Override
protected void process(List<File> chunks) {
for (File child : chunks) {
node.add(new DefaultMutableTreeNode(child));
}
}
#Override
protected void done() {
tree.setEnabled(true);
}
};
worker.execute();
}
/** Update the File details view with the details of this File. */
private void setFileDetails(File file) {
System.out.println("Path: "+ file.getPath());
System.out.println("Name: "+ fileSystemView.getSystemDisplayName(file));
}
private void refresh(){
//refresh the tree here
}
private JScrollPane createSystemView(){
//file syatem hierarchy
fileSystemView = FileSystemView.getFileSystemView();
// the File tree
DefaultMutableTreeNode root = new DefaultMutableTreeNode();
treeModel = new DefaultTreeModel(root);
TreeSelectionListener treeSelectionListener = new TreeSelectionListener() {
#Override
public void valueChanged(TreeSelectionEvent tse){
DefaultMutableTreeNode node =
(DefaultMutableTreeNode)tse.getPath().getLastPathComponent();
showChildren(node);
setFileDetails((File)node.getUserObject());
currentFile = (File)node.getUserObject();
}
};
// show the file system roots.
File[] roots = fileSystemView.getRoots();
for (File fileSystemRoot : roots) {
DefaultMutableTreeNode node = new DefaultMutableTreeNode(fileSystemRoot);
root.add( node );
File[] files = fileSystemView.getFiles(fileSystemRoot, true);
for (File file : files) {
if (file.isDirectory()) {
node.add(new DefaultMutableTreeNode(file));
}
}
}
tree = new JTree(treeModel);
tree.setRootVisible(false);
tree.addTreeSelectionListener(treeSelectionListener);
tree.setCellRenderer(new FileTreeCellRenderer());
tree.expandRow(0);
JScrollPane treeScroll = new JScrollPane(tree);
tree.setVisibleRowCount(15);
Dimension preferredSize = treeScroll.getPreferredSize();
Dimension widePreferred = new Dimension(
200,
(int)preferredSize.getHeight());
treeScroll.setPreferredSize( widePreferred );
return treeScroll;
}
The move left button and the area right are not finished but what I need is when I select a node in the tree and click the right arrow button the file/folder the node reflects is moved internally by my moveFile code and that works. but that change is not reflected in the tree so how can show this change in the tree i.e refresh the tree to show the current state of the filesystem?
I've tried treeModel.reload(); but that doesnt seem to work and throws a null pointer exception.
I've tried :
areaLeft.removeAll();
areaLeft.add(createSystemView());
thinking that it may refresh it by recreating the system view but that doesnt seem to do anything.
Help here would be most appreciated!
Edit: Below is the requested code for the file tree renderer:
/** A TreeCellRenderer for a File. */
class FileTreeCellRenderer extends DefaultTreeCellRenderer {
private static final long serialVersionUID = -7799441088157759804L;
private FileSystemView fileSystemView;
private JLabel label;
FileTreeCellRenderer() {
label = new JLabel();
label.setOpaque(true);
fileSystemView = FileSystemView.getFileSystemView();
}
#Override
public Component getTreeCellRendererComponent(
JTree tree,
Object value,
boolean selected,
boolean expanded,
boolean leaf,
int row,
boolean hasFocus) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode)value;
File file = (File)node.getUserObject();
label.setIcon(fileSystemView.getSystemIcon(file));
label.setText(fileSystemView.getSystemDisplayName(file));
label.setToolTipText(file.getPath());
if (selected) {
label.setBackground(backgroundSelectionColor);
label.setForeground(textSelectionColor);
} else {
label.setBackground(backgroundNonSelectionColor);
label.setForeground(textNonSelectionColor);
}
return label;
}
}
Since from your code it looks that you know what you're doing, I'll just show the elementary example which will only work for the first time you press the refresh button:
private DefaultMutableTreeNode someNode;
private void refresh(){
System.out.println(someNode);
treeModel.removeNodeFromParent(someNode);
}
and rewrite the part of createSystemView() like this:
int cnt = 0;
for (File file : files) {
if (file.isDirectory()) {
if ((cnt++) == 5) { //1
System.out.println(file.getPath());
node.add(someNode = new DefaultMutableTreeNode(file));
}
else {
node.add(new DefaultMutableTreeNode(file));
}
}
}
This will only work if you have at least six (comment 1) directories on your root. Run the file, count the directories from root - when you press the refresh button it'll remove the sixth directory. If you press the button again it will try to remove the already removed node so you'll get an IllegalArgumentException.
You need to call removeNodeFromParent on the treeModel:
Message this to remove node from its parent. This will message nodesWereRemoved to create the appropriate event. This is the preferred way to remove a node as it handles the event creation for you.
See this example also.
If you want to refresh the entire view you should recreate the model in the refersh function as you do in initialization, or just iterate the model and update as neccessary - but I'd suggest a breadth first traversal of the model in that case.
EDIT:
"so after every move refresh will show the FS again with the files where they should now be". Let's start with reinitializing the model, by that I solely mean the treeModel instance of DefaultTreeModel class.
So, in the refresh() method you create a new treeModel instance, and fill it with DefaultMutableTreeNode instances like you did in createSystemView() method:
DefaultMutableTreeNode root = new DefaultMutableTreeNode();
treeModel = new DefaultTreeModel(root);
File[] roots = fileSystemView.getRoots();
for (File fileSystemRoot : roots) {
DefaultMutableTreeNode node = new DefaultMutableTreeNode(fileSystemRoot);
root.add( node );
File[] files = fileSystemView.getFiles(fileSystemRoot, true);
for (File file : files) {
if (file.isDirectory()) {
node.add(new DefaultMutableTreeNode(file));
}
}
}
We have prepared the model, now we need to set it to the tree, I believe that a mere:
tree.setModel(treeModel);
should suffice, notice that you do not need to add the listener, because the setModel method reattaches the listeners from old model to the new model and also notifies the JTree view to redraw itself accordingly - I checked the source. If it won't redraw (I doubt it, but I haven't tested this) force it in the next line like this:
treeModel.reload();
APIdoc for reload() method here.
If however you want to update the model in the refresh function, which I believe would be more natural operation for an action called "refresh", you'll need to obtain the new first level directories and then traverse the tree like this (since we're traversing all the root's children, it would be the mentioned breadth-first traversal):
int firstLevelCount = treeModel.getChildCount(root);
DefaultMutableTreeNode child;
for (int i=0; i < firstLevelCount; i++) {
child = treeModel.getChild(root, index);
// update logic part 1
}
// update logic part 2
treeModel.reload();
You'll need the DefaultMutableTreeNode.getUserObject() method which will return a file that that tree node represents.
Obviously, you ll want to remove all the nodes from the model that are not in the the new files array, and for all the files that don't have their correspondent node in the model, you'll want to add them to the model.
I would advise not to use the files array but list (so that you could benefit from the List.contains() method) e.g.
List<File> files = new ArrayList<File>(Arrays.asList(FileSystemView.getFileSystemView().getRoots()));
Also, rewrite a part of your renderer like this:
if (file != null) {
label.setIcon(fileSystemView.getSystemIcon(file));
label.setText(fileSystemView.getSystemDisplayName(file));
label.setToolTipText(file.getPath());
}
because the root node in your view doesn't have associated file so you'll most probably get an NPE at some time updating the model.
In the second variant I described, you might get tempted to remove the root child node from inside the loop (at the update logic 1 part) - if you do that you'll most probably get an ConcurrentModificationException. The solution is to make another
List<DefaultMutableTreeNode> toBeRemoved = new ArrayList<DefaultMutableTreeNode>();
and at //update logic part 1 place (insde the loop) instead of removing the nodes from the model, you put it in that list. When you're done iterating the loop, you simply iterate over that list and remove them from the model at //update logic part 2 place e.g.
for (DefaultMutableTreeNode node : toBeRemoved) {
treeModel.removeNodeFromParent(node);
}
As mentioned, this will automatically trigger the view (JTree) redraw, so see what best fits your need.
EDIT^2:
Regarding the second variant of your refresh method, you already have the
private DefaultTreeModel treeModel;
as a global variable, you obtain the root of the tree like this (getRoot())
DefaultMutableTreeNode root = (DefaultMutableTreeNode)treeModel.getRoot();
and as you already did, you obtain the current state of the filesystem like this:
FileSystemView.getFileSystemView().getRoots();
these are all the variables you need to write the refresh() method as described.
Regarding the move (the buttons with arrows (<- , ->)) operation, from inside your treeSelectionListener make this variable global:
DefaultMutableTreeNode node = (DefaultMutableTreeNode)tse.getPath().getLastPathComponent();
With this variable (let's call it selectedNode), you can make use of the DefaultTreeModel methods:
removeNodeFromParent(MutableTreeNode node)
insertNodeInto(MutableTreeNode newChild,MutableTreeNode parent,int index)
Note that both methods will trigger JTree redraw. This should be sufficient to implement the operations you described. Also, you could rewrite the moveButton actionListener method like this:
moveRightButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
if (selectedNode != null) {
//all the move-code-refresh-tre-view-here
selectedNode = null;
}
}
});
the selectedNode will only be set by treeSelectionListener, so in this manner you are sure that the the file move operation will only take place if a file is actually selected in the tree view.
I'm creating this app that creates tabs and JTrees on button click events. The problem is when I try to add ne node to a JTree it doesn't refresh the JTree ( or it doesn't add the node to it ... I don't really know).
This is the functions that creates the tabs and trees:
jTabbedPane1.add(st,jSplitpane10);
int count = jTabbedPane1.getTabCount();
jTabbedPane1.setSelectedIndex(count-1);
DefaultMutableTreeNode root = new DefaultMutableTreeNode("All Notebooks");
DefaultMutableTreeNode notebook1 = new DefaultMutableTreeNode("Notebook 1");
root.add(notebook1);
// Create tree
JTree tree = new JTree(root);
//Create Scroll Pane for the tree
JScrollPane sp = new JScrollPane(tree);
Global.trees.add(tree);
And this is the code that is supposed to add new node "Green" to a tree in the selected tab:
int i = jTabbedPane1.getSelectedIndex();
DefaultTreeModel model = (DefaultTreeModel)Global.trees.get(i).getModel();
// Find node to which new node is to be added
int startRow = 0;
String prefix = "J";
TreePath path = Global.trees.get(i).getNextMatch(prefix, startRow, Position.Bias.Forward);
MutableTreeNode node = (MutableTreeNode)path.getLastPathComponent();
// Create new node
MutableTreeNode newNode = new DefaultMutableTreeNode("green");
// Insert new node as last child of node
model.insertNodeInto(newNode, node, node.getChildCount());
model.reload(newNode);
Here's also the declaration of the global list of JTrees:
public class Global {
public java.util.List<JTree> trees = new ArrayList<JTree>();
}Global Global;
Any ideas why new nodes aren't showing in the trees???
JTree and JTable are the most complex Swing components.
I think is reloaded, but not expanded.
The JTree root node has many settings: how handler or not show root node or not and so on.
I am using a debug console listing where I dump the model data as text ( override the toString() in nodes too) and I can see easily,, what is there, but if you have just a few nodes not needed, it is enough with the Netbeans's debugger.
Also try to expand all rows in tree to have it visible.
Your code is good:
// Create new node
MutableTreeNode newNode = new DefaultMutableTreeNode("green");
// Insert new node as last child of node
model.insertNodeInto(newNode, node, node.getChildCount());
model.reload(newNode);
but probably it is not visible, you need to expand, how to do it, that is another question
Here is some code to add JTree programmatically:
Source:http://sickprogrammersarea.blogspot.in/2014/03/add-jtree-programmatically-in-java-swing.html
import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.tree.*;
public class MyTree extends JApplet
{
JTree t;
JLabel l1;
String lang[]={"C","C++","JAVA","PYTHON","AJAX","PHP"};
public void init()
{
try
{
SwingUtilities.invokeAndWait(new Runnable() {
public void run()
{
makeGUI();
}
});
} catch(Exception e){
System.out.println("Sorry some error occured "+e);
}
}
private void makeGUI()
{
DefaultMutableTreeNode top=new DefaultMutableTreeNode("Language");
DefaultMutableTreeNode a=new DefaultMutableTreeNode("Programming");
top.add(a);
DefaultMutableTreeNode a1=new DefaultMutableTreeNode("C");
a.add(a1);
DefaultMutableTreeNode a2=new DefaultMutableTreeNode("Java");
a.add(a2);
DefaultMutableTreeNode b=new DefaultMutableTreeNode("Web Based");
top.add(b);
DefaultMutableTreeNode b1=new DefaultMutableTreeNode("PHP");
b.add(b1);
DefaultMutableTreeNode b2=new DefaultMutableTreeNode("JSP");
b.add(b2);
t=new JTree(top);
JScrollPane scr=new JScrollPane(t);
add(scr);
setLayout(new FlowLayout());
l1=new JLabel("Choose a language");
add(l1,BorderLayout.SOUTH);
t.addTreeSelectionListener(new TreeSelectionListener () {
public void valueChanged(TreeSelectionEvent ae) {
l1.setText(ae.getPath()+" is selected");
}
});
}
}
I produced a small example application to test your issue. I found that the node was being added correctly, but not expanding. Also, the call to model.reload seems unnecessary.
I added a call to expandPath on the tree to cause the display to show the new node. You may need to double check this doesn't expand too much of the tree:
public class Example extends JFrame {
private JTree tree;
public Example() {
DefaultMutableTreeNode root = new DefaultMutableTreeNode("All Notebooks");
DefaultMutableTreeNode notebook1 = new DefaultMutableTreeNode("Notebook 1");
root.add(notebook1);
tree = new JTree(root);
JScrollPane sp = new JScrollPane(tree);
setLayout(new BorderLayout());
add(sp, BorderLayout.CENTER);
add(new JButton("Go") {
{
addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Example.this.addNode();
}
});
}}, BorderLayout.SOUTH);
setDefaultCloseOperation(EXIT_ON_CLOSE);
pack();
}
private void addNode() {
DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
// Find node to which new node is to be added
int startRow = 0;
String prefix = "N";
TreePath path = tree.getNextMatch(prefix, startRow,
Position.Bias.Forward);
MutableTreeNode node = (MutableTreeNode) path.getLastPathComponent();
// Create new node
MutableTreeNode newNode = new DefaultMutableTreeNode("green");
// Insert new node as last child of node
model.insertNodeInto(newNode, node, node.getChildCount());
tree.expandPath(path);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Example().setVisible(true);
}
});
}
}