最近學習了一下JTree的使用方法:
先來看一下樹的實例:
構建一個樹,
DefaultMutableTreeNode root = new DefaultMutableTreeNode("根節點");
DefaultMutableTreeNode node = new DefaultMutableTreeNode("節點1");
root.add(node);
root.add(new DefaultMutableTreeNode("葉子節點3"));
node.add(new DefaultMutableTreeNode("葉子節點1"));
node.add(new DefaultMutableTreeNode("葉子節點2"));
DefaultTreeModel jMode = new DefaultTreeModel(root);
JTree tree = new JTree(jMode);
下面就是添加數據之后,java中默認的樣式,
然后我們可以來改變數中的節點的圖片,以及打開,折疊的樣子:
DefaultTreeCellRenderer render=(DefaultTreeCellRenderer )tree.getCellRenderer();
//設置tree非葉子節折疊時的圖片;
render.setClosedIcon(new ImageIcon(this.getClass().getResource("Arrow_right.png")));
//設置tree非葉子節點展開時的圖片
render.setOpenIcon(new ImageIcon(this.getClass().getResource("right.png")));
//設置tree葉子節點的圖片
render.setLeafIcon(new ImageIcon(this.getClass().getResource("chat_32.png")));
如圖:
然后我們還可以來把前面的連接線給去掉:
tree.putClientProperty("JTree.lineStyle", "Horizontal");// 將樹設為水平分隔風格
如圖:
其他的一些基本設置:
tree.setFont(new Font(Font.SANS_SERIF, Font.LAYOUT_LEFT_TO_RIGHT, 18));
//字體的大小,樣式
tree.setRowHeight(50);//樹節點的高度
tree.setToggleClickCount(1); //設置展開節點之前的鼠標單擊數為1
//設置一次自能選中一個節點 tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
tree.setRootVisible(false);// 設置根節點為不可見;
如圖:
所以從上面我們可以看出來,JTree的是由TreeNode構成的;
JTree和JList一樣,都有一個Model以及TreeCellRenderer渲染器,樹用Model模型來管理TreeNode,然后TreeCellRenderer渲染器則是負責Tree的樣式。
我們也可以像JList一樣通過重寫來實現自定義的樹。但是這里JTree需要改寫的不是Model,而是TreeNode。
JTree,TreeModel,以及TreeNode,以及TreeCellRenderer:
在JTree中,每一個JTree由N個TreeNode構成,而TreeModel管理的是所有的TreeNode。TreeCellRenderer則是負責渲染每一個TreeNode。
TreeNode:在JTree中,可以說是負責數據的存儲。在默認的節點DefaultMutableTreeNode中,JTree上顯示的數據也就是文字是放的屬性userObject(是一個Object對象)中,在上面的例子中我們的userObject存放的就是String型的對象。
TreeMode:是模型,也就是說,他負責把所有的TreeNode給聯系起來。通過TreeMode我們可以知道,當前樹的總的節點數,以及是否為葉子節點等。
TreeCellRenderer:渲染器,JAVA提供的渲染器,一般是一個JLabel對象,然后實現了TreeCellRenderer接口。根據Model傳來的對象,進行包裝——把該對象轉換為String型然后顯示在JLable上面。在TreeCellRenderer渲染器中得到的Value的值是一個TreeNode對象,TreeCellRenderer渲染的是每一個TreeNode。
自定義好友列表:
1.實現TreeNode,在自定義好友列表的TreNode里面,需要顯示好友的名字(uName),以及個性簽名(text),然后是一個頭像(img),然后ID是用來唯一標示該節點,存儲的是好友的ID。然后是考慮到數型結構,會有孩子節點(可以有多個孩子所以為一個數組),以及父節點。
public class FriTreeNode implements TreeNode{
private String ID;//該節點的ID號
private ImageIcon img;//節點存放圖片
private String uName;//第一行文字(顯示名字)
private String text;//第二行文字(顯示簽名)
private ArrayList<TreeNode> children;//孩子節點
private TreeNode parent;//父親節點
public FriTreeNode(String ID) {
this.ID=ID;
}
public FriTreeNode() {
}
public FriTreeNode(String name,String text,ImageIcon img,String ID) {
this.uName=name;
this.text=text;
this.img=img;
this.ID=ID;
}
/**
* @return the iD
*/
public String getID() {
return ID;
}
/**
* @param iD the iD to set
*/
public void setID(String iD) {
ID = iD;
}
/**
* @return the uName
*/
public String getuName() {
return uName;
}
/**
* @param uName the uName to set
*/
public void setuName(String uName) {
this.uName = uName;
}
/**
* @param parent the parent to set
*/
public void setParent(FriTreeNode parent) {
this.parent = parent;
}
/**
* @return the img
*/
public ImageIcon getImg() {
return img;
}
/**
* @param img the img to set
*/
public void setImg(ImageIcon img) {
this.img = img;
}
/**
* @return the text
*/
public String getText() {
return text;
}
/**
* @param text the text to set
*/
public void setText(String text) {
this.text = text;
}
public void addchild(FriTreeNode aChild){
if(children==null){
children=new ArrayList<TreeNode>();
}
children.add(aChild);
aChild.parent=this;
}
/***
* 判斷是否為根節點
* @return
*/
public boolean isroot(){
return (getParent()==null);
}
@Override
public TreeNode getChildAt(int childIndex) {
if (children == null) {
throw new ArrayIndexOutOfBoundsException("node has no children");
}
return children.get(childIndex) ;
}
@Override
public int getChildCount() {
if (children == null) {
return -1 ;
}
return children.size();
}
@Override
public TreeNode getParent() {
return parent;
}
@Override
public int getIndex(TreeNode aChild) {
if (aChild == null) {
throw new IllegalArgumentException("argument is null");
}
if (!isNodeChild(aChild)) {
return -1;
}
return children.indexOf(aChild);
}
@Override
public boolean getAllowsChildren() {
return true;
}
/**
* 判斷是否是葉子節點
*/
@Override
public boolean isLeaf() {
return (getChildCount() ==-1)&&(getParent()!=null);
}
@SuppressWarnings("rawtypes")
@Override
public Enumeration children() {
return null;
}
public boolean isNodeChild(TreeNode aNode) {
boolean retval;
if (aNode == null) {
retval = false;
} else {
if (getChildCount() == 0) {
retval = false;
} else {
retval = (aNode.getParent() == this);
}
}
return retval;
}
}
2.實現 TreeCellRenderer,這里要注意區分一下好友節點以及根節點,還有好友分組節點的顯示是不一樣的,需要分別考慮。同時在JLable中的text屬性是不能換行的,所以使用了HTML來設置JLable的Text值。
public class FriTreeRender extends JLabel implements TreeCellRenderer {
ImageIcon Arrow_right = new ImageIcon(this.getClass().getResource("Arrow_right.png"));//節點折疊時的圖片
ImageIcon Arrow_down = new ImageIcon(this.getClass().getResource("Arrow_down.png"));//節點展開式的圖片
@Override
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean
expanded,boolean leaf, int row, boolean hasFocus) {
FriTreeNode f = (FriTreeNode) value;//把value轉換為節點
if (leaf && f.getParent() != tree.getModel().getRoot()) {//節點需要不為根節點,和根節點的孩子節點
/***************** 設置JLable的文字 ****************************/
String text = "<html>" + f.getuName() + "<br/>" + f.getText() + " <html/>";
setText(text);// 設置JLable的文字
/**************************** 設置JLable的圖片 *****************/
// 得到此圖標的 Image,然后創建此圖像的縮放版本。
Image img = f.getImg().getImage().getScaledInstance(50, 50, Image.SCALE_DEFAULT);
setIcon(new ImageIcon(img));// 設置JLable的圖片
setIconTextGap(15);// 設置JLable的圖片與文字之間的距離
} else { // 非葉子節點的文字為節點的ID
setText(f.getID());// 設置JLable的文字
if (expanded)//節點展開
setIcon(Arrow_down);
else
setIcon(Arrow_right);// 設置JLable的圖片
}
return this;
}
}
3.然后就是和上面的實例一樣去構建一個JTree了。
效果: