본문 바로가기

BackEnd/Java

[java]이것이 자바다 부록 Java UI 9 (Swing을 이용한 트리 컴포넌트)

728x90
반응형

1. 트리 컴포넌트

   ▷ 계층적인 데이터를 표시하는 컴포넌트, Swing은 트리 컴포넌트로 JTree를 제공

   ▷ 하나의 루트 노드 아래에 여러 개의 자식 노드를 가지며, 자식 노드는 또 다시 자식 노드를 가질 수 있음

   ▷ 동일한 부모 노드를 갖는 노드들을 묶어서 형제 노드라고 부르며, 자식 노드가 없는 마지막 노드는 잎사귀 노드(리프  노드)라고 함

 

(1) 트리 생성

   ▷ 생성자의 매개값으로 루트 노드를 대입해야 하는데, 루트 노드는 DefaultMutableTreeNode로 생성

   ▷ 부모 노드, 리프 노드를 생성하는데도 사용

 

◎ 기본적인 노드 모양 나타내는 예제

import java.awt.BorderLayout;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.tree.DefaultMutableTreeNode;

public class JTreeExample extends JFrame {
	private JTree jTree;
	
	public JTreeExample() {
		this.setTitle("JTreeExample");
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.getContentPane().add(new JScrollPane(getJTree()),
				BorderLayout.CENTER);
		this.setSize(200, 150);
	}
	
	// JTree 생성
	public JTree getJTree() {
		if(jTree == null) {
			DefaultMutableTreeNode root = new DefaultMutableTreeNode("그룹리스트");
			
			DefaultMutableTreeNode node1 = new DefaultMutableTreeNode("친구");
			node1.add(new DefaultMutableTreeNode("친구1"));
			node1.add(new DefaultMutableTreeNode("친구2"));
			root.add(node1);
			
			DefaultMutableTreeNode node2 = new DefaultMutableTreeNode("회사동료");
			node2.add(new DefaultMutableTreeNode("동료1"));
			node2.add(new DefaultMutableTreeNode("동료2"));
			root.add(node2);
			
			jTree = new JTree(root);			
		}
		return jTree;
	}

	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				JTreeExample jFram = new JTreeExample();
				jFram.setVisible(true);
			}
		});
	}
}

 


메신저와 유사한 형태로 만들 수 있습니다.

 

 

(2) 노드 표현 변경

   ▷ TreeCellRenderer를 만들어 기본 렌더러인 DefaultTreeCellRenderer를 대체해 노드 아이콘과 리프 노드 표현 변형

 

◎ getTreeCellRendererComponent() 메소드 매개변수

NO 매개변수 값 또는 참조
1 tree 노드를 포함하고 있는 JTree 참조
2 value 노드인 DefaultMutableTreeNode 객체
3 sel 노드가 선택되었는지 여부
4 expanded 부모 노드가 펼쳐졌는지 여부
5 leaf 리프 노드인지 여부
6 hasFocus 포커스를 가지고 있는지 여부

 

◎ 부모 노드의 아이콘 변경 및 리프 노드를 아이콘 + 글자+아이콘으로 표현하는 예제

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeCellRenderer;

public class JTreeExample2 extends JFrame {
	private JTree jTree;
	
	public JTreeExample2() {
		this.setTitle("JTreeExample2");
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.getContentPane().add(new JScrollPane(getJTree()),
				BorderLayout.CENTER);
		this.setSize(200, 150);
	}
	
	// JTree 생성
	public JTree getJTree() {
		if(jTree == null) {
			DefaultMutableTreeNode root = new DefaultMutableTreeNode("그룹리스트");
			
			DefaultMutableTreeNode node1 = new DefaultMutableTreeNode("친구");
			node1.add(new DefaultMutableTreeNode("친구1"));
			node1.add(new DefaultMutableTreeNode("친구2"));
			root.add(node1);
			
			DefaultMutableTreeNode node2 = new DefaultMutableTreeNode("회사동료");
			node2.add(new DefaultMutableTreeNode("동료1"));
			node2.add(new DefaultMutableTreeNode("동료2"));
			root.add(node2);
			
			jTree = new JTree(root);
			// 노드 표현 방법 변경
			jTree.setCellRenderer(new MyTreeCellRenderer());
		}
		return jTree;
	}
	
	// TreeCellRender 정의
	public class MyTreeCellRenderer implements TreeCellRenderer{
		public Component getTreeCellRendererComponent(
				JTree tree, Object value, boolean sel, boolean expanded,
				boolean leaf, int row, boolean hasFocus) {
					if(!leaf) {
						JLabel jLabel = new JLabel();
						jLabel.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
						jLabel.setIcon(new ImageIcon(getClass().getResource("parentnode.gif")));
						jLabel.setText(value.toString());
						return jLabel;
					} else {
						JPanel jPanel = new JPanel();
						jPanel.setBackground(Color.WHITE);
						jPanel.setLayout(new BorderLayout());
						jPanel.setBorder(BorderFactory.createEmptyBorder(3,0,3,0));
						// 노드 간 상하 간격
						
						JLabel lblWest = new JLabel(new ImageIcon(getClass().
								getResource("logon.gif")));
						JLabel lblCenter = new JLabel(" " + value.toString()+" ");
						JLabel lblEast = new JLabel(new ImageIcon(getClass().
								getResource("time.gif")));
						jPanel.add(lblWest, BorderLayout.WEST);
						jPanel.add(lblCenter, BorderLayout.CENTER);
						jPanel.add(lblEast, BorderLayout.EAST);
						
						if(sel) {
							// 노드 선택시 오렌지 배경색 설정
							jPanel.setBackground(Color.ORANGE);
						}
						return jPanel;
					}
			}
	}

	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				JTreeExample2 jFram = new JTreeExample2();
				jFram.setVisible(true);
			}
		});
	}
}

 

 

