<PersonMenu를 MVC로 작성하기>
1. 모델 com.encore.person.model
- Person.java (자바빈) : 필드(int no, String name, int age, String job)
- Model.java (데이터 관련 기능을 정의) : 필드 (Vector<Person> - 데이터 저장소)
==> 메소드 : 추가 insert, 삭제 delete, 수정 update, 조회 select
2. 뷰 com.encore.person.view
- MainView.java (시작 뷰, JTable을 통해 사람정보 출력)
필드 : JTable table
JButton bt_insert, bt_del, bt_update, bt_exit
- InputForm.java (사람정보 입력) - 타이틀: 입력폼
필드 : JTextField tf_name, tf_age, tf_job
JButton bt_submit, bt_cancel
bt_submit의 text - 입력
- UpForm.java (사람정보 수정) - 타이틀: 수정폼
필드 : InputForm.java와 동일
bt_submit의 text - 수정
3. 컨트롤러 com.encore.person.control
- Controller.java (전체 프로그램에 대한 흐름제어!!, main()포함)
<Controller>
package com.encore.person.control;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Vector;
import javax.swing.JOptionPane;
import com.encore.person.model.Model;
import com.encore.person.model.Person;
import com.encore.person.view.InputForm;
import com.encore.person.view.MainView;
import com.encore.person.view.UpForm;
public class Controller implements ActionListener{ // 뷰요청을 받기위한 Listener설정
//뷰등록
MainView mainv;
InputForm form;
UpForm upform;
//모델등록
Model m;
int no;//추가될 Person에 부여할 유일한 번호
int selNo;//수정요청시 저장할 번호
public Controller() {
mainv = new MainView();
form = new InputForm();
upform = new UpForm();
m = new Model();
eventUp();
}//생성자
private void eventUp() {//이벤트(소스) 등록
//메인뷰
mainv.bt_insert.addActionListener(this);
mainv.bt_update.addActionListener(this);
mainv.bt_del.addActionListener(this);
mainv.bt_exit.addActionListener(this);
//입력폼
form.bt_submit.addActionListener(this);
form.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
//입력폼 ----> 메인뷰
form.setVisible(false);
mainv.setVisible(true);
}
});
//수정폼
upform.bt_submit.addActionListener(this);
upform.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
//수정폼 ----> 메인뷰
upform.setVisible(false);
mainv.setVisible(true);
}
});
}//eventUp
@Override
public void actionPerformed(ActionEvent e) {//이벤트 처리부
Object ob = e.getSource();
if(ob==mainv.bt_insert) {//1.메인뷰:입력버튼 클릭 (입력폼 요청)
//4.화면이동: 메인뷰 ---> 입력폼
form.initText();
mainv.setVisible(false);
form.setVisible(true);
}else if(ob==form.bt_submit) {//1.입력폼:입력버튼 클릭 (Vector에 데이터 저장 요청)
//2.
String name = form.tf_name.getText().trim();
String age = form.tf_age.getText();
String job = form.tf_job.getText();
//5.유효성검사 (빈값 체크)
if(name ==null || name.equals("")) {
JOptionPane.showMessageDialog(form,"이름입력!!");
form.tf_name.requestFocus();
//return;
}else if(age.length() < 1) {
JOptionPane.showMessageDialog(form,"나이입력!!");
form.tf_age.requestFocus();
}else if(!age.matches("[\\d]+")){
JOptionPane.showMessageDialog(form,"숫자입력!!");
form.tf_age.setText("");//숫자아닌값을 초기화
form.tf_age.requestFocus();
}else if(job.length()==0) {
JOptionPane.showMessageDialog(form,"직업입력!!");
form.tf_job.requestFocus();
}else {//이름~직업: 정상적인 데이터
//뷰로부터 입력된 3개의 데이터를 한개의 변수(Person클래스)로 저장하기
Person addp = new Person(++no, name, Integer.parseInt(age), job);
//3.
m.insert(addp);//벡터에 p저장
Vector<Person> personv = m.selectAll(); //벡터의 전체 Person정 보 얻기
System.out.println(personv);
Vector<Object[]> paramv = m.personToArray(personv);
//Person벡터를 뷰가 원하는 Object[]벡터로 변환
mainv.displayTable(paramv);
//4.
form.setVisible(false);
mainv.setVisible(true);
}
}else if(ob==mainv.bt_update) {//1.메인뷰:수정버튼 클릭(수정폼을 요청)
int row = mainv.table.getSelectedRow(); //선택된 행의 (인덱스)정보
//선택된 행이 첫째행이라면 : row=0
//선택된 행이 두번째행이라면 : row=1
//선택된 행이 없다면 : row=-1
System.out.println("선택된 row="+ row);
if(row == -1) {//선택된 행이 없다면
JOptionPane.showMessageDialog(mainv,"수정하고자 하는 행을 선택!!");
return;//메소드 종료
}
selNo = (int) mainv.table.getValueAt(row, 0);// 0컬럼은 번호컬럼으로 고정!!
// getValueAt(행인덱스, 열인덱스)
Person oldp = m.select(selNo);//벡터에 저장된 Person정보 얻기
upform.tf_name.setText(oldp.getName());
upform.tf_age.setText(oldp.getAge()+""); //13+"" ---> "13"
//JTextField.setText(String text)
upform.tf_job.setText(oldp.getJob());
//mainv.table.getValueAt(행인덱스,열인덱스);
//System.out.println(mainv.table.getValueAt(0,0)); //첫번째 행의 번호 정보
//System.out.println(mainv.table.getValueAt(1,0)); //두번째 행의 번호 정보
//4. 메인뷰 ---> 수정폼
mainv.setVisible(false);
upform.setVisible(true);
}else if(ob == upform.bt_submit) {//1.수정폼: 수정버튼 클릭 ==> Vector데이터수정요청
//수정정보 얻기
String age = upform.tf_age.getText();
String job = upform.tf_job.getText();
// 13 ---> 문자열 변환 ----> 13+"" 또는 ""+13 ===> "13"
// "13" ---> 숫자 변환 ----> Integer.parseInt("13") ===> 13
//age,job을 newp로 묶어주기
Person newp = new Person(); //[no:0, name:null, age:0, job:null]
newp.setAge(Integer.parseInt(age)); //newp.setAge(int age)
//[no:0, name:null, age:14, job:null]
newp.setJob(job);//[no:0, name:null, age:14, job:"중학생"]
newp.setNo(selNo);//[no:1, name:null, age:14, job:"중학생"]
//Vector에 저장된 Person을 수정
m.update(newp);
//JTable에 변경된 Vector를 반영
Vector<Person> v = m.selectAll();//벡터 전체 조회
Vector<Object[]> v2 = m.personToArray(v);//메인뷰JTable원하는 벡터 변화
mainv.displayTable(v2);
//mainv.displayTable(m.personToArray(m.selectAll()));
//페이지 이동 (수정폼(upform) ---> 메인뷰(mainv))
upform.setVisible(false);
mainv.setVisible(true);
}else if(ob == mainv.bt_del) {//1. 메인뷰: 삭제버튼클릭 ==> 특정번호의 Person을 Vector로 부터 삭제요청!!
//대화상자를 통한 삭제번호 입력
//JOptionPane.showInputDialog(Component parentComponent,Object message)
String delNo = JOptionPane.showInputDialog(mainv, "삭제번호:");
//Vector로 부터 일치하는 번호를 가진 Person삭제
boolean flag = m.delete(Integer.parseInt(delNo)); //"2" ----> 2
if(!flag) {
JOptionPane.showMessageDialog(mainv, "존재하지 않는 번호입니다!!");
return;
}
//삭제된 Vector의 갱신내용을 JTable 에 반영 - displayTable(Vector<Object[]>)
mainv.displayTable(m.personToArray (m.selectAll()));
// JTable갱신 <--- Vector<Object[]> <--- Vector<Person>
}else if(ob == mainv.bt_exit) {//1. 메인뷰: 종료버튼클릭 ==> 전체 응용프로그램 종료 요청!!
System.exit(0);
}
}//actionPerformed
public static void main(String[] args) {
new Controller();
}
<Model>
package com.encore.person.model;
import java.util.Vector;
public class Model {
Vector<Person> personV; //데이터 저장소 표현
public Model() {
personV = new Vector<>();
}
public void insert(Person addp) {//외부에서 전달받은 데이터를 Vector에 저장
personV.add(addp);
}
public Vector<Person> selectAll() {
//Vector에 저장된 모든 Person정보를 전달. ==> JTable출력 필요
return personV;
}
public void update(Person newp) {//외부에서 변경될 데이터(newPerson)를 전달받아
//Vector에 저장되어있는 기존 oldPerson을 수정
for(int i=0; i<personV.size(); i++) {//변경할 정보를 저장한 newp를 기존 oldPerson에 적용(변경)하기.
Person oldp = personV.get(i);//기존 저장된 Person정보
if(oldp.getNo() == newp.getNo()) {//일치한 번호를 찾았다면
oldp.setAge(newp.getAge());
oldp.setJob(newp.getJob());
break;
}
}//for
}//update
public boolean delete(int delNo) {//외부에서 삭제할 정보(no)를 받아
//Vector에 저장된 Person(no)중 일치하는 해당Person을 삭제
for(int i=0; i<personV.size(); i++) {//전체 Vector검색
Person oldp = personV.get(i);
if(oldp.getNo() == delNo) {//일치하는 번호 찾기
//해당 인덱스를 가진 Person을 벡터로 부터 삭제!!
personV.remove(i);//실제 데이터 삭제!!
//break;
return true;//삭제에 성공했음을 표현.
}
}//for
return false;//삭제에 실패!!
}//delete
public Person select(int selNo) {//외부에서 조회할 정보(no)를 받아
//Vector에서 일치하는 Person정보를 전달. ==> 수정폼에서 필요
for(int i=0; i<personV.size(); i++) {
Person p = personV.get(i);
if(p.getNo() == selNo) {
return p;
}
}
return null; //Person 못찾았음!!
}
//Vector<Person> personv ---변환---> Vector<Object[]> paramv
public Vector<Object[]> personToArray (Vector<Person> personv) {
Vector<Object[]> paramv = new Vector<>();
for(int i=0; i<personv.size(); i++) {
Person p = personv.get(i);
Object []rowdata= { p.getNo(), p.getName(), p.getAge(), p.getJob()};
paramv.add(rowdata);
}
return paramv;
}
}//Model
<Person>
package com.encore.person.model;
public class Person {// 입력폼에 입력된 데이터를 Person클래스로 묶어주기 위해서!!
private int no;
private String name;
private int age;
private String job;
public Person() {
// TODO Auto-generated constructor stub
}
public Person(int no, String name, int age, String job) {
super();
this.no = no;
this.name = name;
this.age = age;
this.job = job;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
@Override
public String toString() {
return "Person [no=" + no + ", name=" + name + ", age=" + age + ", job=" + job + "]";
}
}
<View>
package com.encore.person.view;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
public class InputForm extends JFrame{
JLabel la_name,la_age,la_job;
public JTextField tf_name,tf_age,tf_job;
public JButton bt_submit, bt_cancel;
public InputForm() {
setTitle("입력폼");
la_name = new JLabel("이름");
la_age = new JLabel("나이");
la_job = new JLabel("직업");
tf_name = new JTextField();
tf_age = new JTextField();
tf_job = new JTextField();
bt_submit = new JButton("입력");
bt_cancel = new JButton("취소");
la_name.setBounds(50,30, 30,30);
la_age.setBounds(50,80, 30,30);
la_job.setBounds(50,130, 30,30);
tf_name.setBounds(90,30, 130,30);
tf_age.setBounds(90,80, 130,30);
tf_job.setBounds(90,130, 130,30);
bt_submit.setBounds(60,180, 70,30);
bt_cancel.setBounds(140,180, 70,30);
setLayout(null);
add(la_name);
add(la_age);
add(la_job);
add(tf_name);
add(tf_age);
add(tf_job);
add(bt_submit);
add(bt_cancel);
setBounds(500,200,280,280);
//setVisible(true);
//setDefaultCloseOperation(EXIT_ON_CLOSE);
}//생성자
public void initText() {//텍스트필드 초기화
tf_name.setText("");
tf_age.setText("");
tf_job.setText("");
tf_name.requestFocus();
}
}//InputForm
package com.encore.person.view;
import java.util.Calendar;
import java.util.Vector;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class MainView extends JFrame implements Runnable{
DefaultTableModel dtm;
public JTable table;
JScrollPane scroll_table;
public JButton bt_insert, bt_update, bt_del, bt_exit;
JLabel la_time;
JPanel southp,northp;
Calendar cal;
public MainView() {
setTitle("MainView");
Object [][]rowData = new Object[0][4];
//[0]행 : 생성될 행
//생성될 행을 0으로 해야 앞으로 addRow()가 0인덱스부터 추가됨.
String []columnNames = {"번호","이름","나이","직업"};
dtm=new DefaultTableModel(rowData, columnNames);
table = new JTable(dtm);
scroll_table = new JScrollPane(table);
bt_insert = new JButton("입력");
bt_update = new JButton("수정");
bt_del = new JButton("삭제");
bt_exit = new JButton("종료");
la_time = new JLabel();
southp = new JPanel();
southp.add(bt_insert);
southp.add(bt_update);
southp.add(bt_del);
southp.add(bt_exit);
northp = new JPanel();
northp.add(la_time);
add("Center",scroll_table);
add("South",southp);
add("North",northp);
Thread t = new Thread(this);
t.start();
setBounds(300,200,350,300);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}//생성자
@Override
public void run() {
try {
while(true) {
cal = Calendar.getInstance();//시스템 날짜정보를 얻어 cal저장!!
String timeStr=cal.get(Calendar.YEAR)+"년 "
+ (cal.get(Calendar.MONTH)+1)+"월 "
+cal.get(Calendar.DATE)+"일 "
+cal.get(Calendar.HOUR)+"시 "
+cal.get(Calendar.MINUTE)+"분 "
+cal.get(Calendar.SECOND)+"초";
la_time.setText(timeStr);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void displayTable(Vector<Object[]> v) {
dtm.setRowCount(0);//출력될 포인트 행을 0으로 셋팅
//dtm.addRow(Object[] rowData);
for(int i=0; i<v.size(); i++) {
Object [] rowData = v.get(i);
dtm.addRow(rowData);
}
}//displayTable
}//MainView
package com.encore.person.view;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
public class UpForm extends JFrame{
JLabel la_name,la_age,la_job;
public JTextField tf_name,tf_age,tf_job;
public JButton bt_submit, bt_cancel;
public UpForm() {
setTitle("수정폼");
la_name = new JLabel("이름");
la_age = new JLabel("나이");
la_job = new JLabel("직업");
tf_name = new JTextField();
tf_name.setEnabled(false);
tf_age = new JTextField();
tf_job = new JTextField();
bt_submit = new JButton("수정");
bt_cancel = new JButton("취소");
la_name.setBounds(50,30, 30,30);
la_age.setBounds(50,80, 30,30);
la_job.setBounds(50,130, 30,30);
tf_name.setBounds(90,30, 130,30);
tf_age.setBounds(90,80, 130,30);
tf_job.setBounds(90,130, 130,30);
bt_submit.setBounds(60,180, 70,30);
bt_cancel.setBounds(140,180, 70,30);
setLayout(null);
add(la_name);
add(la_age);
add(la_job);
add(tf_name);
add(tf_age);
add(tf_job);
add(bt_submit);
add(bt_cancel);
setBounds(500,200,280,280);
//setVisible(true);
//setDefaultCloseOperation(EXIT_ON_CLOSE);
}//생성자
}//UpForm
<스레드> Thread
- 프로세스내에서 순차적으로 동작하는 문장들의 단일 집합.
- 경량(light weight)의 프로세스
- 하나의 프로세스내에 다수개의 스레드를 정의할 수 있으며
다수개의 스레드는 동시에 수행 될 수 있다 (다중스레드)
- 자바에서는 클래스(Thread)와 인터페이스(Runnable)지원
class My extends Thread{
//스레드 특성 메소드
public void run(){
//동시 실행 코드
}
}
※스레드 객체 생성
Thread t = new Thread();
My m = new My();
t.start();
m.start();
//t,m ===> 스레드 객체!!
class My2 extends JFrame implements Runnable{
//스레드 특성 메소드!!
public void run(){
//동시 실행 코드
}
}
My2 m2 = new My2();
//m2는 스레드객체? (X)
----> Runnable객체!! (O)
----> 별도의 Thread객체 생성이 필요.
---> Thread t2 = new Thread(run()메소드의 위치);
---> Thread t2 = new Thread(m2);
---->스레드 시작: t2.start();
<Test>
TVContribution.java -----> 방송국
Customer.java -----> 경쟁적인 성금자 (스레드)
Account.java -----> 모금함 (저금통)
public class Account {//모금함 (저금통)
private int total;
//지불 메소드
public synchronized void deposit(int account) {
/*
동기화(synchronized)
---> 메소드 동기화 (메소드에 진입한 스레드가 있을 경우
다른 스레드들은 대기(LOCK)하게 하는 역할)
synchronized 리턴형 메소드명(){}
---> 블럭동기화, 특정영역 동기화
synchronized(동기화 객체){}
*/
total += account; //total = total+account;
}//deposit
public int getTotal() {
return total;
}
}
public class Customer extends Thread{//경쟁적인 성금자 (스레드)
//목표액: 50만원!!
Account account;//null
public Customer(Account account) {
this.account = account;//new Account();
}
@Override
public void run() {
try {
for(int i=1; i<=200; i++) {
Thread.sleep(50);//0.05초 간격
account.deposit(1000);//모금
System.out.println(getName()+" : "+ i +"회");//자막효과
if(account.getTotal() >= 500000) {//목표액(오십만원) 달성
break;
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}//run
}
public class TVContribution {//방송국
public static void main(String[] args) {
//성금자(Thread) 5명을 모집
/*
Customer c1 = new Customer();
Customer c2 = new Customer();
Customer c3 = new Customer();
Customer c4 = new Customer();
Customer c5 = new Customer();
//c1~c5: Thread객체!!
c1.start();
c2.start();
c3.start();
c4.start();
c5.start();
*/
//1차원 배열 객체생성: 자료형[] 배열명 = new 자료형[사이즈];
Customer[] customers = new Customer[5];
//customers[]={null,null,null,null,null};
Account account = new Account();
for (int i = 0; i < customers.length; i++) {
customers[i] = new Customer(account);//스레드 객체 5개 생성
}
for (int i = 0; i < customers.length; i++) {
customers[i].start(); //모금시작(스레드 시작)
}
try {
for (int i = 0; i < customers.length; i++) {
customers[i].join();//메인 스레드가 다른 스레드 종료까지 기다려라!!
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("총 모금액: "+ customers[0].account.getTotal());
}//main
}
<Test2>
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class MoveThread extends JFrame implements Runnable, ActionListener{
JLabel la;
JButton bt;
int x,y;
public MoveThread() {
setTitle("MoveThread");
ImageIcon icon = new ImageIcon("image/right.gif");
la = new JLabel(icon);
la.setBounds(x,y,55,55);//x,y,가로,세로
bt = new JButton("시작");
bt.setBounds(20,420, 80,30);
setLayout(null);
add(la);
add(bt);
setBounds(200,200, 500,500);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
bt.addActionListener(this);
}//생성자
@Override
public void actionPerformed(ActionEvent e) {
//버튼이 클릭되었을때 스레드 호출!!
//A a = new A(); a.hello(); ===> new A().hello();
//Thread t = new Thread(this);
//t.start();
new Thread(this).start();
}
@Override
public void run() {
try {
while(true) {
Thread.sleep(50);
if(x<=425) {
x+=5;
}else if(y<=400){
y+=5;
}
//la.setLocation(x, y);
la.setLocation(x, y);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}//run
public static void main(String[] args) {
new MoveThread();
}
}
<Test3>
class YouThread extends Thread{
public YouThread(String name) {
super(name);//상위클래스 생성자 호출
}
//스레드 특징 메소드 ---> run : start()메소드를 통해 호출해야 동시 실행이 가능!!
public void run() {
try {
for(int i=1; i<11; i++) {
Thread.sleep(500);//0.5초 대기
System.out.println(getName()+" : "+ i);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}//run
}
public class ThreadTest2 {
public static void main(String[] args) {
//YouThread = Thread클래스!!
//스레드에 이름 부여하기 new Thread(String name)
YouThread t1 = new YouThread("길동스레드");
YouThread t2 = new YouThread("라임스레드");
YouThread t3 = new YouThread("주원스레드");
//스레드 우선순위 부여(1~10) 10:우선순위 가장 높음, 5 ---> 기본값
t1.setPriority(Thread.MAX_PRIORITY);//(10);
t2.setPriority(Thread.MIN_PRIORITY);//(1);
t3.setPriority(Thread.NORM_PRIORITY);//(5);
//스레드 실행
t1.start();
t2.start();
t3.start();
}
}
'JAVA' 카테고리의 다른 글
Inner class & Anonymous class with JAVA & Kotlin (0) | 2020.02.05 |
---|---|
#10 AWT vs Swing,계산기 만들기 (0) | 2018.12.05 |
#9 Event 처리 (0) | 2018.12.02 |
#8 중첩클래스, TUI, AWT, 데이터저장 (0) | 2018.11.26 |
#7 배열사용이유, 배열(Vector), Exception(예외처리), Matches, StringTest (0) | 2018.11.25 |