JTable
엑셀과 같이 행과 열이 존재하여 표의 형태로 자료를 편집하고 관리할 수 있는 Swing 컴포넌트가 JTable입니다. 행과 열이 만나는 곳이 셀이라고 하며 각 행들은 보통 레코드라고 부릅니다. JTable도 JList와 같이 단일 선택 모드와 다중 선택 모드가 있는데 여기서는 단일 선택 모드를 설명하도록 하겠습니다.
다중 선택모드는 JList와 매우 흡사하므로 아래의 JList를 다루는 포스팅을 참고하시면 될겁니다.
그래서 아래의 프로그램을 구현해보면서 JTable이 어떻게 동작하는지 확인해보도록 합시다.
위의 프로그램은 아래와 같이 동작합니다.
1. 추가 - 이름, 나이, 성별, 3개의 점수를 JTextField로 입력받아서 Table에 추가가 됩니다.
2. 삭제 - 선택된 레코드가 있다면 그 레코드를 JTable에서 삭제하며, 없으면 가장 위쪽(가장 먼저 추가된)의 레코드를 삭제합니다.
3. 읽기 - 셀이 선택되면 시스템 Output에 단순 출력합니다.
구현
1. 기본 설정
우선 JFrame을 상속받아 기본 세팅을 진행해보도록 합시다. 여기서는 레이아웃의 배치와 JTable을 초기화, 각 버튼, 텍스트 필드의 이벤트 설정등을 생성자에서 구현하게 됩니다.
public class JTableTest extends JFrame implements MouseListener,KeyListener {
private final String[] labels= {"Name","Age","Sex","Korean","English","Math"};
private JTextField []fields=new JTextField[6];
private JScrollPane scrolledTable;
private JTable table;
private JButton addBtn;
private JButton delBtn;
public JTableTest(String title) {
this.setLayout(new BorderLayout(10,10));
JPanel topPanel=new JPanel(new GridLayout(6,4,10,5));
for(int i=0;i<6;i++) {
topPanel.add(new JLabel(labels[i]));
fields[i]=new JTextField(30);
topPanel.add(fields[i]);
}
topPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
this.add("North",topPanel); //가장 위쪽 Panel 설정
String header[]= {"Name","Age","Sex","Korean","English","Math"};
DefaultTableModel model=new DefaultTableModel(header,0); //header추가, 행은 0개 지정
table=new JTable(model);
table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
scrolledTable=new JScrollPane(table); //스크롤 될 수 있도록 JScrollPane 적용
scrolledTable.setBorder(BorderFactory.createEmptyBorder(10,10,10,10)); //너무 붙어있어서 가장자리 띄움(padding)
this.add("Center",scrolledTable); //가운데에 JTable 추가
JPanel rightPanel=new JPanel(new GridLayout(5,1,10,10));
addBtn=new JButton("레코드 추가");
delBtn=new JButton("레코드 삭제");
rightPanel.add(addBtn);
rightPanel.add(delBtn);
rightPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
this.add("East",rightPanel); //오른쪽에 버튼들 추가
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(620,400);
this.setLocationRelativeTo(null); //창 가운데 위치
this.setVisible(true);
//이벤트 추가
addBtn.addMouseListener(this); //추가 처리
delBtn.addMouseListener(this); //삭제 처리
for(int i=0;i<6;i++)
fields[i].addKeyListener(this); //엔터 처리
table.addMouseListener(this); //셀 읽기 처리
}
@Override
public void mousePressed(MouseEvent e) {}
@Override
public void mouseReleased(MouseEvent e) {}
@Override
public void mouseEntered(MouseEvent e) {}
@Override
public void mouseExited(MouseEvent e) {}
//KeyListener Overrides
@Override
public void keyTyped(KeyEvent e) {}
@Override
public void keyPressed(KeyEvent e) {}
@Override
public void keyReleased(KeyEvent e) {
}
}
JTable은 DefaultTableModel으로 테이블의 데이터를 추가, 삭제할 수 있습니다. 그래서 DefaultTableModel을 생성한 다음 JTable 생성자로 넘겨줍니다. DefaultTableModel의 생성자는 여러가지가 있는데, 여기서는 header만 있고 맨 처음 상태에서는 아무런 레코드가 없는 상태이기 때문에 row count=0으로 지정하여 생성합니다.
그리고 JTable이 Record가 넘쳐날 경우 잘리지 않게 JScrollPane으로 스크롤 가능하게 만들어준 점도 주목해주세요.
2. 추가 구현 - addRecord()
조금 전 DefaultTableModel을 통해서 레코드를 추가하는 것이 가능합니다. 우선 JTable에 아까 전달한 DefaultTableModel을 얻어온 다음 addRow() 메소드를 통해 추가가 가능합니다. addRow()는 Object 배열을 받을 수 있도록 구현이 되어있는데, 우리는 입력받는 TextField의 텍스트를 String 배열로 넘겨줄 것입니다.
public void addRecord() {
DefaultTableModel model=(DefaultTableModel)table.getModel();
String []record=new String[6];
for(int i=0;i<6;i++) {
if(isInvalidInput(fields[i].getText())) {
System.out.println("Invalid Input");
return;
}
record[i]=fields[i].getText();
}
model.addRow(record);
}
여기서 유요한 입력인지 아닌지를 판별해주는 것이 isInvalidInput()인데, 간단하게 텍스트 필드가 비어있는지 확인하는 메소드입니다.
private boolean isInvalidInput(String input) {
return input==null||input.length()==0;
}
그리고 다음 입력을 편하게 받을 수 있도록 필드를 전부 비워주고 가장 맨 처음인 이름 필드에 focus를 하도록 하지요. model.addRow(record) 밑에 아래의 라인을 추가 구현하면 됩니다.
//모든 TextField 비우기
for(int i=0;i<6;i++)
fields[i].setText("");
fields[0].requestFocus();
이제 addRecords()라는 레코드 추가 메소드는 구현이 되었습니다. 이 메소드는 추가버튼이나 텍스트 필드에서 엔터가 쳐지는 순간 호출하면 됩니다.
@Override
public void mouseClicked(MouseEvent e) {
Object src=e.getSource();
if(src==addBtn) {
addRecord();
}
}
@Override
public void keyReleased(KeyEvent e) {
int keyCode = e.getKeyCode();
if(keyCode==KeyEvent.VK_ENTER) {
addRecord();
}
}
3. 삭제 구현 - removeRecord()
우리는 삭제할때 선택된 레코드가 있으면 그 레코드를 삭제하고 아니면 가장 처음 추가된 레코드를 삭제한다고 했죠. 우리가 구현한 removeRecord()는 선택된 index를 넘겨받는데 만약 선택된 index가 없다면 index는 -1의 값을 가진다고 합시다.
public void removeRecord(int index) {
DefaultTableModel model=(DefaultTableModel)table.getModel();
if(index<0) {
if(table.getRowCount()==0)//비어있는 테이블이면
return;
index=0;
}
model.removeRow(index);
}
index가 -1인 경우에는 아예 Table에 레코드가 없거나, 레코드는 있는데 선택하지 않는 경우입니다. 레코드의 수를 확인하려면 JTable의 getRowCount() 메소드를 통해서 확인하면 됩니다.
getRowCount() == 0 : 이미 비어있으니 아무 동작하지 않고 종료합니다.
getRowCount() > 0 : 레코드가 존재하니까 가장 상위 레코드인 0을 index의 값으로 저장합니다.
이제 DefaultTableMode의 removeRow()에 그 index를 넘겨주면 해당 index의 행이 삭제됩니다. 이 removeRecords() 메소드는 삭제버튼이 눌리게 되면 호출하면 됩니다.
@Override
public void mouseClicked(MouseEvent e) {
Object src=e.getSource();
//...생략 ...//
if(src==delBtn) {
int selected=table.getSelectedRow();
removeRecord(selected);
}
}
JTable의 getSelectedRow() 메소드는 선택된 레코드가 없다면 -1을 넘겨줍니다. 그래서 우리는 그대로 removeRecords()에 그 값을 넘겨주면 됩니다.
4. 읽기 - printCell()
읽으려면 cell의 위치를 알아야합니다. 그래서 선택된 행의 위치, 선택된 열의 위치를 얻어와서 DefaultTableModel의 getValueAt()에 전달해주면 셀을 읽어올 수 있습니다. 내용을 출력해주는 메소드를 printCell()이라고 하여 정의하면 이렇습니다.
public void printCell(int row,int col) {
DefaultTableModel model=(DefaultTableModel)table.getModel();
System.out.println(model.getValueAt(row, col));
}
이 메소드는 JTable이 클릭할때 발생시켜주면 되는데 이때 클릭된 셀의 행과 열 위치를 JList의 getSelectedRow()메소드와 getSelectedColumn() 메소드를 통해서 알아오면 됩니다.
@Override
public void mouseClicked(MouseEvent e) {
Object src=e.getSource();
//... 생략 ...//
if(src==table) {
int row=table.getSelectedRow();
int col=table.getSelectedColumn();
printCell(row,col);
}
}
전반적인 소스 구현은 끝이 났습니다.
전체 코드
전체 코드는 아래와 같습니다.
- JTableTest.java
public class JTableTest extends JFrame implements MouseListener,KeyListener {
private final String[] labels= {"Name","Age","Sex","Korean","English","Math"};
private JTextField []fields=new JTextField[6];
private JScrollPane scrolledTable;
private JTable table;
private JButton addBtn;
private JButton delBtn;
public JTableTest(String title) {
this.setLayout(new BorderLayout(10,10));
JPanel topPanel=new JPanel(new GridLayout(6,4,10,5));
for(int i=0;i<6;i++) {
topPanel.add(new JLabel(labels[i]));
fields[i]=new JTextField(30);
topPanel.add(fields[i]);
}
topPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
this.add("North",topPanel); //가장 위쪽 Panel 설정
String header[]= {"Name","Age","Sex","Korean","English","Math"};
DefaultTableModel model=new DefaultTableModel(header,0); //header추가, 행은 0개 지정
table=new JTable(model);
scrolledTable=new JScrollPane(table); //스크롤 될 수 있도록 JScrollPane 적용
scrolledTable.setBorder(BorderFactory.createEmptyBorder(10,10,10,10)); //너무 붙어있어서 가장자리 띄움(padding)
this.add("Center",scrolledTable); //가운데에 JTable 추가
JPanel rightPanel=new JPanel(new GridLayout(5,1,10,10));
addBtn=new JButton("레코드 추가");
delBtn=new JButton("레코드 삭제");
rightPanel.add(addBtn);
rightPanel.add(delBtn);
rightPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
this.add("East",rightPanel); //오른쪽에 버튼들 추가
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(620,400);
this.setLocationRelativeTo(null); //창 가운데 위치
this.setVisible(true);
//이벤트 추가
addBtn.addMouseListener(this); //추가 처리
delBtn.addMouseListener(this); //삭제 처리
for(int i=0;i<6;i++) //엔터 처리
fields[i].addKeyListener(this);
table.addMouseListener(this); //셀 읽기 처리
}
private boolean isInvalidInput(String input) {
return input==null||input.length()==0;
}
public void removeRecord(int index) {
DefaultTableModel model=(DefaultTableModel)table.getModel();
if(index<0) {
if(table.getRowCount()==0)//비어있는 테이블이면
return;
index=0;
}
model.removeRow(index);
}
public void addRecord() {
DefaultTableModel model=(DefaultTableModel)table.getModel();
String []record=new String[6];
for(int i=0;i<6;i++) {
if(isInvalidInput(fields[i].getText())) {
System.out.println("Invalid Input");
return;
}
record[i]=fields[i].getText();
}
model.addRow(record);
//모든 TextField 비우기
for(int i=0;i<6;i++)
fields[i].setText("");
fields[0].requestFocus();
}
public void printCell(int row,int col) {
DefaultTableModel model=(DefaultTableModel)table.getModel();
System.out.println(model.getValueAt(row, col));
}
//MouseListener Overrides
@Override
public void mouseClicked(MouseEvent e) {
Object src=e.getSource();
if(src==addBtn)
addRecord();
if(src==delBtn) {
int selected=table.getSelectedRow();
removeRecord(selected);
}
if(src==table) {
int row=table.getSelectedRow();
int col=table.getSelectedColumn();
printCell(row,col);
}
}
@Override
public void mousePressed(MouseEvent e) {}
@Override
public void mouseReleased(MouseEvent e) {}
@Override
public void mouseEntered(MouseEvent e) {}
@Override
public void mouseExited(MouseEvent e) {}
//KeyListener Overrides
@Override
public void keyTyped(KeyEvent e) {}
@Override
public void keyPressed(KeyEvent e) {}
@Override
public void keyReleased(KeyEvent e) {
int keyCode = e.getKeyCode();
if(keyCode==KeyEvent.VK_ENTER) {
addRecord();
}
}
}
이 클래스를 main 함수에서 호출하면 됩니다.
- Main.java
public class Main {
public static void main(String[] ar) {
JTableTest test=new JTableTest("reakwon");
}
}
여기까지 JTable에 대한 기본적인 행 추가, 삭제에 대해서 알아보았습니다. 기본적인 사용법만 읽힌다면 어렵지 않게 사용할 수 있을 것 같습니다.
'언어 > JAVA' 카테고리의 다른 글
[자바] 람다 표현식(Lambda Expression)의 개념과 예로 익히는 사용 방법 (0) | 2021.08.23 |
---|---|
[자바/네트워크] 소켓 프로그래밍(TCP Connection) - 클라이언트, 서버 통신 하기 (1) | 2021.04.13 |
[자바/GUI] Swing JList(다중 선택, 단일 선택) - 동적으로 아이템 추가, 삭제 (0) | 2021.04.12 |
[자바] 어렵지 않은 RandomAccessFile 개념과 예제 코드 구현(read, write, seek) (0) | 2021.04.11 |
[자바/GUI]Event와 Event Handling의 기초 - WindowListener 다뤄보기 (0) | 2021.04.09 |