Java Swing에서 JTable을 사용하다 보면 셀을 어떻게 '보여줄지'와 어떻게 '편집할지'를 각각 제어해야 하는 상황이 자주 발생합니다. 이때 사용되는 것이 바로 TableCellRenderer와 TableCellEditor입니다. 두 인터페이스는 이름이 비슷하지만 역할이 명확히 다르며, 이를 이해하면 테이블 UI를 훨씬 유연하게 구성할 수 있습니다.
TableCellRenderer란?
- TableCellRenderer는 JTable 셀의 값을 화면에 표시(렌더링)하는 컴포넌트를 생성하는 인터페이스입니다.
- 기본 렌더러는 JLabel을 사용하여 각 테이블 셀의 값을 단순한 텍스트 형태로 보여줍니다.
- 셀 렌더러는 두 가지 방식으로 지정할 수 있습니다. 첫째, table.setDefaultRenderer() 메서드로 렌더링할 객체의 클래스 타입별로 지정하는 방법과, 둘째, 특정 열(column)에 한정하여 tableColumn.setCellRenderer() 메서드로 지정하는 방법입니다. 또한 열 헤더(header) 전용으로는 tableColumn.setHeaderRenderer() 메서드를 사용할 수 있습니다.
- TableCellRenderer 인터페이스에는 getTableCellRendererComponent() 메서드 하나만 정의되어 있으며, 이 메서드는 셀의 값, 포커스 여부, 선택 여부, 그리고 해당 값이 위치한 행(row)과 열(column) 정보에 따라 서로 다른 렌더링 컴포넌트를 반환할 수 있습니다.
TableCellEditor란?
- TableCellEditor는 셀의 값을 편집하기 위한 컴포넌트를 제공하는 인터페이스이며, 기본적으로 JTable의 셀은 편집 가능하도록 설정되어 있습니다.
- 특정 셀이 편집 가능한지 여부는 TableModel의 isCellEditable() 메서드를 호출하여 판단합니다.
- 셀 값의 자료형에 따라 적절한 에디터를 선택할 수 있습니다. 예를 들어 값이 Boolean 타입이라면 JCheckBox(체크박스)를 사용할 수 있고, 더블클릭 시 텍스트 편집 모드로 진입해야 하는 경우라면 JTextField(텍스트 필드)를 사용할 수 있습니다.
- TableCellEditor 인터페이스에는 getTableCellEditorComponent() 메서드 하나만 정의되어 있으며, 이 메서드 역시 셀의 값, 선택 여부, 행과 열 정보에 따라 서로 다른 편집 컴포넌트를 반환할 수 있습니다.
핵심 차이점 요약
정리하면 TableCellRenderer는 '표시'를 담당하고, TableCellEditor는 '편집'을 담당합니다. 렌더러는 마우스 클릭 없이 항상 화면에 보이는 상태의 UI를 결정하며, 에디터는 사용자가 셀을 더블클릭하거나 편집을 시작했을 때 나타나는 입력 UI를 결정합니다.
예제 코드
아래 예제에서는 첫 번째 열은 편집이 불가능하도록 설정하고, 두 번째 열('Editor')에는 JTextArea를 활용한 커스텀 렌더러와 에디터를 적용했습니다.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;
public class TableCellRendererEditorTest extends JFrame {
private JTable table;
public TableCellRendererEditorTest() {
setTitle("TableCellRendererEditor Test");
// 0번 열은 편집 불가, 나머지 열은 편집 가능하도록 설정
DefaultTableModel dtm = new DefaultTableModel() {
public boolean isCellEditable(int row, int column) {
return !(column == 0);
}
};
dtm.setDataVector(
new Object[][]{{"Table Cell Renderer", "Table Cell Editor"},
{"Table Cell Renderer", "Table Cell Editor"}},
new Object[]{"Renderer", "Editor"}
);
table = new JTable(dtm);
// 'Editor' 열에 커스텀 렌더러와 에디터 적용
table.getColumn("Editor").setCellRenderer(new TextAreaRenderer());
table.getColumn("Editor").setCellEditor(new TextAreaEditor());
table.setRowHeight(80);
JScrollPane spane = new JScrollPane(table);
add(spane);
setSize(400, 275);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setVisible(true);
}
public static void main(String[] args) {
new TableCellRendererEditorTest();
}
}
// JTextArea 기반 커스텀 셀 렌더러
class TextAreaRenderer extends JScrollPane implements TableCellRenderer {
JTextArea textarea;
public TextAreaRenderer() {
textarea = new JTextArea();
textarea.setLineWrap(true);
textarea.setWrapStyleWord(true);
getViewport().add(textarea);
}
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
if (isSelected) {
setForeground(table.getSelectionForeground());
setBackground(table.getSelectionBackground());
textarea.setForeground(table.getSelectionForeground());
textarea.setBackground(table.getSelectionBackground());
} else {
setForeground(table.getForeground());
setBackground(table.getBackground());
textarea.setForeground(table.getForeground());
textarea.setBackground(table.getBackground());
}
textarea.setText((String) value);
textarea.setCaretPosition(0);
return this;
}
}
// JTextArea 기반 커스텀 셀 에디터
class TextAreaEditor extends DefaultCellEditor {
protected JScrollPane scrollpane;
protected JTextArea textarea;
public TextAreaEditor() {
super(new JCheckBox());
scrollpane = new JScrollPane();
textarea = new JTextArea();
textarea.setLineWrap(true);
textarea.setWrapStyleWord(true);
scrollpane.getViewport().add(textarea);
}
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
textarea.setText((String) value);
return scrollpane;
}
public Object getCellEditorValue() {
return textarea.getText();
}
}실행 결과
프로그램을 실행하면 'Renderer' 열은 일반적인 방식으로 값을 표시하며 편집할 수 없고, 'Editor' 열은 클릭하여 편집할 때 JTextArea가 포함된 스크롤 창이 나타나 여러 줄의 텍스트를 자유롭게 수정할 수 있습니다. 이처럼 렌더러와 에디터를 조합하면 JTable의 각 셀에 대해 표시 방식과 편집 방식을 독립적으로 세밀하게 제어할 수 있습니다.