Java SE/JTable 02

JTable 02

Soul-Learner 2008. 4. 29. 11:30

/*
 * TableDemo.java requires no other files.
 */

import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
import java.awt.*;
import java.awt.event.*;

/**
* 이 예제는 모델의 데이터가 변경되면 fireTableDataChanged() 메소드를 이용하여
* 뷰에게 변경사실을 알려 줌으로써 뷰가 새로운 내용으로 갱신되도록 했다.
* 프로그램을 시작하면 emp 테이블의 모든내용이 JTable에 나타나고 이용자가 그 중 한 라인을
* 클릭하면 JTable은 해당 라인만 보여 주도록 갱신된다.
 */
public class JTable_Update extends JPanel {
    private boolean DEBUG = true;
 JTable table;
 MyTableModel model;
 JTableHeader header;

    public JTable_Update() {
        super(new GridLayout(1,0));
   model = new MyTableModel();
        table = new JTable(model);
  // 이부분은 테이블 헤더를 사용하는 방법을 제시할 뿐이며  문맥상 의미는 없다
  // 테이블헤더를 이용하지 않는다면 이부분을 제거해도 됨
  header = table.getTableHeader();
  header.addMouseListener(new MouseAdapter() {
   public void mouseReleased(MouseEvent e) {
    System.out.println("Mouse Clicked");
    model.setValueAt("Hello", 0, 1);
   }
  });// 테이블 헤더 사용예 끝

        table.setPreferredScrollableViewportSize(new Dimension(500, 500));

  table.setRowSelectionAllowed( true );
  table.setColumnSelectionAllowed( true );

  table.setSelectionForeground( Color.white );
  table.setSelectionBackground( Color.red );

  // 2번째 컬럼을 위한 CellEditor를 설정한다
  // 즉, 2번째 컬럼을 더블 클릭하면 해당 셀값을 편집할 수 있는 JTextField가 나타나게 한다
  // CellEditor가 필요없다면 이 부분을 제거해도 됨
  TableColumn lastNameColumn = table.getColumnModel().getColumn(1);
  JTextField tf = new JTextField();
  tf.addActionListener(new ActionListener(){
   public void actionPerformed(ActionEvent ae) {
    Object o = ae.getSource();
    String value = null;
    if(o instanceof JTextField) value=((JTextField)o).getText();
    int row = table.getSelectedRow();
    int col = table.getSelectedColumn();
    System.out.println("Last Name("+row+", "+col+") changed-->"+value);
    //model에게 테이블 셀의 데이터가 변경되었음 알려서 model의 setValueAt(row, col)메소드가
    //실행되도록 하여 실제 모델의 데이터가 변경될 수 있게 한다.
    model.fireTableCellUpdated(row, col);
   }
  });
  lastNameColumn.setCellEditor(new DefaultCellEditor(tf));
  //두번째 컬럼을 위한 CellEditor 설정 끝
 
  //ListSelectionModel에 ListSelectionListener를 설정하여 셀 선택을 감지한다.
  //셀 선택 즉시 해당 셀의 정보를 구할 필요가 없다면 이부분을 제거해도 됨
  ListSelectionModel sm = table.getSelectionModel();
  sm.addListSelectionListener(new ListSelectionListener() {
   public void valueChanged(ListSelectionEvent lse) {
    if(lse.getValueIsAdjusting()) return;
    ListSelectionModel lsm = (ListSelectionModel)lse.getSource();
    if(lsm.isSelectionEmpty()){
    }else{
     int col = table.getSelectedColumn();
     int row = table.getSelectedRow();
     String ename = (String)(table.getValueAt(row, 1));

     //선택한 이름을 키워드로 데이터베이스를 검색한다.
     String sql = "select * from emp where ename='"+ename+"'";
     java.sql.Connection con = null;
     java.sql.Statement stmt = null;
     java.sql.ResultSet rs = null;
     String dbURL = "jdbc:oracle:thin:@localhost:1521:ORCL";

     try {
      Class.forName("oracle.jdbc.OracleDriver");
      con = java.sql.DriverManager.getConnection(dbURL, "scott", "tiger");
      stmt = con.createStatement();
      rs = stmt.executeQuery(sql);
      java.sql.ResultSetMetaData md = rs.getMetaData();
      int columnCount = md.getColumnCount();
      java.util.Vector v = new java.util.Vector();
      Object[] obj = null;
      while(rs.next()) {
       obj = new Object[columnCount];
       obj[0] = new Integer(rs.getInt("EMPNO"));
       obj[1] = rs.getString("ENAME");
       obj[2] = rs.getString("JOB");
       obj[3] = new Integer(rs.getInt("MGR"));
       obj[4] = rs.getDate("HIREDATE");
       obj[5] = new Integer(rs.getInt("SAL"));
       obj[6] = new Integer(rs.getInt("COMM"));
       obj[7] = new Integer(rs.getInt("DEPTNO"));
       v.add(obj);
      }
      int rowCount = v.size();
      model.data = new Object[rowCount][columnCount];
      for(int i=0;i<rowCount;i++)
       model.data[i] = (Object[]) (v.get(i));

      rs.close();
      stmt.close();
      con.close();
      System.out.println("데이터 베이스 접속 및 질의 성공");
      model.fireTableDataChanged(); // 이 부분이 꼭 필요함, 모델의 변경사실을 뷰에 알려서 뷰가 갱신되도록함
     }catch(Exception e){
      System.err.println("에러");
     }finally{
      try{
       if(rs!=null) rs.close();
       if(stmt!=null) stmt.close();
       if(con!=null) con.close();
      }catch(Exception ee) {ee.printStackTrace();}
     }
    }
   }
  });//ListSelectionListener설정 끝
 

  // 테이블 컬럼의 폭을 변경하는 예
  // 테이블 컬럼의 폭을 변경할 필요가 없다면 이부분을 제거해도 됨
  TableColumn column = null;
  for(int i=0;i<table.getColumnCount();i++) {
   column = table.getColumnModel().getColumn(i);
   if(i==2) column.setPreferredWidth(100); // default width is 75.
   else column.setPreferredWidth(50);
  }// 테이블 컬럼의 폭을 변경하는 예 끝

  // 테이블 행의 높이 설정법
  table.setRowHeight(30);
  // 테이블 행의 높이 설정끝

  //Create the scroll pane and add the table to it.
        JScrollPane scrollPane = new JScrollPane(table);

        //Add the scroll pane to this panel.
        add(scrollPane);
    } // end of constructor
 
