// 1. DefaultTableModel 생성// - 컬럼명 설정 배열 : String[] columnNames = {"컬럼명",...};// - 데이터 설정 배열 : String[][] rowData = { {값,.. }, {값,.. },.. };DefaultTableModel dtm = new DefaultTableModel(rowData, columnNames);// 2. JTable 생성JTable jt = new JTable(dtm);// 3. Scrollbar 설정// - 스크롤바 추가 안하면 컬럼의 이름이 보이지 않는다.JScrollPane jsp = new JScrollPane(jt);
// MVC Pattern이 적용된 class@SuppressWarnings("serial")public class UseJTable extends JFrame implements ActionListener { private JTable jt; private JButton btnAdd; private DefaultTableModel dtm; private UseJTable ujt; public UseJTable() { super("JTable 연습"); ujt = this; // 1. 데이터를 관리하는 Model 클래스 생성 String[] columnName = {"번호","이름","주소","이메일"}; String[][] rowData = { { "1","이재찬","인천시 소래동","chan@test.com" }, { "2","정택성","서울시 구로동","teack@test.co.kr" }, { "3","이재현","경기도 안양시","hyun@test.com" } }; // 수정불가능하도록 변경 dtm = new DefaultTableModel(rowData, columnName) { @Override public boolean isCellEditable(int row, int column) { return false; } }; // 2. 데이터를 보여주는 View 클래스 생성 jt = new JTable(dtm); // 테이블 컬럼의 크기 변경 : 컬럼은 하나의 필드 넓이를 변경하면 // 하위 모든 컬럼은 동일한 크기를 적용받음 // 컬럼크기변경 1. 컬럼을 얻는다. TableColumn tcNum = jt.getColumnModel().getColumn(0); // 컬럼크기변경 2. 컬럼의 크기 변경. tcNum.setPreferredWidth(50); // 이렇게 한줄로 처리 가능 jt.getColumnModel().getColumn(1).setPreferredWidth(100); jt.getColumnModel().getColumn(2).setPreferredWidth(200); jt.getColumnModel().getColumn(3).setPreferredWidth(150); // 행의 높이 변경 jt.setRowHeight(29); btnAdd = new JButton("데이터 추가"); JPanel jp = new JPanel(); jp.add(btnAdd); // 3. Column의 이름과 Scrollbar를 사용할 수 있도록 JScrollPane에 배치 JScrollPane jsp = new JScrollPane(jt); add(BorderLayout.CENTER, jsp); add(BorderLayout.SOUTH, jp); btnAdd.addActionListener(this); UseJTable.TableEvt te = this.new TableEvt(); jt.addMouseListener(te); setBounds(300, 250, 500, 200); setVisible(true); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } @Override public void actionPerformed(ActionEvent e) { String inputData = JOptionPane.showInputDialog("데이터입력\n예)번호,이름,주소,이메일"); String[] tempData = inputData.split(","); if (tempData.length != 4) { JOptionPane.showMessageDialog(this, "입력 데이터의 형태는 \n 번호,이름,주소,이메일이어야 합니다.", "입력 오류", JOptionPane.ERROR_MESSAGE); return; } // 입력된 데이터를 화면에 보여주기 위해 DefaultTableModel에 추가 // Object이 String의 부모이므로, String은 Object의 자식이므로 매개변수로 들어갈 수 있음 dtm.addRow(tempData); } ///////////////// inner class 시작 //////////////// public class TableEvt extends MouseAdapter { @Override public void mouseClicked(MouseEvent e) { int selectedRow = jt.getSelectedRow(); int flag = JOptionPane.showConfirmDialog(ujt, "예를 누르면 조회, 아니오를 누르면 삭제"); switch(flag) { case JOptionPane.OK_OPTION: int columnCount = jt.getColumnCount(); // 선택된 행의 정보를 가져와서 Dialog로 보여주기 String selectedVal; StringBuilder viewData = new StringBuilder(); for(int i=0; i<columnCount; i++) { selectedVal = (String)jt.getValueAt(selectedRow, i); viewData.append(selectedVal).append("\n"); } JOptionPane.showMessageDialog(ujt, viewData, "행 결과", JOptionPane.PLAIN_MESSAGE); break; case JOptionPane.NO_OPTION: // 선택한 행을 지우기 switch(JOptionPane.showConfirmDialog(ujt, "정말 삭제하시겠습니까?")) { case JOptionPane.OK_OPTION: dtm.removeRow(selectedRow); break; } } } } ///////////////// inner class 끝 //////////////// public static void main(String[] args) { new UseJTable(); }}
... JTable jt = new JTable(dtm);// 테이블 컬럼의 크기 변경 : 컬럼은 하나의 필드 넓이를 변경하면// 하위 모든 컬럼은 동일한 크기를 적용받음// 컬럼크기변경 1. 컬럼을 얻는다.TableColumn tcNum = jt.getColumnModel().getColumn(0);// 컬럼크기변경 2. 컬럼의 크기 변경.tcNum.setPreferredWidth(50);// 이렇게 한줄로 처리 가능jt.getColumnModel().getColumn(1).setPreferredWidth(100);jt.getColumnModel().getColumn(2).setPreferredWidth(200);jt.getColumnModel().getColumn(3).setPreferredWidth(150);...
// 행의 높이 변경jt.setRowHeight(29);
테이블에 발생한 이벤트는 MouseListener를 사용
이너클래스로 구현
UseJTable.TableEvt te = this.new TableEvt();jt.addMouseListener(te);...///////////////// inner class 시작 ////////////////public class TableEvt extends MouseAdapter { @Override public void mouseClicked(MouseEvent e) { int selectedRow = jt.getSelectedRow(); int columnCount = jt.getColumnCount(); // 선택된 행의 정보를 가져와서 Dialog로 보여주기 String selectedVal; StringBuilder viewData = new StringBuilder(); for(int i=0; i<columnCount; i++) { selectedVal = (String)jt.getValueAt(selectedRow, i); viewData.append(selectedVal).append("\n"); } JOptionPane.showMessageDialog(ujt, viewData, "행 결과", JOptionPane.PLAIN_MESSAGE); }}
이너클래스에서 부모의 창을 전해줄 때 아래와 같이 구현
자기 인스턴스의 주소를 저장하는 인스턴스변수를 만들고
그 인스턴스변수를 사용하여 부모창을 식별할 수 있음
private UseJTable ujt;public UseJTable() { super("JTable 연습"); ujt = this;... // inner 클래스 안에서 현재 창(JFrame)위로 Dialog를 띄울 때, 이렇게 주소 전달 JOptionPane.showMessageDialog(ujt, rowData, "행 결과", JOptionPane.PLAIN_MESSAGE); System.out.println(rowData); } ...}
테이블 Cell의 수정 막기
DefaultTableModel의 isCellEditable은 무조건 true를 반환함
false를 반환하게 만들어야 편집이 안됨
익명클래스로 Override해서 false만 반환하도록 만들면 수정이 불가능해짐
// 수정불가능하도록 변경dtm = new DefaultTableModel(rowData, columnName) { @Override public boolean isCellEditable(int row, int column) { return false; }};
변경과 삭제는 무조건 물어봐야 한다.
///////////////// inner class 시작 ////////////////public class TableEvt extends MouseAdapter { @Override public void mouseClicked(MouseEvent e) { int selectedRow = jt.getSelectedRow(); int flag = JOptionPane.showConfirmDialog(ujt, "예를 누르면 조회, 아니오를 누르면 삭제"); switch(flag) { case JOptionPane.OK_OPTION: int columnCount = jt.getColumnCount(); // 선택된 행의 정보를 가져와서 Dialog로 보여주기 String selectedVal; StringBuilder viewData = new StringBuilder(); for(int i=0; i<columnCount; i++) { selectedVal = (String)jt.getValueAt(selectedRow, i); viewData.append(selectedVal).append("\n"); } JOptionPane.showMessageDialog(ujt, viewData, "행 결과", JOptionPane.PLAIN_MESSAGE); break; case JOptionPane.NO_OPTION: // 선택한 행을 지우기 switch(JOptionPane.showConfirmDialog(ujt, "정말 삭제하시겠습니까?")) { case JOptionPane.OK_OPTION: dtm.removeRow(selectedRow); break; } } }}///////////////// inner class 끝 ////////////////
Tab
한정적인 공간에서 여러 창을 번갈아가며 보여줄 때
JTabbedPane사용
// 1. 생성JTabbedPane jtp = new JTabbedPane();// 2. 디자인을 가진 Container Component 추가JPanal jp = new JPanel(); ... // jp에 컴포넌트들 붙이고 탭에 더한다.jtp.add(jp);
@SuppressWarnings("serial")public class UseJTab extends JFrame { public UseJTab() { super("Tab"); // 1. 탭을 추가할 수 있는 객체를 생성 JTabbedPane jtp = new JTabbedPane(); // 2. 각 탭에 들어갈 컴포넌트를 생성. ImageIcon ii = new ImageIcon("C:/.../ebichuGif.gif"); JLabel jl = new JLabel(ii); // 두번째 탭에 들어갈 컴포넌트 JPanel jp = new JPanel(); jp.add(new JLabel("이름")); jp.add(new JTextField(30)); jp.add(new JButton("입력")); JPanel tab2 = new JPanel(); tab2.setLayout(new BorderLayout()); jp.setBorder(new TitledBorder("입력데이터")); JTextArea jta = new JTextArea(); JScrollPane jsp = new JScrollPane(jta); jsp.setBorder(new TitledBorder("결과창")); tab2.add("North", jp); tab2.add("Center", jsp); jtp.add("처음탭", jl); jtp.add("두번째 탭", tab2); jtp.add("세번째 탭", new JButton("클릭")); // 배치 add("Center",jtp); setBounds(300, 200, 600, 600); setVisible(true); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public static void main(String[] args) { new UseJTab(); }}
Exception Handling(예외처리)
프로그램 동장 중에 발생할 수 있는 가벼운 Error가 발생했을 때 그에 대한 대비코드를 만들어 두는 것
모든 Exception과 Error의 부모는 Throwable 클래스
Error는 발생하면 프로그램이 더 이상 동작을 할 수 없다.
Exception은 발생하면 프로그램은 계속하여 동작할 수 있다.
Compile Exception과 Runtime Exception 두가지로 구분
Compile Exception은 개발자가 반드시 처리해야하는 예외
Runtime Exception은 JVM이 자동으로 처리해주는 예외
try~catch, throws, throw 로 처리
System.err - 표준 에러출력 스트림
상속관계
Compile time, Runtime Exception
컴파일의 목적은 bytecode를 만드는 것.
컴파일 예외처리는 bytecode가 제대로 생성되도록 코드를 처리하는 것.
개발자가 코드 작성시 컴파일 예외처리 코드를 명시
실행할때 발생하는 에러 = RuntimeException
개발자의 손을 벗어난 class가 memory를 사용할 때 발생하는 예외
// 예외처리문법try { 예외발생 예상코드;} catch(예외처리클래스명 객체명) { // 예외발생시 그 예외를 처리할 코드 // catch는 여러개 작성가능 // 부모클래스가 가장 위에 올라오면 안된다.(아래 catch에서 error발생) // 부모는 모든 예외를 다 잡을 수 있다.(Exception)} finally { // 반드시 실행되어야할 코드}
아래 예제에서는 3개의 RuntimeException이 발생
ArrayIndexOutOfBoundsException
ArithmeticException
NumberFormatException
public class UseRuntimeException { public static void main(String[] args) { int num1 = Integer.parseInt(args[0]); int num2 = Integer.parseInt(args[1]); int result = 0; result = num1/num2; System.out.println(num1+" / "+num2+" = "+result); }}
catch문 안에서 예외처리
에러 출력 스트림 사용을 권장(의미적으로)
일반 사용자에겐 예외 내용을 알려줄 필요가 없음
System.err.println("예외발생시 제공할 내용들");// 1. 간단한 메시지만 출력할 때예외처리객채명.getMessage();System.err.println(e.getMessage());// 2. 예외처리객체명과 메시지 출력예외처리객체명 // 예외처리객체명.toString()과 동일// 3. 자세한 메시지를 출력 (예외와 관련있는 모든 클래스가 다 출력)예외처리객체명.printStackTrace();
public class UseRuntimeException { public static void main(String[] args) { try { int num1 = Integer.parseInt(args[0]); int num2 = Integer.parseInt(args[1]); int result = 0; result = num1/num2; System.out.println(num1+" / "+num2+" = "+result); } catch (ArrayIndexOutOfBoundsException aioobe) { System.err.println("배열의 인덱스가 잘못되었습니다."); System.err.println("예외의 이유 : "+aioobe.getMessage()); System.err.println("예외처리 클래스명과 이유 : "+aioobe); aioobe.printStackTrace(); // 자세한 예외 } catch (ArithmeticException ae) { System.err.println("0으로 나눌 수 없습니다."); System.err.println("예외의 이유 : "+ae.getMessage()); System.err.println("예외처리 클래스명과 이유 : "+ae); ae.printStackTrace(); // 자세한 예외 } catch (NumberFormatException nfe) { System.err.println("입력값이 숫자형태가 아닙니다."); System.err.println("예외의 이유 : "+nfe.getMessage()); System.err.println("예외처리 클래스명과 이유 : "+nfe); nfe.printStackTrace(); // 자세한 예외 } catch (Exception e) { System.err.println("개발자가 인지하지 못한예외."); e.printStackTrace(); } finally { System.out.println("반드시 실행되어야할 코드"); } }}
예외를 왜 나눠서 처리할까?
예외가 발생했을 때 식별해서 다르게 처리하려고
숙제풀이
1-1. 프로그램이 시작되면 아래와 같은 메뉴를 제공한다.
1-2. 1번을 넣고 입력을 누르면 inputDialog를 띄워준다.
입력버튼이 눌려지면 입력값을 VO에 넣고
VO를 List에 추가한 후 메뉴를 보여준다.
값을 잘못 넣었을 시 MessageDialog 보여주기
1-3. 출력(2)를 입력하면, 쌓여있는 List의 크기를 재서 0이면 Message Dialog로 "데이터가 없습니다." 를 출력. 데이터가 하나 이상인 경우 아래와 같이 출력하고 확인버튼이 눌리면 다시 메뉴를 제공
// MessageDialog에 JTextArea 넣기 예제public class Test2 { public static void main(String[] args) { // Message Dialog에 JTextArea넣기 // 1.JTextArea 생성(컬럼수, 행수 설정해서 만듦) JTextArea jta = new JTextArea(10,40); jta.setEditable(false); // 편집막 jta.append("asdjflsjdklfjls"); // 값 덧붙여 넣기 // 2. JScrollPane jsp = new JScrollPane(jta); // 3. Message Dialog의 두번째 매개변수에 컴포넌트를 넣기 JOptionPane.showMessageDialog(null, jsp); }}