-
TIL #22 - Swing프로그래밍/TIL(국비과정) 2020. 4. 27. 19:46
앞서 사용한 것은 AWT였다.
오늘 사용할 것은 Swing이다.
awt Component 앞에 J를 추가해주면된다.
AWT SWING java.awt.*; javax.swing.*; platform에 종속 flatform에 free 중량 Component 경량 Component Frame 자체에 분할 Frame 포함 멤버 범용 Component Local swing을 이용해 아래와 같은 table을 만들어 저장, 삭제, 아이디값 제외 수정이 되게 만들어보았다.
먼저 테이블에 들어갈 한 사람 분량의 데이터를 넣을 클래스 PersonDTO를 만든다.
아이디, 이름, 비밀번호, 전화번호 모두 String으로 받고 보낸다.
class PersonDTO { private String id; private String name; private String pwd; private String tel; public PersonDTO(String id, String name, String pwd, String tel){ this.id = id; this.name = name; this.pwd = pwd; this.tel = tel; } // getter public String getId(){ return id; } public String getName(){ return name; } public String getPwd(){ return pwd; } public String getTel(){ return tel; } }
이제 JTableEx.java에 가 필드값을 설정한다.
import java.awt.Container; import java.awt.FlowLayout; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; import java.util.ArrayList; import java.util.Vector; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JPanel; import javax.swing.table.DefaultTableModel; import javax.swing.JOptionPane; class JTableEx2 extends JFrame implements ActionListener{ private ArrayList<PersonDTO> list; private Vector<String> vector; private DefaultTableModel model; private JTable table; private JButton addBtn, delBtn; private JPanel p;
PersonDTO를 저장할 ArrayList, 각 행을 위한 Vector,
DefaultTableModel의 경우엔 JTable이 직접 삭제, 추가 기능을 할 수 없어서 DefaultTableModel 클래스 안의 addRow(), removeRow()를 가져오기 위해 사용한다.
나머지는 앞에 J가 붙는거 외엔 awt 때와 같다.
또, 버튼 이벤트를 수행해야하기 때문에 ActionListener 인터페이스를 implements 했다.
먼저, 샘플용으로 ArrayList를 생성하고 list 안에 행을 3개 넣어놓는다.
public JTableEx2(){ list = new ArrayList<PersonDTO>(); // 리스트 생성 list.add(new PersonDTO("Yang", "양아무개", "111", "010-123-1456")); list.add(new PersonDTO("Choi", "최아무개", "333", "010-666-7777")); list.add(new PersonDTO("Park", "최아무개", "444", "010-666-7777"));
그런 후 테이블의 타이틀로 사용할 가장 위의 행을 vector로 넣는다.
// 타이틀 vector = new Vector<String>(); vector.addElement("아이디"); vector.addElement("이름"); vector.add("비밀번호"); vector.add("전화번호"); // addElement와 add는 같다.
(혹시 벡터 말고 다른 방법으로 가능하다면 댓글로 알려주시면 감사하겠습니다.)
model = new DefaultTableModel(vector, 0); table = new JTable(model); JScrollPane scroll = new JScrollPane(table);
model을 생성해 vector에 대한 정보들을 넣고 미리 행을 설정해 놓지 않고록, vector의 밑의 칼럼을 빈 칼럼들로
만들어 놓기 위해 0을 지정한다.
그런 다음 model을 JTable에 넣는다.
Scroll을 생성해 주지 않으니 vector값이 나타나지 않아서 scroll도 선언해주고 그 안에 table을 넣는다.
scroll에 table을 넣어준 시점부터 table과 관련된 일들을 수행하기 위해 table을 부르고자 하면 scroll을 불러야한다.
이제 list에 넣어놓은 데이터들을 table의 행을 관리하는 vector에 넣어 진짜 table에 데이터들이 나타나게 한다.
for(PersonDTO dto : list){ Vector<String> v = new Vector<String>(); // 들어갈 때는 항상 Vector로 들어가짐 v.add(dto.getId()); v.add(dto.getName()); v.add(dto.getPwd()); v.add(dto.getTel()); // 여기까지가 딱 벡터 한 줄 model.addRow(v); }// for
list에 넣은 것은 어디까지나 PersonDTO 타입의 테이터들을 한데 모아놓은 것이고,
JTable에 올라간 것이 아니다.
현재 DefaultTableModel 클래스에 Vector을 넣었기 때문에 JTable의 행을 관리하는 것은 Model 안의 Vector이다.
그렇기 때문에 Vector에 값을 넣어야 JTable에 값이 나타난다.
따라서 list의 데이터들을 vector에 넣는다.
그리고 그 vector는 model 안에 있기 때문에 model을 통해서 addRow()를 해줘야한다.
데이터를 다 넣어줬다면 추가 / 삭제 버튼을 생성한다.
// 버튼 추가 addBtn = new JButton("추가"); delBtn = new JButton("삭제");
버튼은 South 방향의 오른정렬을 나란히 해놓을 것이기 때문에 Panel로 묶어준다.
p = new JPanel(new FlowLayout(FlowLayout.RIGHT)); // 버튼 오른 정렬 p.add(addBtn); p.add(delBtn); add("South",p);
화면에 출력될 모든 컴포넌트들이 부착되는 공간인 Content Pane을 Container가 가져온다.
Content Pane은 타이틀 바를 가진 Frame의 위에 위치한다.
Container c = getContentPane(); // container 올리기 c.add("Center", scroll);
Container에는 table을 올린다.
scroll은 아까 table을 scroll에 넣었기 때문에 table 대신 scroll을 넣어주는 것이다.
아래는 frame에 대한 설정이다.
setBounds(700, 100, 500, 400); setVisible(true); setDefaultCloseOperation(EXIT_ON_CLOSE);
생성자가 끝나기 전, 버튼들에 대한 이벤트를 불러온다.
// 이벤트 addBtn.addActionListener(this); delBtn.addActionListener(this); }// JTableEx2()
이제 버튼에 대한 actionPerformed 메서드를 선언한다.
public void actionPerformed(ActionEvent e){ if(e.getSource() == addBtn){ insert(); }else if(e.getSource() == delBtn){ delete(); } }
각각 newBtn과 delBtn을 눌렀을 때 수행할 동작을 나타내는데 두 코드가 기므로 따로 insert()와 delete() 메서드로 뺀다.
먼저 insert() 메서드이다.
데이터 입력은 별도의 Dialog(대화 상자)를 띄워서 입력받는다.
단, 데이터 입력전에 아이디를 먼저 입력해서 중복이 있는지 없는지부터 검사한다.
// insert public void insert(){ String id = JOptionPane.showInputDialog(this, "아이디를 입력하세요");
아이디가 없으면 insert() 메서드를 그냥 나가고 중복이면 사용중이라는 메시지를 띄우고 나가도록 한다.
아무 문제 없으면 데이터들을 차례차례 입력받고 테이블에 추가한다.
먼저 아이디 유무 검사이다.
if(id == null || id.length() == 0) { JOptionPane.showMessageDialog(this, "아이디는 필수입력입니다."); return;// insert() 나감 }
id == null 이거나 id의 길이가 0일 경우엔 아이디가 없다고 간주하고 메시지를 띄우고 insert()를 나간다.
다음은 아이디 중복 검사이다.
model 클래스에 원래 있는 getRowCount() 메서드를 통해 행의 갯수를 새고 그 만큼 for문을 돌려 검사한다.
for(int i = 0; i < model.getRowCount(); i++){ if(id.equals(model.getValueAt(i,0))){ // 아이디 중복시 JOptionPane.showMessageDialog(this, "사용중인 아이디입니다"); return; // insert 나감 } }
중복 검사는 getValueAt() 메서드로 한다.
아이디값은 i행 0열에 위치하고 있으므로 getValueAt(i, 0) 의 값을 가져와 입력한 id 값과 비교한다.
만약 같을 시 사용중이라는 메시지를 띄워 insert() 메서드를 나간다 (return)
두 검사를 모두 통과했다면 Dialog를 통해 데이터를 입력받는다.
String name = JOptionPane.showInputDialog(this, "이름을 입력하세요."); String pwd = JOptionPane.showInputDialog(this, "비밀번호를 입력하세요."); String tel = JOptionPane.showInputDialog(this, "전화번호를 입력하세요.");
앞에서도 마찬가지 였지만 데이터가 JTable에 들어갈 땐 항상 Vector로 들어가야한다.
따라서 Vector를다시 생성해주고 그 안에 입력받은 데이터들을 넣는다.
Vector<String> v = new Vector<String>(); // 들어갈 때는 항상 Vector로 들어가짐 v.add(id); v.add(name); v.add(pwd); v.add(tel);
벡터로 저장된 데이터는 다시 벡터들(행)을 모아두고 있는 Model 안에 추가한다.
model.addRow(v); }// insert()
여기까지가 insert()이다.
다음은 delete() 메서드이다.
delete 메서드의 경우엔 이름을 통해 행을 찾아 삭제한다.
단, 중복된 이름이 있는 행이 여러개 있을 경우 해당 이름을 포함하고 있는 행 전부를 지운다.
public void delete(){ int sw = 0; String name = JOptionPane.showInputDialog(this, "이름을 입력하세요");
행이 삭제되었는지 확인이 필요하기 때문에 sw라는 스위치 변수를 둔다.
삭제가 잘 되었다면 0이 아닌 다른 수로 바꾼다.
for(int i = 0; i < model.getRowCount(); i++){ if(name.equals(model.getValueAt(i, 1))){ model.removeRow(i); i--; sw = 1;
입력받는 값을 table에서 찾는 것은 위의 insert와 동일하다.
단 removeRow()로 행을 지웠을 경우 for문으로 인해 단 하나의 행만 제거해도 인덱스 값들이 1씩 증가를 하게 된다.
예를 들어 0, 1, 2 인덱스를 가진 행 세개가 있다고 가정하자.
이 중에서 yang이라는 이름을 포함하고 있는 행을 찾아보지 인덱스 0과 2가 발견되었다.
그 중에서 먼저 0번째 인덱스를 지우고 for문이 한 바퀴를 돌았다고 가정한다.
그러면 0이 없어짐으로 인해 인덱스들이 공백을 채움으로 인해 0, 1 인덱스가 된 행들이 남게 된다.
하지만 맨 처음에 0과 2 인덱스에서 삭제해야할 행이 있었는데 i++로 인해 for문이 한바퀴 돌았고
돌아오니 인덱스 값들이 변해있다.
그럼 삭제하고자 했던 인덱스 2를 엉뚱한 곳에서 찾게 되는 것이다.
이를 방지하기 위해 삭제할 인덱스가 남아있을 경우에 i--를 사용해 for문이 한바퀴 돌아 다음 차례로 넘어가지 않도록 만들어 인덱스 값들이 변하지 않도록 한다.
마지막으로 삭제가 완료되었으면 스위치변수 sw 값을 변경시킨다.
만약 for문을 빠져나와보니 스위치변수 sw가 그대로 0이라면 삭제가 이뤄지지 않은 것이므로
삭제할 이름이 없다는 메시지를 띄운다.
if(sw == 0){ JOptionPane.showMessageDialog(this, "삭제할 이름이 없습니다."); } }// delete()
public static void main(String[] args) { new JTableEx2(); } }
'프로그래밍 > TIL(국비과정)' 카테고리의 다른 글
TIL #24 - I/O (0) 2020.04.29 TIL #23 - 스레드, I/O, 파일 (0) 2020.04.28 TIL #21 - SingleTon, Synchronized (0) 2020.04.24 TIL #20 - Comparable, Exception, 스레드 (0) 2020.04.22 TIL #19 - 제네릭, Collection, ArrayList, Set, Map (0) 2020.04.21