 // JTable의 모델을 내부 클래스로 선언함
    class MyTableModel extends AbstractTableModel {
        private String[] columnNames;
        private Object[][] data;

  MyTableModel() {
   // 오라클 데이터베이스에 연결하여 emp테이블의 모든 데이터를 가져 온 후에
   // columnNames, data 배열에 저장한다.
   java.sql.Connection con = null;
   java.sql.Statement stmt = null;
   java.sql.ResultSet rs = null;
   String dbURL = "jdbc:oracle:thin:@localhost:1521:ORCL";

   try {
    Class.forName("oracle.jdbc.OracleDriver");
    con = java.sql.DriverManager.getConnection(dbURL, "scott", "tiger");
    stmt = con.createStatement();
    rs = stmt.executeQuery("select * from emp");
    java.sql.ResultSetMetaData md = rs.getMetaData();
    int columnCount = md.getColumnCount();
    columnNames = new String[columnCount];
    for(int i=0;i<columnCount;i++)
     columnNames[i] = md.getColumnName(i+1);
    java.util.Vector v = new java.util.Vector();
    Object[] obj = null;
    while(rs.next()) {
     obj = new Object[columnCount];
     obj[0] = new Integer(rs.getInt("EMPNO"));
     obj[1] = rs.getString("ENAME");
     obj[2] = rs.getString("JOB");
     obj[3] = new Integer(rs.getInt("MGR"));
     obj[4] = rs.getDate("HIREDATE");
     obj[5] = new Integer(rs.getInt("SAL"));
     obj[6] = new Integer(rs.getInt("COMM"));
     obj[7] = new Integer(rs.getInt("DEPTNO"));
     v.add(obj);
    }
    int rowCount = v.size();
    data = new Object[rowCount][columnCount];
    for(int i=0;i<rowCount;i++)
     data[i] = (Object[]) (v.get(i));

    rs.close();
    stmt.close();
    con.close();
   }catch(Exception e){
    try{
     if(rs!=null) rs.close();
     if(stmt!=null) stmt.close();
     if(con!=null) con.close();
    }catch(Exception ee) {ee.printStackTrace();}
   }

  }// end of constructor

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

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

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

        public Object getValueAt(int row, int col) {
            return data[row][col];
        }

        /*
         * 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();
        }

        /*
         * Don't need to implement this method unless your table's
         * editable.
         */
        public boolean isCellEditable(int row, int col) {
            //Note that the data/cell address is constant,
            //no matter where the cell appears onscreen.
            if (col < 1) {
                return false;
            } else {
                return true;
            }
        }

        /*
         * Don't need to implement this method unless your table's
         * data can change.
   * 테이블의 특정 셀을 마우스로 더블 클릭하여 데이터를 수정한 후에,
   * model.fireTableCellUpdated(row, col) 메소드를 호출하면 모델의 데이터가 갱신된다.
   * 즉, Table --> Model 갱신
   * 반대로, 모델의 setValueAt(Object, row, col) 메소드를 직접 호출하여 모델의 데이터를
   * 수정한 후에 이 메소드 안에서 fireTableCellUpdated(row, col)메소드를 호출하면
   * 테이블의 해당 셀이 갱신된다. 즉, Model --> Table 갱신
         */
        public void setValueAt(Object value, int row, int col) {
            if (DEBUG) {
                System.out.println("Setting value at " + row + "," + col
                                   + " to " + value
                                   + " (an instance of "
                                   + value.getClass() + ")");
            }

            data[row][col] = value;

   // view(JTable)에 알려서 수정된 모델의 데이터를 테이블에 반영한다.
            fireTableCellUpdated(row, col);

            if (DEBUG) {
                System.out.println("New value of data:");
                printDebugData();
            }
        }

        private void printDebugData() {
            int numRows = getRowCount();
            int numCols = getColumnCount();

            for (int i=0; i < numRows; i++) {
                System.out.print("    row " + i + ":");
                for (int j=0; j < numCols; j++) {
                    System.out.print("  " + data[i][j]);
                }
                System.out.println();
            }
            System.out.println("--------------------------");
        }
    }

    /**
     * Create the GUI and show it.  For thread safety,
     * this method should be invoked from the
     * event-dispatching thread.
     */
    private static void createAndShowGUI() {
        //Create and set up the window.
        JFrame frame = new JFrame("TableDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //Create and set up the content pane.
        JTable_Update newContentPane = new JTable_Update();
        newContentPane.setOpaque(true); //content panes must be opaque
        frame.setContentPane(newContentPane);

        //Display the window.
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
}