Với lớp JTree, bạn có thể hiển thị dữ liệu phân cấp. Một đối tượng JTree không thực sự chứa dữ liệu của bạn; nó chỉ cung cấp một góc nhìn (view) của dữ liệu. Giống như mọi thành phần Swing không tầm thường khác, cây lấy dữ liệu bằng cách truy vấn data model của nó. Dưới đây là hình một cây:

Ví dụ một JTree

Như hình trên cho thấy, JTree hiển thị dữ liệu theo chiều dọc. Mỗi dòng của cây chứa đúng một phần dữ liệu, gọi là một node. Mọi cây đều có một node root (gốc), từ đó tất cả các node khác phát sinh. Theo mặc định, cây hiển thị node gốc, nhưng bạn có thể tắt đi. Một node có thể có node con hoặc không. Những node có khả năng có node con (dù hiện tại có node con hay chưa) được gọi là node branch (nhánh). Những node không thể có node con là node leaf (lá).

Node nhánh có thể có số lượng con bất kỳ. Thông thường, người dùng có thể mở rộng (expand) hoặc thu gọn (collapse) node nhánh bằng cách nhấp vào chúng, làm cho các node con hiện ra hoặc ẩn đi. Theo mặc định, tất cả node nhánh trừ node gốc đều ở trạng thái thu gọn. Chương trình có thể phát hiện thay đổi trạng thái mở rộng của node nhánh bằng cách lắng nghe các sự kiện tree expansion hoặc tree-will-expand, như mô tả trong How to Write a Tree Expansion Listener và How to Write a Tree-Will-Expand Listener.

Một node cụ thể trong cây có thể được xác định bằng một TreePath (đối tượng bao gồm node đó và toàn bộ node tổ tiên của nó), hoặc bằng display row (dòng hiển thị), trong đó mỗi dòng trong vùng hiển thị chứa một node.

  • Node expanded (đã mở rộng) là node không phải lá, sẽ hiển thị các con của nó khi tất cả tổ tiên của nó cũng đã mở rộng.
  • Node collapsed (đã thu gọn) là node ẩn các con của nó.
  • Node hidden (bị ẩn) là node nằm dưới một tổ tiên đang thu gọn.

Phần còn lại của bài viết bàn về các chủ đề sau:

Tạo một cây (Creating a Tree)

Đây là hình một ứng dụng, nửa trên hiển thị một cây đặt trong scroll pane.

TreeDemo

Try this:

  1. Nhấp nút Launch để chạy Tree Demo bằng Java™ Web Start (tải JDK 6). Hoặc bạn có thể tự biên dịch và chạy ví dụ theo example index.
    Launches the TreeDemo example
  2. Mở rộng một hoặc nhiều node bằng cách nhấp vào hình tròn bên trái mục đó.
  3. Thu gọn một node bằng cách nhấp vào hình tròn bên trái node đang mở rộng.

Đoạn code sau, trích từ TreeDemo.java, tạo đối tượng JTree và đặt nó vào một scroll pane:

//Where instance variables are declared:
private JTree tree;
...
public TreeDemo() {
    ...
    DefaultMutableTreeNode top =
        new DefaultMutableTreeNode("The Java Series");
    createNodes(top);
    tree = new JTree(top);
    ...
    JScrollPane treeView = new JScrollPane(tree);
    ...
}

Code này tạo một thể hiện của DefaultMutableTreeNode làm node gốc cho cây, sau đó tạo các node còn lại. Tiếp theo, nó tạo cây, truyền node gốc làm đối số cho constructor của JTree. Cuối cùng, nó đặt cây vào scroll pane, một cách làm phổ biến vì hiển thị toàn bộ cây đã mở rộng sẽ tốn quá nhiều không gian.

Đây là đoạn code tạo các node bên dưới node gốc:

