테이블 컴포넌트
JTable은 테이블 형식의 데이터를 표시하고 편집할 수 있는 컴포넌트이다.
JTable은 다른 컴포넌트에 비해서 다소 복잡한 구조로 이루어져 있다
- 테이블은 컬럼(column)과 행(row)으로 구성되어 있고, 컬럼과 행이 만나는 곳이 셀(cell)이다.
- 셀은 실제 데이터가 표시되는 곳이다.
- 하나의 컬럼을 구성하는 셀들은 동일한 데이터 타입을 가져야 한다
테이블 생성
간단한 JTable 객체를 만들기 위해서는 먼저 컬럼 이름을 포함하고 있는 1차원 String 배열과 셀의 데이터인 2차원 Object 배열을 생성해야 한다. 그리고 이들을 JTable 생성자를 호출할 때 매개 값 으로 넘겨준다
이름과 나이 컬럼으로 구성된 테이블을 생성하는 방법
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
public class JTableExample extends JFrame {
private JTable jTable;
public JTableExample() {
this.setTitle("JTableExample");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.getContentPane().add(new JScrollPane(getJTable()),BorderLayout.CENTER);
this.setSize(200, 125);
}
public JTable getJTable() {
if(jTable == null) {
String[] columnNames = { "이름", "나이" };
Object[][] rowData = {
{ "춘삼월", 25 },
{ "하여름", 23 },
{ "하바다", 26 },
{ "추가을", 22 },
{ "동겨울", 27 },
{ "동장군", 15 }
};
jTable = new JTable(rowData, columnNames);
jTable.getColumn("이름").setPreferredWidth(100);
jTable.getColumn("나이").setPreferredWidth(50);
}
return jTable;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JTableExample jFrame = new JTableExample();
jFrame.setVisible(true);
}
});
}
}
- 실행 결과 -
테이블 모델
JTable은 TableModel 객체를 사용해서 컬럼과 셀의 데이터를 관리한다.
JTable을 생성할 때 컬럼 이름인 1차원 String 배열과 셀의 데이터인 2차원 Object 배열을 생성자로 넘겨주면, TableModel 이 내부적으로 생성되고 이 데이터들을 관리하게 된다.
JTable은 내부적으로 생성된 TableModel을 프로그램에서 사용할 수 있도록 getModel() 메소 드를 제공
TableModel tableModel = jTable.getModel();
TableModel에는 다음과 같이 데이터에 대한 여러 가지 정보를 제공하는 메소드들
메소드 | 용도 | |
int | getColumnCount() | 총 컬럼의 수 얻기 |
String | getColumnName(int columnIndex | 컬럼의 이름 얻기 |
int | getRowCount() | 총 행의 수 얻기 |
Object | getValueAt(int rowIndex, int columnIndex) | 셀의 데이터 얻기 |
void | setValueAt(Object aValue, int rowIndex, int columnIndex | 셀의 데이터 변경 |
void | setDataVector(Object[ ][ ] rows, Object[ ] columnNames) setDataVector(Vector rows, Vector columnNames); |
전체 테이블 데이터를 주어진 매개값으로 대체 |
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.TableModel;
public class JTableExample2 extends JFrame {
private JTable jTable;
private JButton btnInfo;
public JTableExample2() {
this.setTitle("JTableExample2");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.getContentPane().add(new JScrollPane(getJTable()),BorderLayout.CENTER);
this.getContentPane().add(getBtnInfo(), BorderLayout.SOUTH);
this.setSize(200, 200);
}
public JTable getJTable() {
if(jTable == null) {
String[] columnNames = {"이름", "나이"};
Object[][] rowData = {
{"춘삼월", 25},
{"하여름", 23}
};
jTable = new JTable(rowData, columnNames);
}
return jTable;
}
public JButton getBtnInfo() {
if(btnInfo == null) {
btnInfo = new JButton();
btnInfo.setText("테이블 정보 출력");
btnInfo.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// 테이블 모델 얻기
TableModel tableModel = getJTable().getModel();
// 전체 컬럼 수 얻기
int columnCount = tableModel.getColumnCount();
// 전체 행수 얻기
int rowCount = tableModel.getRowCount();
// 컬럼 이름 출력
for(int i=0; i<columnCount; i++) {
String columnName = tableModel.getColumnName(i);
System.out.println(columnName + "\t\t");
}
System.out.println();
System.out.println("------------------------");
// 테이블의 데이터 출력 : 행 단위로 출력
for(int i=0; i<rowCount; i++) {
String column0 = (String) tableModel.getValueAt(i, 0);
Integer column1 = (Integer) tableModel.getValueAt(i, 1);
System.out.println(column0 + "\t\t" + column1);
}
// 1행 셀 데이터 변경
tableModel.setValueAt("개나리", 0, 0);
tableModel.setValueAt(20, 0, 1);
}
});
}
return btnInfo;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JTableExample2 jFrame = new JTableExample2();
jFrame.setVisible(true);
}
});
}
}
- 실행 결과 -
셀 표현 변경
컬럼 헤더와 셀 텍스트 내용을 수평 정렬하거나 셀 내용으로 다양한 컴포넌트를 넣고 싶다면 새로운 셀 렌더러를 정의해야 한다.
셀 렌더러는 넣고 싶은 컴포넌트를 상속하고 TableCellRenderer 인터페이스를 구현해서 만든다
public class MyTableCellRenderer extends 컴포넌트 implements TableCellRenderer {
public Component getTableCellRendererComponent(...) {
//컴포넌트를 초기화하고 반환하는 코드
return this;
}
};
getTableCellRendererComponent() 메소드는 상속받은 컴포넌트를 매개값으로 초기화하고 리턴해야 한다.
getTableCellRendererComponent() 메소드의 매개변수
매개변수 | 값 또는 참조 |
table | 셀을 포함하고 있는 JTable |
value | 셀에 표시될 데이터 |
isSelected | 셀을 포함하고 있는 행이 선택 되었는지 여부 |
hasFocus | 셀에 포커스가 있는지 여부 |
row | 셀을 포함하고 있는 행의 순번 |
column | 셀을 포함하고 있는 컬럼의 순번 |
새로운 셀 렌더러가 정의되었다면 TableColumn의 setHeaderRenderer ( ) 또는 setCellRenderer() 메소드로 헤더와 셀 렌더러를 변경하면 된다.
TableColumn tc = jTable.getColumn("컬럼 이름");
TableCellRenderer tc = new new MyTableCellRenderer();
//헤더 모양 변경
tableColumn.setHeaderRenderer(tc);
//셀 모양 변경
tableColumn. setCellRenderer(tc);
첫 번째 컬럼에 텍스트를 중앙 정렬한 JLabel을 넣었고,
두 번째 컬럼에 이미지와 텍스 트가 포함된 JLabel을,
세 번째 컬럼에는 JCheckBox를 넣었다. 그리고 마우스로 행을 선택하면 노란색 배경으로 변경 방법
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import javax.swing.ImageIcon;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
public class JTableExample3 extends JFrame {
private JTable jTable;
public JTableExample3() {
this.setTitle("JTableExample3");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.getContentPane().add(new JScrollPane(getJTable()), BorderLayout.CENTER);
this.setSize(200, 125);
}
// 테이블 생성
public JTable getJTable() {
if(jTable == null) {
String[] columnNames = {"이름", "나이", "선택"};
Object[][] rowData = {
{ "춘삼월", 25, false },
{ "하여름", 26, true },
{ "추가을", 22, false },
{ "동겨울", 27, true }
};
jTable = new JTable(rowData, columnNames);
// 각 컬럼의 셀 렌더러 변경
TableColumn tcName = jTable.getColumn("이름");
tcName.setCellRenderer(new NameTableCellRenderer());
TableColumn tcAge = jTable.getColumn("나이");
tcAge.setCellRenderer(new AgeTableCellRenderer());
TableColumn tcSelect = jTable.getColumn("선택");
tcSelect.setCellRenderer(new SelectTableCellRenderer());
}
return jTable;
}
// 이름 컬럼의 셀 렌더러 정의
public class NameTableCellRenderer extends JLabel implements TableCellRenderer {
public Component getTableCellRendererComponent( JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
setText(value.toString());
setFont(new Font(null, Font.PLAIN,12)); // 폰트의 글씨 크기 12
setHorizontalAlignment(JLabel.CENTER); // 중앙 정렬
setOpaque(true); // JLabel의 배경을 불투명하게 설정
if(isSelected) { // 선택된 행의 색상을 변경
setBackground(Color.YELLOW); // 선택되면 노란색
} else {
setBackground(Color.WHITE); // 선택되지 않았다면 흰색
}
return this;
}
}
// 나이 컬럼의 셀 렌더러 정의
public class AgeTableCellRenderer extends JLabel implements TableCellRenderer {
public Component getTableCellRendererComponent ( JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
int age = ((Integer) value).intValue();
if(age <= 25) {
setIcon(new ImageIcon(getClass().getResource("key.gif")));
} else {
setIcon(new ImageIcon(getClass().getResource("start.gif")));
}
setText(value.toString());
setFont(new Font(null, Font.PLAIN, 12)); // 폰트의 글씨 크기 12
setHorizontalAlignment(JLabel.CENTER); // 중앙 정렬
setOpaque(true); //JLabel의 배경을 불투명하게 설정
if (isSelected) { // 선택된 행의 색상을 변경
setBackground(Color.YELLOW); // 선택되면 노란색
} else {
setBackground(Color.WHITE); // 선택되지 않았다면 흰색
}
return this;
}
}
//선택 컬럼의 셀 렌더러 정의
public class SelectTableCellRenderer extends JCheckBox implements TableCellRenderer {
public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected, boolean hasFocus,
int row, int column) {
Boolean boolWrapper = (Boolean) value; // 값을 그대로 입력
setSelected(boolWrapper.booleanValue());
setHorizontalAlignment(CENTER); // 중앙 정렬
if (isSelected) { // 선택된 행의 색상을 변경
setBackground(Color.YELLOW); // 선택되면 노란색
} else {
setBackground(Color.WHITE); // 선택되지 않았다면 흰색
}
return this;
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JTableExample3 jFrame = new JTableExample3();
jFrame.setVisible(true);
}
});
}
}
- 실행 결과 -
이벤트 처리
JTable은 MouseEvent가 발생하므로 MouseListener를 등록해서 이벤트를 처리할 수 있다.
MouseEvent에서 getSelectedColumn()과 getSelectedRow() 메소드를 이용하면 어떤 컬럼과 행에서 클릭되었는지 알아낼 수 있다.
jTable.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
int rowIndex = jTable.getSelectedRow();
int columnIndex = jTable.getSelectedColumn();
if(rowIndex !=-1 || columnIndex != -1) {
//이벤트 처리 코드
}
}
});
사용자가 행을 선택하면 행의 데이터를 읽고 이름과 나이를 JTextField에 표시 방법
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.table.TableModel;
public class JTableExample4 extends JFrame {
private JTable jTable;
private JPanel pSouth;
private JTextField txtName;
private JTextField txtAge;
private Object[][] rowData;
//메인 윈도우 설정
public JTableExample4() {
this.setTitle("JTableExample4");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.getContentPane().add(new JScrollPane(getJTable()), BorderLayout.CENTER);
this.getContentPane().add(getPSouth(), BorderLayout.SOUTH);
this.setSize(200, 230);
}
//JTable 생성
public JTable getJTable() {
if(jTable == null) {
String[] columnNames = new String[] {"이름", "나이" };
rowData = new Object[][] {
{ "춘삼월", 25 },
{ "하여름", 23 },
{ "추가을", 22 },
{ "동겨울", 27 }
};
jTable = new JTable(rowData, columnNames);
//MouseEvent 처리
jTable.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
int rowIndex = jTable.getSelectedRow();
if(rowIndex !=-1) { // -1이 아니면 선택한 행이 있다.
// 선택한 행의 셀값 읽어 들이기
TableModel tableModel = jTable.getModel();
String name = (String) tableModel.getValueAt(rowIndex, 0);
Integer age = (Integer) tableModel.getValueAt(rowIndex, 1);
//읽은 값을 아래쪽에 있는 JPanel에서 보여주기
getTxtName().setText(name);
getTxtAge().setText(String.valueOf(age.intValue()));
}
}
});
}
return jTable;
}
//하단에 위치할 JPanel 생성
public JPanel getPSouth() {
if(pSouth == null) {
pSouth = new JPanel();
pSouth.setLayout(new GridLayout(4,2));
pSouth.add(new JLabel("[선택한 행 정보]"));
pSouth.add(new JLabel(""));
pSouth.add(new JLabel("이름", JLabel.CENTER));
pSouth.add(getTxtName());
pSouth.add(new JLabel("나이", JLabel.CENTER));
pSouth.add(getTxtAge());
}
return pSouth;
}
public JTextField getTxtName() {
if(txtName == null) {
txtName = new JTextField();
}
return txtName;
}
public JTextField getTxtAge() {
if(txtAge == null) {
txtAge = new JTextField();
}
return txtAge;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JTableExample4 jFrame = new JTableExample4();
jFrame.setVisible(true);
}
});
}
}
- 실행 결과 -
행 추가, 수정, 삭제
TableModel 타입은 JTable이 어떤 생성자로 만들어졌는지에 따라 다르다.
AbstractTableModel과 DefaultTableModel의 차이점은
DefaultTableModel은 행을 추가, 삽입, 삭제할 수 있는 다음 메소드 들이 추가적으로 제공된다는 점이다.
메소드 | 용도 | |
void | addRow(Object[] rowData ) addRow(Vector rowData) |
맨 뒤에 행 추가 |
void | insertRow(int rowIndex, Object[] rowData) insertRow(int rowIndex, Vector rowData |
주어진 인덱스에 행 삽입 |
void | removeRow(int rowIndex) | 주어진 인덱스의 행 삭제 |
메소드들을 이용하려면 JTable() 생성자로 JTable을 생성하고, getModel() 메소드가 리턴하 는 TableModel을 DefaultTableModel로 변환해야 한다.
사용자가 입력한 내용을 JTable의 행으로 넣는다. 그리고 선택된 행의 데이터를 수정 하고 삭제할 수 있는 방법
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Vector;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
public class JTableExample5 extends JFrame {
private JTable jTable;
private JPanel pSouth;
private JTextField txtName, txtAge;
private JButton btnInsert, btnUpdate, btnDelete;
public JTableExample5 () {
this.setTitle("JTableExample5");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.getContentPane().add(new JScrollPane(getJTable()),BorderLayout.CENTER);
this.getContentPane().add(getPSouth(), BorderLayout.SOUTH);
this.setSize(250, 250);
}
public JTable getJTable() {
if (jTable == null) {
jTable = new JTable();
final DefaultTableModel tableModel = (DefaultTableModel) jTable.getModel();
tableModel.addColumn("이름");
tableModel.addColumn("나이");
// 행을 선택했을 때 이벤트 처리
jTable.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
int rowIndex = jTable.getSelectedRow();
if(rowIndex != -1) {
String name = (String) tableModel.getValueAt(rowIndex, 0);
String age = (String) tableModel.getValueAt(rowIndex, 1);
txtName.setText(name);
txtAge.setText(age.toString());
}
}
});
}
return jTable;
}
// 사용자 입력 JPanel 생성
public JPanel getPSouth() {
if (pSouth == null) {
pSouth = new JPanel();
pSouth.setLayout(new GridLayout(3, 1));
// 이름 텍스트 필더
JPanel pNameInput = new JPanel();
pNameInput.setLayout(new GridLayout(1, 2));
pNameInput.add(new JLabel("이름", JLabel.CENTER)); // 이름 표시
pNameInput.add(getTxtName()); // 이름을 수정, 삽입
pSouth.add(pNameInput);
// 나이 텍스트 필더
JPanel pAgeInput = new JPanel();
pAgeInput.setLayout(new GridLayout(1, 2));
pAgeInput.add(new JLabel("나이", JLabel.CENTER)); // 나이 표시
pAgeInput.add(getTxtAge()); // 나이를 수정, 삽입
pSouth.add(pAgeInput);
// 버튼(삽입, 수정, 삭제)
JPanel pButton = new JPanel();
pButton.add(getBtnInsert()); // 삽입
pButton.add(getBtnUpdate()); // 수정
pButton.add(getBtnDelete()); // 삭제
pSouth.add(pButton);
}
return pSouth;
}
// 이름 텍스트필드
public JTextField getTxtName() {
if(txtName == null) {
txtName = new JTextField();
}
return txtName;
}
// 나이 텍스트필드
public JTextField getTxtAge() {
if(txtAge == null) {
txtAge = new JTextField();
}
return txtAge;
}
// 행 삽입 버튼 생성
public JButton getBtnInsert() {
if(btnInsert == null) {
btnInsert = new JButton();
btnInsert.setText("추가");
// 텍스트필드 이름, 나이를 위에 테이블 마지막에 추가
btnInsert.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Object[] rowData = { txtName.getText(), txtAge.getText() };
// 테이블 모델을 디폴트테이블모델로 형 변환
DefaultTableModel tableModel = (DefaultTableModel)getJTable().getModel();
// 형 변환된 테이블 마지막에 텍스트필드 안에 있는 데이터를 삽입
tableModel.addRow(rowData);
// 텍스트 필드 내용을 초기화(비워두기)
txtName.setText("");
txtAge.setText("");
}
});
}
return btnInsert;
}
//행 수정 버튼 생성
public JButton getBtnUpdate() {
if (btnUpdate == null) {
btnUpdate = new JButton();
btnUpdate.setText("수정");
// 텍스트 필드에 수정한 내용을 선택한 행에 적용
btnUpdate.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// 테이블 모델을 디폴트테이블 모델로 형 변환
DefaultTableModel tableModel = (DefaultTableModel) getJTable().getModel();
// 전체 행의 정보를 rows에 담기
Vector<Vector> rows = tableModel.getDataVector();
// 사용자가 선택한 행의 정보를 row에 담기
Vector row = rows.elementAt(jTable.getSelectedRow());
// row의 첫번째 칼럼 수정 (이름)
row.set(0, txtName.getText());
// row의 첫번째 칼럼 수정 (나이)
row.set(1, txtAge.getText());
// 테이블에 수정된 내용 적용
tableModel.fireTableDataChanged();
// 텍스트 필드 내용을 초기화(비워두기)
txtName.setText("");
txtAge.setText("");
}
});
}
return btnUpdate;
}
//행 삭제 버튼 생성
public JButton getBtnDelete() {
if (btnDelete == null) {
btnDelete = new JButton();
btnDelete.setText("삭제");
// 텍스트 필드에 수정한 내용을 선택한 행에 적용
btnDelete.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// 사용자가 몇번째 행을 선택 확인
int rowIndex = getJTable().getSelectedRow();
if (rowIndex != -1) {
// 테이블 모델을 디폴트 테이블 모델로 형 변환
DefaultTableModel tableModel = (DefaultTableModel) getJTable().getModel();
tableModel.removeRow(rowIndex);
txtName.setText("");
txtAge.setText("");
}
}
});
}
return btnDelete;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JTableExample5 jFrame = new JTableExample5();
jFrame.setVisible(true);
}
});
}
}
- 실행 결과 -
'자바' 카테고리의 다른 글
자바 UI - Swing (메뉴 컴포넌트) (0) | 2023.02.17 |
---|---|
자바 UI - Swing (트리 컴포넌트) (0) | 2023.02.17 |
자바 UI - Swing (리스트 컴포넌트) (0) | 2023.02.17 |
자바 UI - Swing (채팅창 텍스트 입력 후 내용을 엔터키 누르고 전송) (2) | 2023.02.16 |
자바 UI - 04) Swing (텍스트 컴포넌트) (0) | 2023.02.16 |