In fact, what this article will say has nothing to do with the components in TWaver just because I find it quite interesting. Therefore, I would like to share it with you. The file tree is completely based on JTree of swing. Now let's first see the final effect:
Screenshot:
Introduction on Functions:
- to show the structure of files in tree
- the icon of files should be systematic ones
- The background color of the current node will be changed when you mouse over it.(such as the bricky-red background of the text "Windows" in the image above)
First let' s see the class structure:
- main program
- file tree, which inherits from JTree
- the encapsulated node, including the name and the icon of a file, the File class and other identity
- The customized node renderer which inherits from DefaultTreeCellRenderer
- the customized TreeModel which inherits from DefaultTreeModel
Considering that there will be quite a few system files, it is not reasonable to initialize the whole tree at starting a program. So we have taken measures to delay loading: to only initialize the child nodes of a node only when it is to be expanded. Now add a listener into the construction of FileTree:
addTreeWillExpandListener(new TreeWillExpandListener() {
@Override
public void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException {
DefaultMutableTreeNode lastTreeNode =
(DefaultMutableTreeNode) event.getPath().getLastPathComponent();
FileNode fileNode = (FileNode) lastTreeNode.getUserObject();
if (!fileNode.isInit) {
File[] files;
if (fileNode.isDummyRoot) {
files = fileSystemView.getRoots();
} else {
files = fileSystemView.getFiles(
((FileNode) lastTreeNode.getUserObject()).file,
false);
}
for (int i = 0; i < files.length; i++) {
//The name and the icon of the file is obtained through fileSystemView.
FileNode childFileNode = new FileNode(
fileSystemView.getSystemDisplayName(files[i]),
fileSystemView.getSystemIcon(files[i]), files[i],
false);
DefaultMutableTreeNode childTreeNode = new DefaultMutableTreeNode(childFileNode);
lastTreeNode.add(childTreeNode);
}
//To notify that a node has been changed
DefaultTreeModel treeModel1 = (DefaultTreeModel) getModel();
treeModel1.nodeStructureChanged(lastTreeNode);
}
//to change the identifier to avoid loading repeatedly
fileNode.isInit = true;
}
@Override
public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException {
}
});
Of course, this method must be combined with TableModel. I have reloaded DefaultTreeModel and initialized the root node in the construction. Then load the method isLeaf.
Now let's think how to change the background color of a node when you mouse over it.
Right at this time I recalled the mistake I made during the time when I first learned Renderer that every node has a Renderer and I even tend to add a listener to it! The thing I have to emphasize is that
Renderer is just a renderer. JTree will call it to render nodes onto the screen to show them. But remember however nodes there are, there is only one Renderer in a JTree!
Since it is useless to add a listener to Renderer, we have to change our focus, that is, to add listener which listens to mouse-moves in JTree and then repaint the node on which the mouse is.
addMouseMotionListener(new MouseAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
//to obtain the TreePath of the mouse
TreePath path=getPathForLocation(e.getX(), e.getY());
//to calculate the area to be reprinted and to repaint JTree
if(path!=null){
if(mouseInPath!=null){
Rectangle oldRect=getPathBounds(mouseInPath);
mouseInPath=path;
repaint(getPathBounds(path).union(oldRect));
}else{
mouseInPath=path;
Rectangle bounds=getPathBounds(mouseInPath);
repaint(bounds);
}
}else if(mouseInPath!=null){
Rectangle oldRect=getPathBounds(mouseInPath);
mouseInPath=null;
repaint(oldRect);
}
}
});
The background color of mouseInPath can be changed in Renderer only when the TreePath(mouseInPath) of MouseOver is saved in JTree.
FileTree fileTree=(FileTree)tree;
JLabel label= (JLabel) super.getTreeCellRendererComponent(tree,value,sel,expanded,leaf,row,hasFocus);
DefaultMutableTreeNode node=(DefaultMutableTreeNode)value;
FileNode fileNode=(FileNode)node.getUserObject();
label.setText(fileNode.name);
label.setIcon(fileNode.icon);
label.setOpaque(false);
//to change the background color if the node in rendering now is the node under the mouse over
if(fileTree.mouseInPath!=null&&
fileTree.mouseInPath.getLastPathComponent().equals(value)){
label.setOpaque(true);
label.setBackground(new Color(255,0,0,90));
}
return label;
Now it is the end of the article. If you have interest in it, welcome for your communication and good ideas.