트리 컴포넌트
트리 컴포넌트는 계층적인 데이터를 표시하는 컴포넌트이다.
Swing은 트리 컴포넌트로 JTree를 제공한다. JTree는 하나의 루트 노드(root node) 아래에 여러 개의 자식 노드(child node)를 가지며, 자식 노 드는 또 다시 자식 노드를 가질 수 있다.
동일한 부모 노드parent node를 갖는 노드들을 묶어서 형제 노드sibling node라고 부르는데,
다음 그림에서 친구1과 친구2는 형제 노드이다. 자식 노드가 없는 마지막 노드는 잎사귀 노드라고 해서 리프(leaf) 노드라고 부른다.
트리 생성
JTree를 생성하려면 생성자의 매개값으로 루트 노드를 대입해야 하는데, 루트 노드는 DefaultMutableTreeNode로 생성한다.
DefaultMutableTreeNode는 루트 노드뿐만 아니라 부모 노드, 리프 노드를 생성하는 데 사용된다
DefaultMutableTreeNode로 생성된 계층적 데이터를 JTree를 생성할 때 매개값으로 제 공해야 함을 보여준다.
기본적인 노드의 모양 출력 방법
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 jFrame = new JTreeExample();
jFrame.setVisible(true);
}
});
}
}
- 실행 결과 -
노드 표현 변경
노드의 아이콘과 리프 노드의 표현을 다르게 변형하고 싶다면 새로운 TreeCellRenderer를 만들어 기본 렌더러인 DefaultTreeCellRenderer를 대체하면 된다.
새로운 TreeCellRenderer는 TreeCellRenderer 인터페이스를 구현해서 만든다.
public class MyTreeCellRenderer implements TreeCellRenderer {
public Component getTreeCellRendererComponent(...) {
//컴포넌트를 초기화하고 리턴하는 코드
}
}
getTreeCellRendererComponent() 메소드는 주어진 매개값을 이용해서 노드를 표현할 컴포넌트를 리턴하는 역할을 한다.
매개변수 | 값 또는 참조 |
tree | 노드를 포함하고 있는 JTree 참 |
value | 노드인 DefaultMutableTreeNode 객체 |
sel | 노드가 선택되었는지 여부 |
expanded | 부모 노드가 펼쳐졌는지 여부 |
leaf | 리프 노드인지 여부 |
hasFocus | 포커스를 가지고 있는지 여부 |
TreeCellRenderer가 정의되었다면 JTree의 setCellRenderer() 메소드로 기본 렌더러를 변경하면 된다
jTree.setCellRenderer(new MyTreeCellRenderer());
부모 노드의 아이콘을 변경하고 리프 노드를 아이콘+글자+아이콘으로 표현 방법
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;
}
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();
// 상, 우, 하, 좌: 상, 하에 간격 : 5
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));
//노드 간 상하 간격 : 3
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 jFrame = new JTreeExample2();
jFrame.setVisible(true);
}
});
}
}
- 실행 결과 -
이벤트 처리
JTree에서 노드 선택이 변경되면 TreeSelectionEvent가 발생하기 때문에 TreeSelectionListener를 추가해서 이벤트를 처리할 수 있다
TreeSelectionListener의 valueChanged() 메소드는 노 드 선택이 변경되면 호출된다
TreeSelectionListener 구현 클래스를 작성하는 방법
public class MyTreeSelectionListener implements TreeSelectionListener {
public void valueChanged(TreeSelectionEvent e) {
//선택된 노드의 전체 경로 얻기
TreePath treePath = e.getPath();
//선택된 노드의 DefaultMutableTreeNode 얻기
DefaultMutableTreeNode node =
(DefaultMutableTreeNode) treePath.getLastPathComponent();
//선택된 노드의 텍스트 얻기
String userObject = (String) node.getUserObject();
//처리 코드
//~
}
}
TreeSelectionEvent의 getPath()는 루트 노드에서부터 선택된 노드까지의 경로 정보를 가지고 있는 TreePath를 리턴한다.
TreePath의 getLastPathComponent()는 선택된 노드를 Object 타입으로 리턴하는데, DefaultMutableTreeNode로 타입 변환할 수 있다.
선택된 노드의 문자열은 DefaultMutableTreeNode의 getUserObject() 메소드로 얻을 수 있다.
만약 노드 선택 변경보다는 클릭과 더블 클릭에 더 관심이 있다면 다음과 같이 MouseEvent를 처리할 수도 있다
public class MyMouseListener extends MouseAdapter {
public void mousePressed(MouseEvent e) {
//JTree 얻기
JTree jTree = (JTree) e.getSource();
//선택된 노드의 전체 경로 얻기
TreePath treePath = jTree.getPathForLocation(e.getX(), e.getY());
//선택된 노드가 있을 경우
if(selRow !=-1) {
if(e.getClickCount() = = 1) {
//클릭했을 경우 실행할 코드
} else if(e.getClickCount() = = 2) {
//더블 클릭했을 경우 실행할 코드
}
}
}
}
JTree의 getPathForLocation() 메소드는 마우스로 클릭된 좌표를 가지고 선택된 노드의 전 체 경로를 가진 TreePath를 리턴한다.
마우스를 클릭했느냐 더블 클릭했느냐는 MouseEvent의 getClickCount()의 리턴값으로 구분할 수 있으므로 if 문으로 실행할 코드를 선택할 수 있다.
TreeSelectionListener를 추가해서 선택 노드의 텍스트를 메시지 다이얼로그로 나타 내고, MouseListener를 추가해서 마우스 더블 클릭을 처리 방법
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);
}
return jTree;
}
// TreeSelectionListener 필드선언
private TreeSelectionListener treeSelectionListener = new TreeSelectionListener() {
@Override
public void valueChanged(TreeSelectionEvent e) {
TreePath treePath = e.getPath(); // 사용자가 선택한 경로의 전체 경로
DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) treePath.getLastPathComponent();
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);
}
};
};
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();
// 상, 우, 하, 좌: 상, 하에 간격 : 5
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));
//노드 간 상하 간격 : 3
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 jFrame = new JTreeExample3();
jFrame.setVisible(true);
}
});
}
}
- 실행 결과 -
![]() |
![]() |
'자바' 카테고리의 다른 글
자바 UI - Swing (툴바 컴포넌트) (0) | 2023.02.20 |
---|---|
자바 UI - Swing (메뉴 컴포넌트) (0) | 2023.02.17 |
자바 UI - Swing (테이블 컴포넌트) (0) | 2023.02.17 |
자바 UI - Swing (리스트 컴포넌트) (0) | 2023.02.17 |
자바 UI - Swing (채팅창 텍스트 입력 후 내용을 엔터키 누르고 전송) (2) | 2023.02.16 |