Java 정리 25
17 Dec 2018
Reading time ~7 minutes
Java 정리 25 - JTable, JTabbedPane, Exception Handling(1)
JTable
- MVC Pattern이 적용된 Component
// 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만 반환하도록 만들면 수정이 불가능해짐
- DefaultTableModel의 isCellEditable은 무조건 true를 반환함
// 수정불가능하도록 변경
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);
}
}
1-4. 3이 입력되면 프로그램을 종료