本文鏈接: http://blog.csdn.net/xietansheng/article/details/78079812
1. 概述
官方JavaDocsApi: javax.swing.JTree
JTree
,樹。將分層數據顯示爲樹狀輪廓的組件。
一顆樹由若干節點,通過層級關係組成,一個節點由TreeNode
實例來表示,節點在樹中的位置(路徑)由TreePath
實例來表示(定位)。
創建樹時,首先要創建一個根節點,然後創建第二層節點添加到根節點,繼續創建節點添加到其父節點,最終形成由根節點所引領的一棵樹,再由 JTree 數組件顯示出來。所有擁有子節點的節點可以自由展開或摺疊子節點。
TreeNode 是一個接口,創建節點對象時,通常使用已實現該接口的的 DefaultMutableTreeNode 類。
2. 節點: DefaultMutableTreeNode
DefaultMutableTreeNode
表示一個節點,擁有對節點增刪改查等操作的豐富方法。DefaultMutableTreeNode 實現了 MutableTreeNode 接口,而 MutableTreeNode 接口繼承自 TreeNode 接口。
DefaultMutableTreeNode 構造方法:
/**
* 參數說明:
* userObject: 節點的用戶對象(節點顯示的名稱)
* allowsChildren: 是否允許有子節點
*/
DefaultMutableTreeNode()
DefaultMutableTreeNode(Object userObject)
DefaultMutableTreeNode(Object userObject, boolean allowsChildren)
DefaultMutableTreeNode 常用方法:
// 添加一個子節點在末尾
void add(MutableTreeNode newChild);
// 在指定位置插入一個子節點
void insert(MutableTreeNode newChild, int childIndex)
// 移除子節點
void remove(int childIndex);
void remove(MutableTreeNode aChild);
void removeAllChildren();
// 獲取子節點數量
int getChildCount();
// 獲取葉子節點的數量
int getLeafCount();
// 獲取指定索引位置的子節點
TreeNode getChildAt(int index);
// 獲取指定子節點之後的子節點
TreeNode getChildAfter(TreeNode aChild);
// 獲取指定子節點之前的子節點
TreeNode getChildBefore(TreeNode aChild);
// 判斷某節點是否爲此節點的子節點
boolean isNodeChild(TreeNode aNode);
// 獲取此節點的父節點,沒有父節點則返回 null
TreeNode getParent();
// 判斷此節點是否爲根節點
boolean isRoot();
// 判斷是否爲葉節點(沒有子節點即爲葉節點,則返回 true)
boolean isLeaf();
// 返回此節點上的級數,從根到此節點的距離。如果此節點爲根,則返回 0。
int getLevel();
// 返回從根到此節點的路徑。該路徑中第一個元素是根節點,最後一個元素是此節點。
TreeNode[] getPath();
// 遍歷子節點(只包括直接子節點,不包括孫節點)
Enumeration children();
// 按廣度優先的順序遍歷以此節點爲根的子樹(包含此節點下的所有節點)
Enumeration breadthFirstEnumeration();
// 按深度優先的順序遍歷以此節點爲根的子樹(包含此節點下的所有節點)
Enumeration depthFirstEnumeration();
// 設置節點的用戶對象(節點顯示的名稱)
void setUserObject(Object userObject);
// 獲取節點的用戶對象(節點顯示的名稱)
Object getUserObject();
3. 路徑: TreePath
TreePath
表示某節點的路徑(從根節點到此節點),一般使用方式:
// 一個節點
DefaultMutableTreeNode node = ...;
// 獲取節點的路徑(從根節點到此節點沿路徑的所有節點集)
TreeNode[] pathNodes = node.getPath();
// 使用節點路徑集創建樹路徑
TreePath treePath = new TreePath(pathNodes);
/*
* 這裏得到的 treePath 表示的是樹中的一個路徑,可以定位到具體的節點,
* 從而對該節點進行相關操作(展開/摺疊子節點等),詳見後面 JTree 的介紹。
*/
/* 樹路徑的其他常用方法 */
// 獲取此樹路徑上的所有節點,返回數組的元素爲節點對象
Object[] paths = treePath.getPath();
// 獲取此樹路徑上的節點數量
int nodeCount = treePath.getPathCount();
// 獲取此樹路徑表示的節點的父節點的樹路徑
TreePath parentPath = treePath.getParentPath();
// 判斷指定樹路徑是否爲此樹路徑的“子孫”樹路徑
boolean isDescendant = treePath.isDescendant(TreePath aTreePath);
4. 樹: JTree
JTree
表示一個樹組件,負責把內存中構造的整顆結構樹顯示出來。因爲對於樹結構,只需要得到一個根節點,就相當於獲取到了整棵樹的應用,因此只需要把一顆樹的根節點傳遞給 JTree 便可顯示整棵樹。
JTree 實例的創建:
// 方式一: 指定一個根節點創建樹
JTree tree = JTree(TreeNode root);
// 方式二: 先創建一個樹模型(自定義樹模型或使用已實現的默認樹模型),再用指定樹模型創建樹
TreeModel treeModel = new DefaultTreeModel(TreeNode root);
JTree tree = JTree(treeModel);
// 方式三: 先創建一個空樹,在設置樹模型
JTree tree = JTree();
tree.setModel(TreeModel newModel);
JTree 對節點的操作:
// 通過行索引獲取指定行的樹路徑(這裏的行表示的是在 JTree 組件
// 內可以直接看到的行,即不包括已摺疊的,根節點行索引爲 0,如果
// 根節點展開,則根節點的直接第一個子節點行索引爲 1)。
TreePath getPathForRow(int row);
// 根據樹路徑獲取指定節點所在行索引
int getRowForPath(TreePath path);
// 根據在 JTree 組件內的座標獲取指定座標處所在的節點定位,
// 通過監聽鼠標點擊事件獲取到點擊座標,從而可利用此方法實現
// 監聽對節點的單擊或雙擊事件。
int getRowForLocation(int x, int y);
TreePath getPathForLocation(int x, int y);
// 展開指定節點(通過可視行索引或樹路徑定位目標節點)
void expandRow(int row);
void expandPath(TreePath path);
// 摺疊指定節點
void collapseRow(int row);
void collapsePath(TreePath path);
// 判斷指定節點是否處於展開狀態
boolean isExpanded(int row);
boolean isExpanded(TreePath path);
// 設置當前默認選中的節點(可多選)
void setSelectionRow(int row);
void setSelectionRows(int[] rows);
void setSelectionPath(TreePath path);
void setSelectionPaths(TreePath[] paths);
// 獲取當前選中的節點
int[] getSelectionRows();
TreePath getSelectionPath();
TreePath[] getSelectionPaths();
// 是否顯示根節點(默認顯示)
void setRootVisible(boolean rootVisible);
// 是否顯示根節點的句柄(默認不顯示)
void setShowsRootHandles(boolean newValue);
// 是否允許編輯節點
void setEditable(boolean flag);
JTree 自定義節點樣式(字體、圖標等):
// 首先,創建一個樹節點的渲染器
DefaultTreeCellRenderer render = new DefaultTreeCellRenderer();
// 設置節點 展開 和 摺疊 狀態顯示的圖標
render.setOpenIcon(Icon newIcon);
render.setClosedIcon(Icon newIcon);
// 設置葉子節點顯示的圖標
render.setLeafIcon(Icon newIcon);
// 設置節點字體,以及 選中 和 未選中 時的顏色
render.setFont(Font font);
render.setTextSelectionColor(Color newColor);
render.setTextNonSelectionColor(Color newColor);
// 設置節點 選中 和 未選中 時的背景顏色
render.setBackgroundSelectionColor(Color newColor);
render.setBackgroundNonSelectionColor(Color newColor);
// 最後,設置樹組件的節點渲染器
jTree.setCellRenderer(render);
JTree 對節點變化的監聽:
JTree tree = new JTree(rootNode);
/*
* 節點展開/摺疊監聽器
*/
tree.addTreeExpansionListener(new TreeExpansionListener() {
@Override
public void treeExpanded(TreeExpansionEvent event) {
System.out.println("展開的節點: " + event.getPath());
}
@Override
public void treeCollapsed(TreeExpansionEvent event) {
System.out.println("摺疊的節點: " + event.getPath());
}
});
/*
* 節點展開/摺疊監聽器(比上一個監聽器先執行)
*/
tree.addTreeWillExpandListener(new TreeWillExpandListener() {
@Override
public void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException {
System.out.println("展開的節點: " + event.getPath());
}
@Override
public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException {
System.out.println("摺疊的節點: " + event.getPath());
}
});
/*
* 節點被選中的監聽器
*/
tree.addTreeSelectionListener(new TreeSelectionListener() {
@Override
public void valueChanged(TreeSelectionEvent e) {
// 獲取被選中的相關節點
TreePath path = e.getPath();
TreePath[] paths = e.getPaths();
TreePath newLeadPath = e.getNewLeadSelectionPath();
TreePath oldLeadPath = e.getOldLeadSelectionPath();
}
});
// 節點增刪改監聽器
tree.getModel().addTreeModelListener(new TreeModelListener() {
@Override
public void treeNodesChanged(TreeModelEvent e) {
System.out.println("節點改變: " + e.getTreePath());
}
@Override
public void treeNodesInserted(TreeModelEvent e) {
System.out.println("節點插入: " + e.getTreePath());
}
@Override
public void treeNodesRemoved(TreeModelEvent e) {
System.out.println("節點移除: " + e.getTreePath());
}
@Override
public void treeStructureChanged(TreeModelEvent e) {
System.out.println("結構改變: " + e.getTreePath());
}
});
5. 代碼實例
package com.xiets.swing;
import javax.swing.*;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import java.awt.*;
public class Main {
public static void main(String[] args) {
JFrame jf = new JFrame("測試窗口");
jf.setSize(300, 300);
jf.setLocationRelativeTo(null);
jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
JPanel panel = new JPanel(new BorderLayout());
// 創建根節點
DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode("中國");
// 創建二級節點
DefaultMutableTreeNode gdNode = new DefaultMutableTreeNode("廣東");
DefaultMutableTreeNode fjNode = new DefaultMutableTreeNode("福建");
DefaultMutableTreeNode shNode = new DefaultMutableTreeNode("上海");
DefaultMutableTreeNode twNode = new DefaultMutableTreeNode("臺灣");
// 把二級節點作爲子節點添加到根節點
rootNode.add(gdNode);
rootNode.add(fjNode);
rootNode.add(shNode);
rootNode.add(twNode);
// 創建三級節點
DefaultMutableTreeNode gzNode = new DefaultMutableTreeNode("廣州");
DefaultMutableTreeNode szNode = new DefaultMutableTreeNode("深圳");
DefaultMutableTreeNode fzNode = new DefaultMutableTreeNode("福州");
DefaultMutableTreeNode xmNode = new DefaultMutableTreeNode("廈門");
DefaultMutableTreeNode tbNode = new DefaultMutableTreeNode("臺北");
DefaultMutableTreeNode gxNode = new DefaultMutableTreeNode("高雄");
DefaultMutableTreeNode jlNode = new DefaultMutableTreeNode("基隆");
// 把三級節點作爲子節點添加到相應的二級節點
gdNode.add(gzNode);
gdNode.add(szNode);
fjNode.add(fzNode);
fjNode.add(xmNode);
twNode.add(tbNode);
twNode.add(gxNode);
twNode.add(jlNode);
// 使用根節點創建樹組件
JTree tree = new JTree(rootNode);
// 設置樹顯示根節點句柄
tree.setShowsRootHandles(true);
// 設置樹節點可編輯
tree.setEditable(true);
// 設置節點選中監聽器
tree.addTreeSelectionListener(new TreeSelectionListener() {
@Override
public void valueChanged(TreeSelectionEvent e) {
System.out.println("當前被選中的節點: " + e.getPath());
}
});
// 創建滾動面板,包裹樹(因爲樹節點展開後可能需要很大的空間來顯示,所以需要用一個滾動面板來包裹)
JScrollPane scrollPane = new JScrollPane(tree);
// 添加滾動面板到那內容面板
panel.add(scrollPane, BorderLayout.CENTER);
// 設置窗口內容面板並顯示
jf.setContentPane(panel);
jf.setVisible(true);
}
}
結果展示: