이전에 포스팅한 MVC 2까지의 내용을 응용하여 계산기 프로그램을 구현하고, GUI개념을 Java에 적용하여 버튼식 계산기 프로그램을 구현하였다.
1. MVC 2 내용 응용 _ 계산기 구현
1) 설계
: 코딩 전 구현할 내용 정리 및 설계에 대한 내용 정리
- 전체 흐름 파악
- M -> int num1, String op(+,-), int num2, int res(결과값) 필요
- V -> 입력, 출력메서드 필요
- MVC로 분할 : 사용자 입력 저장에 대해 두가지의 풀이방법 존재
- 사용자 입력 멤버변수로 저장하기 : View에서 진행
- 사용자 입력 메서드(void)로 저장하기 : ModelVO생성 후 진행
2) View
package view;
import java.util.InputMismatchException;
import java.util.Scanner;
// 범위 외 입력 예외처리 목적
class MyException extends Exception{
MyException(String message){
super(message);
}
}
public class CalculatorView {
//멤버변수(사용자의 입력) & 스캐너
Scanner sc = new Scanner(System.in);
MyException myExcep = new MyException("입력을 다시 확인하세요");
String mainMsg = "1. 계산하기 \n2. 종료하기";
//사용자입력 저장할 변수
private int action;
private int num1;
private int num2;
private String op;
//게터세터
public int getAction() {
return action;
}
public void setAction(int action) {
this.action = action;
}
public int getNum1() {
return num1;
}
public void setNum1(int num1) {
this.num1 = num1;
}
public int getNum2() {
return num2;
}
public void setNum2(int num2) {
this.num2 = num2;
}
public String getOp() {
return op;
}
public void setOp(String op) {
this.op = op;
}
// 시작화면
public void StartView() {
System.out.println("===계산기===");
System.out.println(mainMsg);
System.out.println("===========");
while(true) {
try {
System.out.println(">>");
int action = sc.nextInt();
if(action<1 || action>2) {
throw myExcep;
}
this.action = action;
break;
}catch(InputMismatchException e) {
sc.nextLine();
System.out.println("*정수로 입력하세요*");
}catch(Exception e) {
System.out.println(e.getMessage());
}
}
}
// 정수1 입력
public int num1() {
while(true) {
try {
System.out.println("첫번째 정수 : ");
int num1 = sc.nextInt();
this.num1 = num1;
break;
}catch(InputMismatchException e) {
sc.nextLine();
System.out.println("*정수로 입력하세요*");
}catch(Exception e) {
System.out.println(e.getMessage());
}
}
return num1;
}
// 정수2 입력
public int num2() {
while(true) {
try {
System.out.println("두번째 정수 : ");
int num2 = sc.nextInt();
this.num2 = num2;
break;
}catch(InputMismatchException e) {
sc.nextLine();
System.out.println("*정수로 입력하세요*");
}catch(Exception e) {
System.out.println(e.getMessage());
}
}
return num2;
}
// 연산자입력
public String op() {
while(true) {
try {
System.out.println("연산자 : ");
String op = sc.next();
if(op.equals("+") || op.equals("-")) {
this.op = op;
break;
}
if(op.equals("*") || op.equals("/")) {
this.op = op;
break;
}
throw myExcep;
}catch(InputMismatchException e) {
sc.nextInt();
System.out.println("*연산자를 입력하세요*");
}catch(Exception e) {
System.out.println(e.getMessage());
}
}
return op;
}
// 출력메서드
public void print(Object obj) {
for(int i=0; i<5; i++) {
System.out.print("두구");
try {
Thread.sleep(300);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println();
System.out.println(obj);
}
public void endPrint() {
System.out.println("★계산기를 종료합니다★");
}
}
사용자의 입력을 멤버변수에 저장하는 방식으로 진행
3) Model
package model;
public class CalculatorModel {
//멤버변수
private int num1;
private int num2;
private String op;
private int res;
//getter&setter
public int getNum1() {
return num1;
}
public void setNum1(int num1) {
this.num1 = num1;
}
public int getNum2() {
return num2;
}
public void setNum2(int num2) {
this.num2 = num2;
}
public String getOp() {
return op;
}
public void setOp(String op) {
this.op = op;
}
public int getRes() {
return res;
}
public void setRes(int res) {
this.res = res;
}
//계산메서드
public int res(Object obj) {
if (obj.equals("+")){//덧셈
this.res = num1 + num2;
} else if (obj.equals("-")){//뺄셈
this.res = num1 - num2;
} else if (obj.equals("*")) {//곱셈
this.res = num1 * num2;
} else if (obj.equals("/")) {//나눗셈
this.res = num1 / num2;
}
return res;
}
}
*기본생성자를 이용하여 작업 진행*
이때 생성자가 없을 경우, 멤버변수 초기화가 안되는 것을 유의할 것. 즉, setter를 호출해야한다.
4) Controller
package controller;
import model.CalculatorModel;
import view.CalculatorView;
public class CalculatorCtrl {
//접근선언
CalculatorModel model;
CalculatorView view;
//ctrl실행 메서드 : model과 view정보 불러오기
public void ctrlStart () {
model = new CalculatorModel();
view = new CalculatorView();
}
// 앱실행 메서드
public void appStart () {
while(true) {
view.StartView(); //main화면출력
//메인에서 1 입력시 계산실행
if(view.getAction()==1) {
//view의 입력 -> model에 저장
model.setNum1(view.num1());
model.setOp(view.op());
model.setNum2(view.num2());
// syso(num1 + num2 = res); 과 같다
view.print(model.getNum1()+model.getOp()+model.getNum2()
+"="+model.res(model.getOp()));
//메인에서 2 입력시 종료
}else if(view.getAction()==2) {
//종료문구 출력
view.endPrint();
break;
}
}
}
}
5) 실행결과
package class01;
import controller.CalculatorCtrl;
public class Client {
public static void main(String[] args) {
CalculatorCtrl ctrl = new CalculatorCtrl();
//데이터불러오기
ctrl.ctrlStart();
//앱실행
ctrl.appStart();
}
}
[출력화면 : ★ -> 입력]
===계산기===
1. 계산하기
2. 종료하기
===========
>>
1
첫번째 정수 :
8
연산자 :
*
두번째 정수 :
9
두구두구두구두구두구
8*9=72
===계산기===
1. 계산하기
2. 종료하기
===========
>>
종료
*정수로 입력하세요*
>>
2
★계산기를 종료합니다★
2. GUI 자바응용_ 버튼식 계산기 구현
1) 배경이론
UI / UX
UI (User Interface) : "사용자를 마주하다"라는 의미로, 사용자가 앱 사용시 마주하는 디자인, 레이아웃, 기술적인 부분을 말한다. 상세하게는 줄간격, 폰트, 색상, 반응성, 입출력단계, 애니메이션 효과 등 여러 부분을 포함한다.
UX (User Experience) : "사용자의 경험을 녹이다"라는 의미로, 앱을 주로 사용하는 사용자들의 경험(가장 먼저 터치하는 화면, 사용자의 선택 플로우 등)들을 분석하여 그것을 더 편하고 효율적인 방향으로 프로세스가 진행될 수 있도록 하는 과정 및 결과를 뜻한다. UI에서 파생되었다고 보아도 무관하다.
UI / UX에서는 사용자가 서비스를 이용하는 흐름을 잘 이해하는 것이 중요하다.
즉, 사용자 편의성을 항상 고려해야한다.
참고 : https://brunch.co.kr/@aw2sum/36
GUI (Graphical User Interface)
직역하면 "그래픽 사용자 인터페이스"이다.
사용자 편의성을 고려하여 입출력 등의 기능을 알기 쉬운 아이콘, 버튼 등의 그래픽으로 나타낸 것이다.
컴포넌트
제품의 모듈과 유사한 개념으로, 소프트웨어상의 모듈이라고 할 수 있다.
독립적인 기능을 수행하도록 구현하여, 이를 다른 부분에 응용 or 삽입하여 사용할 수 있도록 한다.(핸드폰 탈부착 배터리의 기능과 유사!) 컴포넌트는 소프트웨어의 재사용의 중요성과 필용성을 위해 나온 기술이며, 이로인해 개발시간 단축, 개발비용 절감의 이점을 이행할 수 있다. 추가로 입력을 강제할 수 있다는 특징이 있다.
(ex. 전화번호 입력시 [ ][ ][ ]or[ - - ]따위로 입력을 구체적으로 정의)
참고 : https://mommoo.tistory.com/55
2) View
package view;
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
// 상속을 통해 Frame으로 만듦!
public class CalcView2 extends JFrame{
public JTextField n1, n2;
public JComboBox<String> op;
public JButton btn;
public JLabel res;
//위의 요소들을 여기에 붙인다.
JPanel panel;
// *생성자 내부에서 멤버변수 초기화 진행*
public CalcView2() {
setTitle("계산기 MVC 실습");
n1 = new JTextField(5); //생성자 내부의 칸 크기 설정
n2 = new JTextField(5); //생성자 내부의 칸 크기 설정
op = new JComboBox(); //스크롤박스
// 스크롤박스 내부의 문자표시
op.addItem("+");
op.addItem("-");
op.addItem("/");
op.addItem("x"); //*의 표시
btn = new JButton("계산하기"); //버튼글씨
res = new JLabel(); //버튼
// 모든 GUI View는 레이아웃을 설정한다.
setLayout(new FlowLayout()); //그리드 같은 것
panel = new JPanel();
panel.add(n1);
panel.add(op);
panel.add(n2);
panel.add(btn);
add(panel);
add(res);
setVisible(true); //화면에 안뜨는게 기본
//창의 X버튼을 눌렀을때, 종료되도록한다. -> 미선언시 X눌러도 미종료
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
// 리셋
public void reset() {
n1.setText(""); //공백없이 진행
n2.setText(""); //공백없이 진행
}
}
: 별도의 필기 없이 필드의 주석을 통해 내용 파악이 가능하다.
3) Model
package model;
public class CalcModel2 {
//멤버변수
private int n1, n2, res;
private String op;
//생성자
public CalcModel2(int n1, int n2, String op) {
super();
this.n1 = n1;
this.n2 = n2;
this.op = op;
//model생성자에 인자가 들어오면
//계산메서드 진행을 통해 res값 setting!
calculate();
}
// 메서드에 값변경에 대한 로직이 들어있는 경우.
// 즉, 멤버변수의 값을 초기화하는 로직은 private을 통해 감출 수 있다.
// but, 로직코드는 공개하기
private void calculate() {
if (op.equals("+")){
this.res = plus(n1, n2);
} else if (op.equals("-")){
this.res = minus(n1, n2);
} else if (op.equals("/")){
this.res = divide(n1, n2);
} else if (op.equals("x")){
this.res = multip(n1, n2);
}
}
// 순수 알고리즘 코드! == 컴포넌트
// 이러한 로직코드는 재사용을 위해 open하는 것이 좋다!
public int plus(int n1, int n2) {
return n1 + n2;
}
public int minus(int n1, int n2) {
return n1 - n2;
}
public int divide(int n1, int n2) {
return n1 / n2;
}
public int multip(int n1, int n2) {
return n1 * n2;
}
//결과 출력하는 메서드
public String printRes() {
return n1 + " " + op + " " + n2 + "=" + res;
}
// getter & setter
public int getN1() {
return n1;
}
public void setN1(int n1) {
this.n1 = n1;
}
public int getN2() {
return n2;
}
public void setN2(int n2) {
this.n2 = n2;
}
public int getRes() {
return res;
}
public void setRes(int res) {
this.res = res;
}
public String getOp() {
return op;
}
public void setOp(String op) {
this.op = op;
}
}
: 별도의 필기 없이 필드의 주석을 통해 내용 파악이 가능하다.
4) Controller
package controller;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import model.CalcModel2;
import view.CalcView2;
// FrameView인 경우 버튼에 대한 반응 구현 필수
// 인터페이스를 통해 강제 할 수 있다.
// * 하단 필기내용 참고 *
public class CalcCtrl2 implements ActionListener{ //Listener : 모니터링(감지체크)
CalcView2 view;
public CalcCtrl2 () {
view = new CalcView2();
//뷰에 현재 구현한 Ctrl를 더하는(연결) 작업
view.btn.addActionListener(this);
}
@Override
public void actionPerformed(ActionEvent e) {
// e = 액션 그 차제 : 버튼을 누른 행위
if(e.getSource()==view.btn) { // if,버튼을 눌렀다면
//사용자의 정보의 저장은 String으로 진행됨
String n1 = view.n1.getText();
String n2 = view.n2.getText();
String op = view.op.getSelectedItem().toString();
// 유효성체크
if(!n1.matches("[0-9]+") || !n2.matches("[\\d]+")) {
//정규식
view.res.setText("정수만 입력하세요");
view.reset();
return;
} else if (op.equals("/") && n2.equals("0")) {
view.res.setText("불능");
view.reset();
return;
}
CalcModel2 calc = new CalcModel2(Integer.parseInt(n1), Integer.parseInt(n2), op);
String res = calc.printRes();
view.res.setText(res);
view.reset();
}
}
}
* 필기 : ActionListener *
ActionListener이라는 interface 안에 actionPerformed를 @Override해서 해당 메소드안에 실행코드를 입력하게 되면, 지정한 Component의 액션이 발생했을 때, 실행코드가 작동하게 된다.
5) 실행결과
: 컨트롤러의 초기화만으로 출력 가능
package class01;
import controller.CalcCtrl2;
public class Client2 {
public static void main(String[] args) {
new CalcCtrl2();
}
}
- 실행 가능한 메서드
- 정상입력시
- 비정상입력시
'JAVA' 카테고리의 다른 글
[MVC] 학생관리시스템 : 예제 (0) | 2022.01.17 |
---|---|
[컬렉션 프레임워크] 학생관리시스템_배열리스트 (0) | 2022.01.15 |
[MVC] MVC개념 & DAO·VO (0) | 2022.01.15 |
[파일 입출력] TXT & 이미지형식 (+Wrapper Class) (0) | 2022.01.14 |
[Thread] 블록 & 동기화 (0) | 2022.01.13 |