private void createNodes(DefaultMutableTreeNode top) {
    DefaultMutableTreeNode category = null;
    DefaultMutableTreeNode book = null;

    category = new DefaultMutableTreeNode("Books for Java Programmers");
    top.add(category);

    //original Tutorial
    book = new DefaultMutableTreeNode(new BookInfo
        ("The Java Tutorial: A Short Course on the Basics",
        "tutorial.html"));
    category.add(book);

    //Tutorial Continued
    book = new DefaultMutableTreeNode(new BookInfo
        ("The Java Tutorial Continued: The Rest of the JDK",
        "tutorialcont.html"));
    category.add(book);

    //Swing Tutorial
    book = new DefaultMutableTreeNode(new BookInfo
        ("The Swing Tutorial: A Guide to Constructing GUIs",
        "swingtutorial.html"));
    category.add(book);

    //...add more books for programmers...

    category = new DefaultMutableTreeNode("Books for Java Implementers");
    top.add(category);

    //VM
    book = new DefaultMutableTreeNode(new BookInfo
        ("The Java Virtual Machine Specification",
         "vm.html"));
    category.add(book);

    //Language Spec
    book = new DefaultMutableTreeNode(new BookInfo
        ("The Java Language Specification",
         "jls.html"));
    category.add(book);
}

Đối số của constructor DefaultMutableTreeNode là user object, tức là đối tượng chứa hoặc trỏ tới dữ liệu gắn với node. User object có thể là một chuỗi, hoặc một đối tượng tùy biến. Nếu bạn tự cài đặt một đối tượng tùy biến, bạn nên cài đặt phương thức toString để nó trả về chuỗi sẽ hiển thị cho node đó. Theo mặc định, JTree vẽ mỗi node bằng giá trị trả về từ toString, vì vậy điều quan trọng là toString phải trả về thứ có ý nghĩa. Đôi khi không thể override toString; trong trường hợp đó bạn có thể override phương thức convertValueToText của JTree để ánh xạ đối tượng từ model sang chuỗi hiển thị.

Ví dụ, lớp BookInfo dùng trong đoạn code trước là một lớp tùy biến chứa hai dữ liệu: tên cuốn sách và URL của file HTML mô tả cuốn sách. Phương thức toString được cài đặt để trả về tên sách. Nhờ vậy, mỗi node gắn với một đối tượng BookInfo sẽ hiển thị tên một cuốn sách.

Lưu ý: Bạn có thể định dạng văn bản trong node của cây bằng cách đặt thẻ HTML vào chuỗi của node. Xem chi tiết tại Using HTML in Swing Components.

Tóm lại, bạn có thể tạo cây bằng cách gọi constructor JTree, truyền vào một lớp cài đặt TreeNode. Bạn nên đặt cây trong một scroll pane để nó không chiếm quá nhiều không gian. Bạn không cần làm gì để các node tự mở rộng/thu gọn khi người dùng nhấp chuột. Tuy nhiên, bạn phải thêm code để cây phản hồi khi người dùng chọn một node, chẳng hạn bằng cách nhấp vào node đó.

Xử lý việc chọn node (Responding to Node Selection)

Xử lý việc chọn node rất đơn giản: bạn cài đặt một tree selection listener và đăng ký nó với cây. Đoạn code sau là phần liên quan đến việc chọn node trong chương trình TreeDemo:

//Where the tree is initialized:
    tree.getSelectionModel().setSelectionMode
            (TreeSelectionModel.SINGLE_TREE_SELECTION);

    //Listen for when the selection changes.
    tree.addTreeSelectionListener(this);
...
public void valueChanged(TreeSelectionEvent e) {
//Returns the last path element of the selection.
//This method is useful only when the selection model allows a single selection.
    DefaultMutableTreeNode node = (DefaultMutableTreeNode)
                       tree.getLastSelectedPathComponent();

    if (node == null)
    //Nothing is selected.
    return;

    Object nodeInfo = node.getUserObject();
    if (node.isLeaf()) {
        BookInfo book = (BookInfo)nodeInfo;
        displayURL(book.bookURL);
    } else {
        displayURL(helpURL);
    }
}

Đoạn code trên thực hiện các việc sau:

  • Lấy TreeSelectionModel mặc định của cây, rồi thiết lập để mỗi lần chỉ chọn được tối đa một node.
  • Đăng ký một event handler với cây. Event handler là đối tượng cài đặt interface TreeSelectionListener.
  • Trong event handler, xác định node đang được chọn bằng phương thức getLastSelectedPathComponent của cây.
  • Dùng phương thức getUserObject để lấy dữ liệu gắn với node.