(3) 이벤트 처리

   ▷ 노드 선택이 변경되면 TreeSelectionEvent가 발생하기 때문에 TreeSelectionListener 를 추가해서 이벤트를 처리함

   ▷ TreeSelectionListener의 valueChanged() 메소드는 노드 선택이 변경되면 호출됨

 

◎ 노드 선택 및 더블클릭시 텍스트 이벤트 표시 예시

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseListener;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreePath;

public class JTreeExample3 extends JFrame {
	private JTree jTree;
	
	public JTreeExample3() {
		this.setTitle("JTreeExample3");
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.getContentPane().add(new JScrollPane(getJTree()),
				BorderLayout.CENTER);
		this.setSize(200, 150);
	}
	
	// JTree 생성
	public JTree getJTree() {
		if(jTree == null) {
			DefaultMutableTreeNode root = new DefaultMutableTreeNode("그룹리스트");
			
			DefaultMutableTreeNode node1 = new DefaultMutableTreeNode("친구");
			node1.add(new DefaultMutableTreeNode("친구1"));
			node1.add(new DefaultMutableTreeNode("친구2"));
			root.add(node1);
			
			jTree = new JTree(root);
			jTree.setCellRenderer(new MyTreeCellRenderer());
			jTree.addTreeSelectionListener(treeSelectionListener);
			jTree.addMouseListener(mouseListener);
			
			DefaultMutableTreeNode node2 = new DefaultMutableTreeNode("회사동료");
			node2.add(new DefaultMutableTreeNode("동료1"));
			node2.add(new DefaultMutableTreeNode("동료2"));
			root.add(node2);
			
		}
		return jTree;
	}
	
	// TreeSelectionListener 필드 선언
	private TreeSelectionListener treeSelectionListener = 
			new TreeSelectionListener() {
		@Override
		public void valueChanged(TreeSelectionEvent e) {
			// 사용자가 선택한 경로의 전체 경로
			TreePath treePath = e.getPath();
			DefaultMutableTreeNode treeNode =
					(DefaultMutableTreeNode) treePath.getLastPathComponent();
			// 사용자가 선택한 경로의 Value 값 반환
			String nodeText = (String) treeNode.getUserObject();
			JOptionPane.showMessageDialog(JTreeExample3.this, "노드 변경: " +
			nodeText);
		}
	};
	
	// MouseListener 필드 선언
	private MouseListener mouseListener = new MouseAdapter() {
		public void mouseClicked(java.awt.event.MouseEvent e) {
			// 더블 클릭이 되었을 경우에만 실행
			if(e.getClickCount() == 2) {
				TreePath treePath = jTree.getPathForLocation(e.getX(), e.getY());
				DefaultMutableTreeNode treeNode =
						(DefaultMutableTreeNode) treePath.getLastPathComponent();
				String nodeText = (String) treeNode.getUserObject();
				JOptionPane.showMessageDialog(JTreeExample3.this, "더블 클릭: " +
				nodeText);
			}
		};
	};
		
	// TreeCellRender 정의
	public class MyTreeCellRenderer implements TreeCellRenderer{
		public Component getTreeCellRendererComponent(
				JTree tree, Object value, boolean sel, boolean expanded,
				boolean leaf, int row, boolean hasFocus) {
					if(!leaf) {
						JLabel jLabel = new JLabel();
						jLabel.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
						jLabel.setIcon(new ImageIcon(getClass().getResource("parentnode.gif")));
						jLabel.setText(value.toString());
						return jLabel;
					} else {
						JPanel jPanel = new JPanel();
						jPanel.setBackground(Color.WHITE);
						jPanel.setLayout(new BorderLayout());
						jPanel.setBorder(BorderFactory.createEmptyBorder(3,0,3,0));
						// 노드 간 상하 간격
						
						JLabel lblWest = new JLabel(new ImageIcon(getClass().
								getResource("logon.gif")));
						JLabel lblCenter = new JLabel(" " + value.toString()+" ");
						JLabel lblEast = new JLabel(new ImageIcon(getClass().
								getResource("time.gif")));
						jPanel.add(lblWest, BorderLayout.WEST);
						jPanel.add(lblCenter, BorderLayout.CENTER);
						jPanel.add(lblEast, BorderLayout.EAST);
						
						if(sel) {
							// 노드 선택시 오렌지 배경색 설정
							jPanel.setBackground(Color.ORANGE);
						}
						return jPanel;
					}
			}
	}

	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				JTreeExample3 jFram = new JTreeExample3();
				jFram.setVisible(true);
			}
		});
	}
}

 

 

JTree을 이용해 그룹을 만들어 펼치거나 접게 만들었습니다.

 

JTree를 이용하니 회사 사내 메신저나 옛날에 사용했던 네이트온 같은 모습이 나타나네요!!

 

더 많은 기능들에 대해서 배워볼게요~!!

 

많은 분들의 피드백은 언제나 환영합니다!  많은 댓글 부탁드려요~~

 

728x90
반응형