JTree学习笔记!

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;
 }
}

你可能感兴趣的:(JTree学习笔记!)