Để biết thêm chi tiết về xử lý sự kiện chọn node, xem How to Write a Tree Selection Listener.

Tùy biến hiển thị của cây (Customizing a Tree's Display)

Đây là hình một số node của cây, được vẽ bởi các look and feel Java, Windows và Mac OS.

Cây trong ba look and feel

Như các hình trên cho thấy, cây thường hiển thị một icon và một đoạn văn bản cho mỗi node. Bạn có thể tùy biến chúng, như sẽ trình bày ngay sau đây.

Cây thường cũng vẽ thêm một số hình phụ thuộc look and feel để thể hiện quan hệ giữa các node. Bạn có thể tùy biến phần này ở mức hạn chế. Thứ nhất, dùng tree.setRootVisible(true) để hiện node gốc hoặc tree.setRootVisible(false) để ẩn nó. Thứ hai, dùng tree.setShowsRootHandles(true) để yêu cầu các node cấp cao nhất (node gốc nếu nó hiển thị, hoặc các con của nó nếu không) có handle cho phép mở rộng hoặc thu gọn.

Nếu dùng Java look and feel, bạn có thể tùy biến việc có vẽ đường nối giữa các node hay không. Theo mặc định, Java look and feel vẽ các đường gấp khúc giữa các node. Bằng cách đặt client property JTree.lineStyle của cây, bạn có thể chọn kiểu khác. Ví dụ, để yêu cầu Java look and feel chỉ dùng đường ngang để nhóm các node:

tree.putClientProperty("JTree.lineStyle", "Horizontal");

Để yêu cầu Java look and feel không vẽ đường nào:

tree.putClientProperty("JTree.lineStyle", "None");

Hình sau cho thấy kết quả khi đặt thuộc tính JTree.lineStyle với Java look and feel.

Các kiểu đường nối

Bất kể look and feel nào, icon mặc định của một node được quyết định bởi việc node đó có phải là lá hay không và, nếu không, nó có đang mở rộng hay không. Ví dụ, trong look and feel Windows và Motif, icon lá mặc định là một dấu chấm; trong Java look and feel, icon lá mặc định là hình tờ giấy. Trong tất cả look and feel đã minh họa, node nhánh đều được đánh dấu bằng biểu tượng hình thư mục. Một số look and feel có thể dùng icon khác nhau cho nhánh đang mở và nhánh đang đóng.

Bạn có thể dễ dàng thay đổi icon mặc định cho node lá, node nhánh đang mở rộng hoặc node nhánh đang thu gọn. Để làm vậy, trước hết tạo một thể hiện của DefaultTreeCellRenderer (bạn cũng có thể tự viết một cài đặt TreeCellRenderer từ đầu, tái sử dụng các component tùy thích). Tiếp theo, chỉ định icon bằng cách gọi một hoặc nhiều phương thức sau trên renderer:

  • setLeafIcon: cho node lá
  • setOpenIcon: cho node nhánh đang mở rộng
  • setClosedIcon: cho node nhánh đang thu gọn

Nếu muốn cây không hiển thị icon cho một loại node, hãy truyền null. Sau khi thiết lập icon, dùng phương thức setCellRenderer của cây để yêu cầu DefaultTreeCellRenderer vẽ các node. Đây là ví dụ lấy từ TreeIconDemo.java:

ImageIcon leafIcon = createImageIcon("images/middle.gif");
if (leafIcon != null) {
    DefaultTreeCellRenderer renderer =
        new DefaultTreeCellRenderer();
    renderer.setLeafIcon(leafIcon);
    tree.setCellRenderer(renderer);
}

Ảnh chụp màn hình TreeIconDemo:

TreeIconDemo

Try this:

Nếu muốn kiểm soát icon của node chi tiết hơn hoặc muốn có tool tip, bạn có thể tạo một lớp con của DefaultTreeCellRenderer và override phương thức getTreeCellRendererComponent. Vì DefaultTreeCellRenderer là lớp con của JLabel, bạn có thể dùng bất kỳ phương thức nào của JLabel (như setIcon) để tùy biến nó.

Đoạn code sau, trích từ TreeIconDemo2.java, tạo một cell renderer thay đổi icon lá tùy theo việc từ "Tutorial" có nằm trong dữ liệu văn bản của node hay không. Renderer này cũng đặt tool-tip text (các dòng in đậm).

Try this:

//...where the tree is initialized:
    //Enable tool tips.
    ToolTipManager.sharedInstance().registerComponent(tree);

    ImageIcon tutorialIcon = createImageIcon("images/middle.gif");
    if (tutorialIcon != null) {
        tree.setCellRenderer(new MyRenderer(tutorialIcon));
    }
...
class MyRenderer extends DefaultTreeCellRenderer {
    Icon tutorialIcon;

    public MyRenderer(Icon icon) {
        tutorialIcon = icon;
    }

    public Component getTreeCellRendererComponent(
                        JTree tree,
                        Object value,
                        boolean sel,
                        boolean expanded,
                        boolean leaf,
                        int row,
                        boolean hasFocus) {

        super.getTreeCellRendererComponent(
                        tree, value, sel,
                        expanded, leaf, row,
                        hasFocus);
        if (leaf && isTutorialBook(value)) {
            setIcon(tutorialIcon);
            setToolTipText("This book is in the Tutorial series.");
        } else {
            setToolTipText(null); //no tool tip
        }

        return this;
    }

    protected boolean isTutorialBook(Object value) {
        DefaultMutableTreeNode node =
                (DefaultMutableTreeNode)value;
        BookInfo nodeInfo =
                (BookInfo)(node.getUserObject());
        String title = nodeInfo.bookName;
        if (title.indexOf("Tutorial") >= 0) {
            return true;
        }

        return false;
    }
}

Kết quả:

TreeIconDemo2

Có thể bạn thắc mắc cell renderer hoạt động như thế nào. Khi cây vẽ từng node, cả JTree lẫn phần cài đặt theo look and feel của nó đều không chứa code vẽ node. Thay vào đó, cây dùng code vẽ của cell renderer. Ví dụ, để vẽ một node lá có chuỗi "The Java Programming Language", cây yêu cầu cell renderer trả về một component có thể vẽ node lá với chuỗi đó. Nếu cell renderer là DefaultTreeCellRenderer, nó trả về một label vẽ icon lá mặc định theo sau là chuỗi.

Cell renderer chỉ vẽ; nó không xử lý được sự kiện. Nếu muốn thêm xử lý sự kiện cho cây, bạn cần đăng ký handler với cây, hoặc với cell editor của cây nếu việc xử lý chỉ xảy ra khi node được chọn. Về cell editor, xem Concepts: Editors and Renderers. Phần đó bàn về cell editor và renderer của bảng, tương tự như của cây.

Thay đổi cây động (Dynamically Changing a Tree)

Hình sau cho thấy ứng dụng DynamicTreeDemo, cho phép thêm và xóa node trên cây đang hiển thị. Bạn cũng có thể sửa văn bản của từng node.

DynamicTreeDemo

Ứng dụng này dựa trên một ví dụ do bạn đọc Richard Stanford của tutorial cung cấp.

Try this:

Đây là đoạn code khởi tạo cây:

rootNode = new DefaultMutableTreeNode("Root Node");
treeModel = new DefaultTreeModel(rootNode);
treeModel.addTreeModelListener(new MyTreeModelListener());

tree = new JTree(treeModel);
tree.setEditable(true);
tree.getSelectionModel().setSelectionMode
        (TreeSelectionModel.SINGLE_TREE_SELECTION);
tree.setShowsRootHandles(true);

Bằng cách tạo tường minh model của cây, đoạn code đảm bảo model đó là một thể hiện của DefaultTreeModel. Nhờ vậy ta biết chính xác các phương thức model hỗ trợ. Ví dụ, ta biết có thể gọi phương thức insertNodeInto của model, dù phương thức này không bắt buộc bởi interface TreeModel.

Để cho phép sửa văn bản trong các node, ta gọi setEditable(true) trên cây. Khi người dùng sửa xong một node, model phát ra một tree model event để báo cho mọi listener (bao gồm cả JTree) biết các node đã thay đổi. Lưu ý rằng dù DefaultMutableTreeNode có các phương thức để thay đổi nội dung node, mọi thay đổi nên đi qua các phương thức bao (cover method) của DefaultTreeModel. Nếu không, các tree model event sẽ không được phát ra, và các listener như cây sẽ không biết về những cập nhật đó.

Để được thông báo về thay đổi của node, ta có thể cài đặt TreeModelListener. Đây là ví dụ một tree model listener phát hiện khi người dùng gõ tên mới cho node:

class MyTreeModelListener implements TreeModelListener {
    public void treeNodesChanged(TreeModelEvent e) {
        DefaultMutableTreeNode node;
        node = (DefaultMutableTreeNode)
                 (e.getTreePath().getLastPathComponent());

        /*
         * If the event lists children, then the changed
         * node is the child of the node we have already
         * gotten.  Otherwise, the changed node and the
         * specified node are the same.
         */
        try {
            int index = e.getChildIndices()[0];
            node = (DefaultMutableTreeNode)
                   (node.getChildAt(index));
        } catch (NullPointerException exc) {}

        System.out.println("The user has finished editing the node.");
        System.out.println("New value: " + node.getUserObject());
    }
    public void treeNodesInserted(TreeModelEvent e) {
    }
    public void treeNodesRemoved(TreeModelEvent e) {
    }
    public void treeStructureChanged(TreeModelEvent e) {
    }
}

Đây là đoạn code mà event handler của nút Add dùng để thêm một node mới vào cây:

treePanel.addObject("New Node " + newNodeSuffix++);
...
public DefaultMutableTreeNode addObject(Object child) {
    DefaultMutableTreeNode parentNode = null;
    TreePath parentPath = tree.getSelectionPath();

    if (parentPath == null) {
        //There is no selection. Default to the root node.
        parentNode = rootNode;
    } else {
        parentNode = (DefaultMutableTreeNode)
                     (parentPath.getLastPathComponent());
    }

    return addObject(parentNode, child, true);
}
...
public DefaultMutableTreeNode addObject(DefaultMutableTreeNode parent,
                                        Object child,
                                        boolean shouldBeVisible) {
    DefaultMutableTreeNode childNode =
            new DefaultMutableTreeNode(child);
    ...
    treeModel.insertNodeInto(childNode, parent,
                             parent.getChildCount());

    //Make sure the user can see the lovely new node.
    if (shouldBeVisible) {
        tree.scrollPathToVisible(new TreePath(childNode.getPath()));
    }
    return childNode;
}

Đoạn code tạo một node, chèn nó vào tree model, rồi nếu cần thì yêu cầu mở rộng các node cha phía trên và cuộn cây để node mới hiển thị. Để chèn node vào model, code dùng phương thức insertNodeInto do lớp DefaultTreeModel cung cấp.

Tạo data model (Creating a Data Model)

Nếu DefaultTreeModel không đáp ứng nhu cầu, bạn sẽ cần viết một data model tùy biến. Data model của bạn phải cài đặt interface TreeModel. TreeModel quy định các phương thức để lấy một node cụ thể của cây, lấy số con của một node, xác định một node có phải lá không, thông báo cho model về thay đổi trên cây, và thêm/xóa tree model listener.

Điều thú vị là interface TreeModel chấp nhận bất kỳ loại đối tượng nào làm node của cây. Nó không yêu cầu node phải là đối tượng DefaultMutableTreeNode, hay thậm chí phải cài đặt interface TreeNode. Do đó, nếu interface TreeNode không phù hợp với tree model của bạn, cứ thoải mái tự thiết kế cách biểu diễn node. Ví dụ, nếu bạn đã có sẵn một cấu trúc dữ liệu phân cấp, bạn không cần nhân đôi nó hay ép nó vào khuôn TreeNode; chỉ cần cài đặt tree model sao cho nó dùng thông tin trong cấu trúc dữ liệu có sẵn đó.

Hình sau cho thấy ứng dụng GenealogyExample, hiển thị con cháu hoặc tổ tiên của một người cụ thể. (Cảm ơn bạn đọc Olivier Berlanger của tutorial đã cung cấp ví dụ này.)

Try this:

GenealogyExample

Bạn có thể xem cài đặt tree model tùy biến trong GenealogyModel.java. Vì model được cài đặt như một lớp con của Object thay vì, chẳng hạn, lớp con của DefaultTreeModel, nó phải cài đặt trực tiếp interface TreeModel. Điều này đòi hỏi cài đặt các phương thức lấy thông tin về node, như đâu là node gốc và các con của một node là gì. Với GenealogyModel, mỗi node được biểu diễn bởi một đối tượng kiểu Person, một lớp tùy biến không cài đặt TreeNode.

Tree model cũng phải cài đặt các phương thức thêm và xóa tree model listener, và phải phát các TreeModelEvent tới các listener đó khi cấu trúc hoặc dữ liệu của cây thay đổi. Ví dụ, khi người dùng yêu cầu GenealogyExample chuyển từ hiển thị tổ tiên sang hiển thị con cháu, tree model thực hiện thay đổi rồi phát một sự kiện để thông báo cho các listener (như component cây).

Nạp node con theo kiểu lazy (How to Load Children Lazily)

Lazy loading là đặc tính của ứng dụng trong đó việc nạp và khởi tạo một lớp bị trì hoãn cho đến ngay trước khi thể hiện đó thực sự được dùng.

Ta có lợi gì khi nạp lazy? Có, chắc chắn nó cải thiện hiệu năng ứng dụng. Với lazy loading, bạn chỉ dành tài nguyên bộ nhớ để nạp và khởi tạo một đối tượng khi nó thực sự được dùng. Bạn cũng có thể rút ngắn thời gian nạp ban đầu của ứng dụng.

Một cách để nạp lazy các node con của cây là dùng interface TreeWillExpandListener. Ví dụ, bạn có thể khai báo và nạp node gốc, node ông và node cha của cây ngay khi khởi động ứng dụng, như đoạn code sau:

class DemoArea extends JScrollPane
                   implements TreeWillExpandListener {
        .......
        .......

        private TreeNode createNodes() {
            DefaultMutableTreeNode root;
            DefaultMutableTreeNode grandparent;
            DefaultMutableTreeNode parent;

            root = new DefaultMutableTreeNode("San Francisco");

            grandparent = new DefaultMutableTreeNode("Potrero Hill");
            root.add(grandparent);

            parent = new DefaultMutableTreeNode("Restaurants");
            grandparent.add(parent);

            dummyParent = parent;
            return root;
        }

Bạn có thể nạp các node vừa khai báo vào cây như sau:

TreeNode rootNode = createNodes();
            tree = new JTree(rootNode);
            tree.addTreeExpansionListener(this);
            tree.addTreeWillExpandListener(this);
     .......
     .......
            setViewportView(tree);

Bây giờ, bạn có thể nạp lazy các node con mỗi khi node cha Restaurants hiển thị trong ứng dụng. Để làm vậy, ta khai báo hai node con trong một phương thức riêng rồi gọi phương thức đó:

private void LoadLazyChildren(){
            DefaultMutableTreeNode child;
            child = new DefaultMutableTreeNode("Thai Barbeque");
            dummyParent.add(child);
            child = new DefaultMutableTreeNode("Goat Hill Pizza");
            dummyParent.add(child);
            textArea.append(" Thai Barbeque and Goat Hill Pizza are loaded lazily");
        }

        .......
        .......

public void treeWillExpand(TreeExpansionEvent e)
                    throws ExpandVetoException {
            saySomething("You are about to expand node ", e);
            int n = JOptionPane.showOptionDialog(
                this, willExpandText, willExpandTitle,
                JOptionPane.YES_NO_OPTION,
                JOptionPane.QUESTION_MESSAGE,
                null,
                willExpandOptions,
                willExpandOptions[1]);

        LoadLazyChildren();
        }

Xem How to Write a Tree-Will-Expand Listener để biết mô tả về Tree-Will-Expand listener.

Tree API

Tree API khá rộng. Các bảng sau chỉ liệt kê một phần nhỏ của API, tập trung vào các nhóm sau:

Để biết thêm về tree API, xem tài liệu API của JTree và của các lớp, interface trong tree package. Đồng thời xem The JComponent Class để biết API mà JTree kế thừa từ lớp cha.

Các lớp và interface liên quan đến cây
Lớp hoặc InterfaceMục đích
JTreeComponent trình bày cây cho người dùng.
TreePathBiểu diễn đường dẫn tới một node.
TreeNode
MutableTreeNode
DefaultMutableTreeNode
Các interface mà tree model mặc định yêu cầu node của nó cài đặt, và lớp cài đặt được tree model mặc định sử dụng.
TreeModel
DefaultTreeModel
Lần lượt là interface mà tree model phải cài đặt và lớp cài đặt thường dùng.
TreeCellRenderer
DefaultTreeCellRenderer
Lần lượt là interface mà tree cell renderer phải cài đặt và lớp cài đặt thường dùng.
TreeCellEditor
DefaultTreeCellEditor
Lần lượt là interface mà tree cell editor phải cài đặt và lớp cài đặt thường dùng.
TreeSelectionModel
DefaultTreeSelectionModel
Lần lượt là interface mà selection model của cây phải cài đặt và lớp cài đặt thường dùng.
TreeSelectionListener
TreeSelectionEvent
Interface và kiểu sự kiện dùng để phát hiện thay đổi việc chọn node. Xem thêm tại Getting Started.
TreeModelListener
TreeModelEvent
Interface và kiểu sự kiện dùng để phát hiện thay đổi tree model. Xem thêm tại How to Write a Tree Model Listener.
TreeExpansionListener
TreeWillExpandListener
TreeExpansionEvent
Các interface và kiểu sự kiện dùng để phát hiện việc mở rộng và thu gọn cây. Xem thêm tại How to Write a Tree Expansion Listener và How to Write a Tree-Will-Expand Listener.
ExpandVetoExceptionException mà một TreeWillExpandListener có thể ném ra để báo rằng việc mở rộng/thu gọn sắp diễn ra không được xảy ra. Xem thêm tại How to Write a Tree-Will-Expand Listener.

Tạo và thiết lập cây
Constructor hoặc Phương thứcMục đích
JTree(TreeNode)
JTree(TreeNode, boolean)
JTree(TreeModel)
JTree()
JTree(Hashtable)
JTree(Object[])
JTree(Vector)
Tạo một cây. Đối số TreeNode chỉ định node gốc, do tree model mặc định quản lý. Đối số TreeModel chỉ định model cung cấp dữ liệu cho cây. Phiên bản không đối số của constructor này dành cho các công cụ builder; nó tạo một cây chứa dữ liệu mẫu. Nếu bạn truyền Hashtable, mảng đối tượng hoặc Vector, đối số đó được coi là danh sách các node nằm dưới node gốc (không được hiển thị), và model cùng các node sẽ được tạo tương ứng.

Đối số boolean, nếu có, chỉ định cách cây xác định một node có hiển thị như lá hay không. Nếu là false (mặc định), mọi node không có node con đều hiển thị như lá. Nếu là true, một node chỉ là lá khi phương thức getAllowsChildren của nó trả về false.
void setCellRenderer(TreeCellRenderer)Đặt renderer vẽ từng node.
void setEditable(boolean)
void setCellEditor(TreeCellEditor)
Phương thức đầu đặt việc người dùng có được sửa node của cây hay không. Theo mặc định, node không sửa được. Phương thức thứ hai đặt editor tùy biến sẽ dùng.
void setRootVisible(boolean)Đặt việc cây có hiển thị node gốc hay không. Giá trị mặc định là false nếu cây được tạo bằng constructor nhận cấu trúc dữ liệu, và true trong các trường hợp còn lại.
void setShowsRootHandles(boolean)Đặt việc cây có hiển thị handle cho các node ngoài cùng bên trái hay không, cho phép mở rộng và thu gọn chúng. Mặc định là false. Nếu cây không hiển thị node gốc, bạn nên gọi setShowsRootHandles(true).
void setDragEnabled(boolean)
boolean getDragEnabled()
Đặt hoặc lấy thuộc tính dragEnabled, phải là true để bật xử lý kéo trên component này. Mặc định là false. Xem Drag and Drop and Data Transfer để biết thêm.

Cài đặt việc chọn node
Phương thứcMục đích
void addTreeSelectionListener(TreeSelectionListener)Đăng ký listener để phát hiện khi một node được chọn hoặc bị bỏ chọn.
void setSelectionModel(TreeSelectionModel)
TreeSelectionModel getSelectionModel()
Đặt hoặc lấy model điều khiển việc chọn node. Bạn có thể tắt hoàn toàn việc chọn node bằng setSelectionModel(null).
void setSelectionMode(int)
int getSelectionMode()
(trong TreeSelectionModel)
Đặt hoặc lấy chế độ chọn. Giá trị có thể là CONTIGUOUS_TREE_SELECTION, DISCONTIGUOUS_TREE_SELECTION hoặc SINGLE_TREE_SELECTION (đều định nghĩa trong TreeSelectionModel).
Object getLastSelectedPathComponent()Lấy đối tượng biểu diễn node đang được chọn. Tương đương với việc gọi getLastPathComponent trên giá trị trả về của tree.getSelectionPath().
void setSelectionPath(TreePath)
TreePath getSelectionPath()
Đặt hoặc lấy đường dẫn tới node đang được chọn.
void setSelectionPaths(TreePath[])
TreePath[] getSelectionPaths()
Đặt hoặc lấy các đường dẫn tới những node đang được chọn.

Hiện và ẩn node
Phương thứcMục đích
void addTreeExpansionListener(TreeExpansionListener)
void addTreeWillExpandListener(TreeWillExpandListener)
Đăng ký listener để phát hiện khi các node của cây đã mở rộng/thu gọn, hoặc sắp mở rộng/thu gọn (tương ứng). Để từ chối một lần mở rộng hoặc thu gọn sắp diễn ra, TreeWillExpandListener có thể ném ExpandVetoException.
void expandPath(TreePath)
void collapsePath(TreePath)
Mở rộng hoặc thu gọn đường dẫn được chỉ định.
void scrollPathToVisible(TreePath)Đảm bảo node được chỉ định bởi đường dẫn hiển thị: đường dẫn dẫn tới nó được mở rộng và node nằm trong vùng nhìn của scroll pane.
void makeVisible(TreePath)Đảm bảo node được chỉ định bởi đường dẫn có thể xem được: đường dẫn dẫn tới nó được mở rộng. Node có thể vẫn nằm ngoài vùng nhìn.
void setScrollsOnExpand(boolean)
boolean getScrollsOnExpand()
Đặt hoặc lấy việc cây có cố cuộn để hiện các node vừa được hiện hay không. Mặc định là true.
void setToggleClickCount(int)
int getToggleClickCount()
Đặt hoặc lấy số lần nhấp chuột trước khi node mở rộng hoặc đóng lại. Mặc định là hai.
TreePath getNextMatch(String, int, Position.Bias)Trả về TreePath tới phần tử cây tiếp theo bắt đầu bằng tiền tố đã cho.

Các ví dụ sử dụng cây (Examples that Use Trees)

Bảng sau liệt kê các ví dụ dùng JTree và nơi các ví dụ đó được mô tả.

Ví dụNơi mô tảGhi chú
TreeDemoTạo một cây, Xử lý việc chọn node, Tùy biến hiển thị của câyTạo một cây phản hồi việc người dùng chọn node. Cũng có code tùy biến kiểu đường nối cho Java look and feel.
TreeIconDemoTùy biến hiển thị của câyThêm icon lá tùy biến vào TreeDemo.
TreeIconDemo2Tùy biến hiển thị của câyTùy biến một số icon lá và cung cấp tool tip cho một số node.
DynamicTreeDemoThay đổi cây độngMinh họa việc thêm và xóa node của cây. Cũng cho phép sửa văn bản node.
GenealogyExampleTạo data modelCài đặt tree model tùy biến và kiểu node tùy biến.
TreeExpandEventDemoHow to Write a Tree Expansion ListenerCho thấy cách phát hiện việc mở rộng và thu gọn node.
TreeExpandEventDemo2How to Write a Tree-Will-Expand ListenerCho thấy cách từ chối việc mở rộng node.
TreeTable, TreeTable II, Editable JTreeTableCreating TreeTables in Swing, Creating TreeTables: Part 2, Editable JTreeTableCác ví dụ trong The Swing Connection kết hợp cây và bảng để hiển thị thông tin chi tiết về một hệ phân cấp như hệ thống file. Cây đóng vai trò renderer cho bảng.

Translated from: http://download.oracle.com/javase/tutorial/uiswing/components/tree.html