하나만 만들어 놓고 언제나 사용할 수 있는 Table Model 을 만들자는 취지로 시작했지만.. Table 의 요구사항 변경에 따라 수정 할 수 밖에 없다. 좀 아쉬운 감이 있지만 모든걸 다 적용시키기는 힘들다는 결론에 다다르고 단순히 범용적으로 사용할 수 있는 넘 하나만 만들었다.

TableModel 은 column name 과 data 두개의 부분으로 나눠지는데.. 이 두개만 생성해 model에 등록하면 알아서 동작하는 넘으로 작성되었다. Reflection 기능을 이용하니 손쉽게 작성된듯...


MyTableModel.java

AbstractTableModel 클래스를 상속받아 구현된 단순한 넘. 기본 골격은 (http://java.sun.com/docs/books/tutorial/uiswing/components/table.html#validtext) 참조했으며 신규 추가된 부분이 data 와 header 부분을 Value Object로 변경한 부분이다. 물론 변경된 사항에 따라서 column name 과 data get, set 부분이 수정되었다.

import javax.swing.table.AbstractTableModel;

 /**
 *
 * @author Administrator
 */
public class MyTableModel extends AbstractTableModel {

    private AbstractTableVo[] data;
    private CustomTableColumnName[] columnNames;

    public Object[] longValues;

    public Object[] getLongValues() {
        return longValues;
    }

    public void setLongValues(Object[] longValues) {
        this.longValues = longValues;
    }

    public CustomTableColumnName[] getColumnNames() {
        return columnNames;
    }

    public void setColumnNames(CustomTableColumnName[] columnNames) {
        this.columnNames = columnNames;
    }

   
    public AbstractTableVo[] getData() {
        return data;
    }

    public void setData(AbstractTableVo[] data) {
        this.data = data;
    }

    public String getColumnName(int col) {
        return columnNames[col].getName();
    }


    public int getRowCount() {
        return data.length;
    }

    public int getColumnCount() {
        return columnNames.length;
    }

    public Object getValueAt(int rowIndex, int columnIndex) {
        return data[rowIndex].getValueAt(columnNames[columnIndex].getId());
    }
   
    /*
     * Don't need to implement this method unless your table's
     * editable.
     */
    public boolean isCellEditable(int row, int col) {
        return true;
    }

    /*
     * Don't need to implement this method unless your table's
     * data can change.
     */
    public void setValueAt(Object value, int row, int col) {

        data[row].setValueAt(value, columnNames[col].getId());

    }

    /*
     * JTable uses this method to determine the default renderer/
     * editor for each cell.  If we didn't implement this method,
     * then the last column would contain text ("true"/"false"),
     * rather than a check box.
     */
    public Class getColumnClass(int c) {
        return getValueAt(0, c).getClass();
    }

}


SampleVo.java
- 샘플로 작성된 Table Data Value 객체. AbstractTableVo 클래스를 상속받아야 하는 rule 만 지켜주면 만사형통임.

/**
 *
 * @author Administrator
 */
public class SampleVo extends AbstractTableVo {

    private String firstName;
    private String lastName;
    private String sport;
    private Integer ofYears;
    private Boolean vegetarian;
       
    public Boolean getVegetarian() {
        return vegetarian;
    }

    public void setVegetarian(Boolean vegetarian) {
        this.vegetarian = vegetarian;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public Integer getOfYears() {
        return ofYears;
    }

    public void setOfYears(Integer ofYears) {
        this.ofYears = ofYears;
    }

    public String getSport() {
        return sport;
    }

    public void setSport(String sport) {
        this.sport = sport;
    }  
}


AbstractTableVo.java
- CustomTableColumnName, SampleVo 클래스 들이 규칙에 따라 작성되면 TableModel 과 연결되어 알아서 작동한다.

import java.lang.reflect.Method;

/**
 *
 * @author Administrator
 */
public abstract class AbstractTableVo {

    public void setValueAt(Object value, String id) {
         try {

            String methodName = "set" + id.substring(0, 1).toUpperCase() + id.substring(1, id.length());

            Method method = this.getClass().getMethod(methodName , new Class[]{value.getClass()});

            method.invoke(this, value);
        } catch(Exception e) {

        }
    }
  
    public Object getValueAt(String id) {

        try {

            String methodName = "get" + id.substring(0, 1).toUpperCase() + id.substring(1, id.length());

            System.out.println("Method Name : " + methodName);

            Method method = this.getClass().getMethod(methodName ,null);

            return method.invoke(this, null);
        } catch(Exception e) {

        }
        return null;
    }
}


CustomTableColumnName.java
- table의 header 명을 가지는 클래스로 name 필드는 컬럼명을 의미하며, id 는 컴럼명을 의미하는 키로 SampleVo 의 필드명과 일치해야 한다.    

/**
 *
 * @author Administrator
 */
public class CustomTableColumnName {

    private String id;
    private String name;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}


사용법
Model 을 만드는 부분이 화면에 보여질 데이터를 작성하는 것이기 때문에 어쩔 수 없이 무식하고 지져분해질 수 밖에 없는듯하다. 좀더 좋은 방법이 있겠지만, 귀찮니즘 때문인지 단순히 데이터를 무식하게 쌓기만 했다. 사용은 각자가 알아서 하면 될듯하다.

SampleVo 를 토대로 작성했기 때문에 다른 Data Value Object 작성 시 아래 코드는 참조용으로만 사용해야 할듯.

private MyTableModel myTableModel = new MyTableModel();

// Table Model 초기화

private void initTable() {       

        SampleVo[] tableDataValues;
        CustomTableColumnName[] tableColumnNames;

        // table data 초기화

        tableDataValues = new SampleVo[5];
        setData(tableDataValues, 0, "Mary", "Campione", "Snowboarding", new Integer(5), new Boolean(false));
        setData(tableDataValues, 1, "Mary", "Campione", "Snowboarding", new Integer(5), new Boolean(true));
        setData(tableDataValues, 2, "Mary", "Campione", "Snowboarding", new Integer(5), new Boolean(false));
        setData(tableDataValues, 3, "Mary", "Campione", "Snowboarding", new Integer(5), new Boolean(true));
        setData(tableDataValues, 4, "Mary", "Campione", "Snowboarding", new Integer(5), new Boolean(true));
        myTableModel.setData(tableDataValues);

        // column name 초기화
        tableColumnNames = new CustomTableColumnName[5];
        setColumnName(tableColumnNames,0, "firstName", "First Name");
        setColumnName(tableColumnNames,1, "lastName", "Last Name");
        setColumnName(tableColumnNames,2, "sport", "Sport");
        setColumnName(tableColumnNames,3, "ofYears", "# of Years");
        setColumnName(tableColumnNames,4, "vegetarian", "Vegetarian");
        myTableModel.setColumnNames(tableColumnNames);

       // column 최대 사이즈를 구하기 위해서..
       Object[] longValues = {"Sharon", "Campione", "None of the above", new Integer(20), Boolean.TRUE};
       myTableModel.setLongValues(longValues);
    }

     public void setColumnName(CustomTableColumnName[] tableColumnNames, int offset, String id, String name) {
        tableColumnNames[offset] = new CustomTableColumnName();
        tableColumnNames[offset].setId(id);
        tableColumnNames[offset].setName(name);
    }
   
    public void setData(SampleVo[] tableDataValues, int offset, String firstName, String lastName, String sport, Integer integer, Boolean boo) {
        tableDataValues[offset] = new SampleVo();
        tableDataValues[offset].setFirstName(firstName);
        tableDataValues[offset].setLastName(lastName);
        tableDataValues[offset].setSport(sport);
        tableDataValues[offset].setOfYears(integer);
        tableDataValues[offset].setVegetarian(boo);
    }



Posted by 짱가쟁이