JTree学习笔记!
对于JTree比较重要的几个类或接口:
1。TreeMode是一个接口,是构建树的模型,接口中比较重要的几个函数是:getChild、getChildCount、getRoot、getIndexOfChild、isLeaf。如果想把一些特殊的东西抽象成一棵树,那么就可以实现该接口,用自己构造的这个模型来创建树JTree(TreeModel newModel)
2。TreeNode是一个接口,代表树的节点。DefaultMutableTreeNode是该接口的一个实现,可以直接用来创建树的节点。
3。TreePath是一个类,负责节点到根的路径
4。TreeSelectionModel是一个接口,表示树选择组件的当前状态。DefaultTreeSelectionModel类是该接口的一个实现类。
构造方法摘要 | |
---|---|
JTree() 返回带有示例模型的 JTree 。 |
|
JTree(Hashtable<?,?> value) 返回从 Hashtable 创建的 JTree ,它不显示根。 |
|
JTree(Object[] value) 返回 JTree ,指定数组的每个元素作为不被显示的新根节点的子节点。 |
|
JTree(TreeModel newModel) 返回 JTree 的一个实例,它显示根节点 - 使用指定的数据模型创建树。 |
|
JTree(TreeNode root) 返回 JTree ,指定的 TreeNode 作为其根,它显示根节点。 |
|
JTree(TreeNode root, boolean asksAllowsChildren) 返回 JTree ,指定的 TreeNode 作为其根,它用指定的方式显示根节点,并确定节点是否为叶节点。 |
|
JTree(Vector<?> value) 返回 JTree ,指定 Vector 的每个元素作为不被显示的新根节点的子节点。 |
常用方法:
1。得到模型:
getModel()或(DefaultTreeModel)getModel()
2。得到根:
getModel().getRoot()或(DefaultMutableTreeNode)getModel().getRoot()
3。根据node得到path:
TreePath visiblePath = new TreePath(((DefaultTreeModel)getModel()).getPathToRoot(node))
4。根据Path展开到该节点:
makeVisible(visiblePath)
5。根据path设定该节点选定
tree.setSelectionPath(visiblePath)
6。滚动到可见位置:
scrollRowToVisible(int row)
7。展开树<从根展开或从某一个节点展开>
关于JTree的展开
// If expand is true, expands all nodes in the tree.
// Otherwise, collapses all nodes in the tree.
public static void expandAll(JTree tree, boolean expand) {
TreeNode root = (TreeNode) tree.getModel().getRoot();
// Traverse tree from root
expandAll(tree, new TreePath(root), expand);
}
private static void expandAll(JTree tree, TreePath parent, boolean expand) {
// Traverse children
TreeNode node = (TreeNode) parent.getLastPathComponent();
if (node.getChildCount() >= 0) {
for (Enumeration e = node.children(); e.hasMoreElements();) {
TreeNode n = (TreeNode) e.nextElement();
TreePath path = parent.pathByAddingChild(n);
expandAll(tree, path, expand);
}
}
// Expansion or collapse must be done bottom-up
if (expand) {
tree.expandPath(parent);
} else {
tree.collapsePath(parent);
}
}
8。遍历树的所有节点<从根遍历或从某一个节点遍历>
public static void visitAllNodes(JTree tree) {
TreeNode root = (TreeNode) tree.getModel().getRoot();
visitAllNodes(tree,root);
}
public static void visitAllNodes(JTree tree,TreeNode node) {
// node is visited exactly once
//you can do your things about this node,such as:
tree.makeVisible(new TreePath(
((DefaultTreeModel)tree.getModel()).getPathToRoot(node)));
if (node.getChildCount() >= 0) {
for (Enumeration e = node.children(); e.hasMoreElements();) {
TreeNode n = (TreeNode) e.nextElement();
visitAllNodes(tree,n);
}
}
}
9。遍历树已经展开的节点<从根遍历或从某一个节点遍历>
// Traverse all expanded nodes in tree
public static void visitAllExpandedNodes(JTree tree) {
TreeNode root = (TreeNode) tree.getModel().getRoot();
visitAllExpandedNodes(tree, new TreePath(root));
}
public static void visitAllExpandedNodes(JTree tree, TreePath parent) {
// Return if node is not expanded
if (!tree.isVisible(parent)) {
return;
}
// node is visible and is visited exactly once
TreeNode node = (TreeNode) parent.getLastPathComponent();
//you can do your things about this node,such as:
System.out.println(node.toString());
// Visit all children
if (node.getChildCount() >= 0) {
for (Enumeration e = node.children(); e.hasMoreElements();) {
TreeNode n = (TreeNode) e.nextElement();
TreePath path = parent.pathByAddingChild(n);
visitAllExpandedNodes(tree, path);
}
}
}
一个较为完整的练习:
import java.awt.Dimension;
import java.awt.Color;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Enumeration;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.BoxLayout;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
public class JTreeDemo {
public static void expandAll(JTree tree, boolean expand) {
TreeNode root = (TreeNode) tree.getModel().getRoot();
// Traverse tree from root
expandAll(tree, new TreePath(root), expand);
}
private static void expandAll(JTree tree, TreePath parent, boolean expand) {
// Traverse children
TreeNode node = (TreeNode) parent.getLastPathComponent();
if (node.getChildCount() >= 0) {
for (Enumeration e = node.children(); e.hasMoreElements();) {
TreeNode n = (TreeNode) e.nextElement();
TreePath path = parent.pathByAddingChild(n);
expandAll(tree, path, expand);
}
}
// Expansion or collapse must be done bottom-up
if (expand) {
tree.expandPath(parent);
} else {
tree.collapsePath(parent);
}
}
public static void visitAllNodes(JTree tree) {
TreeNode root = (TreeNode) tree.getModel().getRoot();
visitAllNodes(tree,root);
}
public static void visitAllNodes(JTree tree,TreeNode node) {
// node is visited exactly once
//you can do your things about this node,such as:
tree.makeVisible(new TreePath(
((DefaultTreeModel)tree.getModel()).getPathToRoot(node)));
if (node.getChildCount() >= 0) {
for (Enumeration e = node.children(); e.hasMoreElements();) {
TreeNode n = (TreeNode) e.nextElement();
visitAllNodes(tree,n);
}
}
}
// Traverse all expanded nodes in tree
public static void visitAllExpandedNodes(JTree tree) {
TreeNode root = (TreeNode) tree.getModel().getRoot();
visitAllExpandedNodes(tree, new TreePath(root));
}
public static void visitAllExpandedNodes(JTree tree, TreePath parent) {
// Return if node is not expanded
if (!tree.isVisible(parent)) {
return;
}
// node is visible and is visited exactly once
TreeNode node = (TreeNode) parent.getLastPathComponent();
//you can do your things about this node,such as:
System.out.println(node.toString());
// Visit all children
if (node.getChildCount() >= 0) {
for (Enumeration e = node.children(); e.hasMoreElements();) {
TreeNode n = (TreeNode) e.nextElement();
TreePath path = parent.pathByAddingChild(n);
visitAllExpandedNodes(tree, path);
}
}
}
public static JTree tr;
public static void main(String[] args) {
// 构造函数:JTree()
JTree example1 = new JTree();
tr=example1;
example1.setBackground(Color.lightGray);
example1.addMouseListener(new MouseAdapter(){
public void mouseClicked(MouseEvent me){
try{
visitAllNodes(tr);
Thread.sleep(2000);
System.out.println(tr.getPathForRow(1).toString());
expandAll(tr,tr.getPathForRow(1),false);
Thread.sleep(2000);
visitAllExpandedNodes(tr);
}catch(InterruptedException e){
e.printStackTrace();
}
}
});
// 构造函数:JTree(Object[] value)
Object[] letters = { " a ", " b ", " c ", " d ", " e " };
JTree example2 = new JTree(letters);
// 构造函数:JTree(TreeNode root)(TreeNode空)
// 用空结点创建树
DefaultMutableTreeNode node1 = new DefaultMutableTreeNode(); // 定义树结点
JTree example3 = new JTree(node1); // 用此树结点做参数调用 JTree的构造函数创建含有一个根结点的树
// 构造函数:JTree(TreeNode root)(同上,只是TreeNode非空)
// 用一个根结点创建树
DefaultMutableTreeNode node2 = new DefaultMutableTreeNode(" Color ");
JTree example4 = new JTree(node2); // 结点不可以颜色,默认为白面黑字
example4.setBackground(Color.lightGray);
// 构造函数:JTree(TreeNode root, boolean
// asksAllowsChildren)(同上,只是TreeNode又有不同)
// 使用DefaultMutableTreeNode类先用一个根结点创建树,设置为可添加孩子结点,再添加孩子结点
DefaultMutableTreeNode color = new DefaultMutableTreeNode(" Color ",
true);
DefaultMutableTreeNode gray = new DefaultMutableTreeNode(" Gray ");
color.add(gray);
color.add(new DefaultMutableTreeNode(" Red "));
gray.add(new DefaultMutableTreeNode(" Lightgray "));
gray.add(new DefaultMutableTreeNode(" Darkgray "));
color.add(new DefaultMutableTreeNode(" Green "));
JTree example5 = new JTree(color);
// 构造函数:JTree(TreeNode root)(同上,只是TreeNode非空)
// 通过逐个添加结点创建树
DefaultMutableTreeNode biology = new DefaultMutableTreeNode(" Biology ");
DefaultMutableTreeNode animal = new DefaultMutableTreeNode(" Animal ");
DefaultMutableTreeNode mammal = new DefaultMutableTreeNode(" Mammal ");
DefaultMutableTreeNode horse = new DefaultMutableTreeNode(" Horse ");
mammal.add(horse);
animal.add(mammal);
biology.add(animal);
JTree example6 = new JTree(biology);
horse.isLeaf();
horse.isRoot();
// 构造函数:JTree(TreeModel newModel)
// 用DefaultMutableTreeNodel类定义一个结点再用这个结点做参数定义一个用DefaultTreeMode
// 创建一个树的模型,再用JTree的构造函数创建一个树
DefaultMutableTreeNode root = new DefaultMutableTreeNode(" Root1 ");
DefaultMutableTreeNode child1 = new DefaultMutableTreeNode(" Child1 ");
DefaultMutableTreeNode child11 = new DefaultMutableTreeNode(" Child11 ");
DefaultMutableTreeNode child111 = new DefaultMutableTreeNode(
" Child111 ");
root.add(child1);
child1.add(child11);
child11.add(child111);
DefaultTreeModel model = new DefaultTreeModel(root);
JTree example7 = new JTree(model);
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
panel.setPreferredSize(new Dimension(700, 400));
panel.add(new JScrollPane(example1)); // JTree必须放在JScrollPane上
panel.add(new JScrollPane(example2));
panel.add(new JScrollPane(example3));
panel.add(new JScrollPane(example4));
panel.add(new JScrollPane(example5));
panel.add(new JScrollPane(example6));
panel.add(new JScrollPane(example7));
JFrame frame = new JFrame(" JTreeDemo ");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(panel);
frame.pack();
frame.setVisible(true);
}
}
另外一个例子,在该例子中笔者使用基于本机目录构建的模型来构建树:
/**
* 查API时发现1.4FileSystemView这个东东多了一些功能,
* 无聊地写了这个文件目录树
*
* 声明:使用j2sdk1.4
* 建议:实现自己的File类,以过滤掉一般文件,只剩下目录
* 缺点:gui慢得要死,swing的通病?(my pc==256ddr,thunderbird900,xp)
*/
import java.awt.Component;
import java.io.*;
import javax.swing.*;
import javax.swing.event.TreeModelListener;
import javax.swing.filechooser.FileSystemView;
import javax.swing.tree.*;
public class Test {
/**
* javax.swing.filechooser.FileSystemView在这个程序里很重要,
* 用法参考j2sdk1.4 API文档
* 切记,1.4 not 1.3!!!!!!!!
*/
private static FileSystemView fileView;
int a=BB;
static int BB=34;
/**
*在这里使用了Singleton模式
* 不过似乎没什么破用
*/
static FileSystemView getFileView() {
if (fileView == null)
fileView = FileSystemView.getFileSystemView();
return fileView;
}
public static void main(String[] args) throws Exception {
//如果加入下面这句,会乱码.i wonder why
UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
//initial frame
JFrame frame = new JFrame();
frame.setSize(400, 300);
//关闭窗口时退出程序
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//initial tree with customer TreeModel
JTree tree = new JTree(new CustomTreeModel());
//set customer TreeCellRenderer
tree.setCellRenderer(new CustomTreeCellRenderer());
frame.getContentPane().add(new JScrollPane(tree));
frame.setVisible(true);
}
}
class CustomTreeModel implements TreeModel {
private FileSystemView fileView;
public CustomTreeModel() {
fileView = Test.getFileView();
}
//返回根节点
public Object getRoot() {
return fileView.getRoots()[0];
}
//返回父节点parent的第index个子节点,index以0开始
public Object getChild(Object _parent, int index) {
File parent = (File) _parent;
return parent.listFiles()[index];
}
//返回父节点parent下,子节点child的位置,与上面的方法正好相反
public int getIndexOfChild(Object parent, Object child) {
File[] files = ((File) parent).listFiles();
for (int i = 0; i < files.length; i++) {
if (files[i].equals(child))
return i;
}
return -1;
}
//返回父节点parent的子节点数
public int getChildCount(Object parent) {
File[] files = ((File) parent).listFiles();
/**
*maybe driver not ready,ie cdrom
*then files is null
*/
if (files == null)
return -1;
return files.length;
}
//是否叶节点
public boolean isLeaf(Object node) {
return ((File) node).isFile();
}
public void valueForPathChanged(TreePath path, Object newValue) {
}
/**
*下面的方法要实现,则要涉及比较复杂的事件处理
*如果有兴趣,
*可以简单的使用javax.swing.EventListenerList来实现
*/
public void addTreeModelListener(TreeModelListener l) {
}
public void removeTreeModelListener(TreeModelListener l) {
}
}
/**
* 如果没有安装自己的CellRenderer
* JTree默认的CellRenderer就是JLabel
* 它只是简单的setText(node.toString)
* CustomeTreeCellRenderer也只是简单取回
* windows默认的文件图标和文件名,装到JLabel上去
*/
class CustomTreeCellRenderer extends DefaultTreeCellRenderer {
/**
*
*/
private static final long serialVersionUID = 3892593039200536416L;
private FileSystemView fileView;
public CustomTreeCellRenderer() {
fileView = Test.getFileView();
}
public Component getTreeCellRendererComponent(JTree tree, Object value,
boolean selected, boolean expanded, boolean leaf, int row,
boolean hasFocus) {
super.getTreeCellRendererComponent(tree, value, selected, expanded,
leaf, row, hasFocus);
File file = (File) value;
setIcon(fileView.getSystemIcon(file));
setText(fileView.getSystemDisplayName(file));
return this;
}
}