Archive

Java Day 20 계산기 구현

|

Java Day 20 계산기 구현


  • 완성 화면

계산기


  • 조건

    • 처음 화면에 표시될 내용은 0.

    • 숫자 버튼 클릭시마다 숫자의 마지막에 . 표시
    • 소수점 버튼 클릭시 숫자 중간에 .이 들어가고 이 때는 마지막에 . 이 없다
    • +/- 버튼 클릭시 양수, 음수 전환
    • [숫자] - [연산자] - [숫자] - [연산자] 클릭시 = (equal) 버튼을 클릭하지 않아도 계산의 중간 결과가 화면에 화면에 출력
    • backspace 클릭시 뒤에서부터 한 글자씩 삭제, 이 때 숫자의 마지막 . 은 지워지지 않는다
    • 한 자리 숫자일때 backspace 클릭시 0. 으로 초기화
    • CE 버튼 클릭시 화면에 0. 표시되나 중간 결과가 사라지진 않는다
    • C 클릭시 완전 초기화
    • 0 연타 해도 화면에 0이 연속으로 출력되지 않는다 (소수점 제외)


  • 순서도

    • 레이아웃 및 이벤트 걸기
    • 숫자를 처음 눌렀을 때와 아닐 때를 boolean 값으로 판별
    • 소수점이 눌렸을 때와 아닐 때를 boolean 값으로 판별
    • 사칙연산은 누른 연산자를 변수에 저장하여 switch문으로 연산
    • 각각의 버튼들 구현


  • 코딩

import java.awt.*;
import java.awt.event.*;

public class MyCal extends Frame implements ActionListener {
	// 멤버필드
	private Label disp = new Label("0.", Label.RIGHT);
	private Button[] btn_num = new Button[12];
	private String[] str_num = { "7", "8", "9", "4", "5", "6", "1", "2", "3", "0", "+/-", "." };
	private Button[] btn_func = new Button[3];
	private String[] str_func = { "←", "CE", "C" };
	private Button[] btn_oper = new Button[4];
	private String[] str_oper = { "÷", "×", "-", "+" };
	private Button btn_equ = new Button("=");
	private double result = 0;
	private boolean dotCheck = true;
	private boolean decimal = false;
	private char operator = '+';

Label에 출력되는 값들을 표시하고 중복되는 코드를 방지하기 위해 배열을 이용해서 초기화한다.

결과값이 저장될 변수는 result이다.

boolean dotcheck로 숫자를 누른게 처음인지 판별, 처음이면 true 아니면 false이다.

boolean decimal로 소수점을 눌렀는지 판별, 누르면 true, 초기값은 false이다.

누른 연산자가 무엇인지 담기 위한 operator 변수, 초기값은 + 이다.


// 생성자
public MyCal() {
    super("계산기");
    buildGUI();
    setEvent();
    addWindowListener(new WindowAdapter() {
        @Override
        public void windowClosing(WindowEvent e) {
            System.exit(0);
        }
    });
    setSize(300, 400);
    setResizable(false);
    setVisible(true);
}

buildGUI() 메소드로 레이아웃을 구현한다.

setEvent() 메소드로 각각의 버튼에 이벤트를 건다.

익명 클래스를 이용해서 계산기 window의 X 버튼 클릭시 프로그램 종료를 구현한다.

이하 생략.

// buildGUI() 메소드
public void buildGUI() {// 레이아웃
    setLayout(new BorderLayout(5, 5));
    setBackground(Color.orange);
    Panel main_disp = new Panel(new BorderLayout(5, 5));
    main_disp.add("North", new Label());
    main_disp.add("West", new Label());
    main_disp.add("East", new Label());
    main_disp.add("South", new Label());
    disp.setBackground(Color.white);
    disp.setFont(new Font("SansSerif", Font.BOLD, 20));
    main_disp.add("Center", disp);
    add("North", main_disp);
    Panel main = new Panel(new GridLayout(5, 4, 5, 5));
    for (int i = 0; i < str_func.length; i++) {
        btn_func[i] = new Button(str_func[i]);
        btn_func[i].setFont(new Font("SansSerif", Font.BOLD, 20));
        main.add(btn_func[i]);
    }
    btn_oper[0] = new Button(str_oper[0]);
    btn_oper[0].setFont(new Font("SansSerif", Font.BOLD, 20));
    main.add(btn_oper[0]);
    for (int i = 0; i < str_num.length; i++) {
        btn_num[i] = new Button(str_num[i]);
        btn_num[i].setFont(new Font("SansSerif", Font.BOLD, 20));
        main.add(btn_num[i]);
        switch (i) {
            case 2:
                btn_oper[1] = new Button(str_oper[1]);
                btn_oper[1].setFont(new Font("SansSerif", Font.BOLD, 20));
                main.add(btn_oper[1]);
                break;
            case 5:
                btn_oper[2] = new Button(str_oper[2]);
                btn_oper[2].setFont(new Font("SansSerif", Font.BOLD, 20));
                main.add(btn_oper[2]);
                break;
            case 8:
                btn_oper[3] = new Button(str_oper[3]);
                btn_oper[3].setFont(new Font("SansSerif", Font.BOLD, 20));
                main.add(btn_oper[3]);
                break;
        }
        btn_equ.setFont(new Font("SansSerif", Font.BOLD, 20));
        main.add(btn_equ);
    }
    add("West", new Label());
    add("East", new Label());
    add("South", new Label());
    add("Center", main);
}

GridLayout은 순서대로만 넣어야해서 코드가 좀 복잡해졌다. 숫자 3개 넣고 연산자 1개가 들어갈 수 있도록 for문 안에 switch문으로 제어를 해주었다.


// setEvent() 메소드
public void setEvent() {// 이벤트 걸기
    for (int i = 0; i < btn_num.length; i++) {
        btn_num[i].addActionListener(this);
    }
    for (int i = 0; i < btn_oper.length; i++) {
        btn_oper[i].addActionListener(this);
    }
    btn_equ.addActionListener(this);
    for (int i = 0; i < btn_func.length; i++) {
        btn_func[i].addActionListener(this);
    }
}

for문으로 각각의 버튼 배열을 순회하며 이벤트를 건다.


@Override
public void actionPerformed(ActionEvent e) {
    for (int i = 0; i < btn_num.length - 2; i++) {
        if (e.getSource() == btn_num[i]) {
            if (dotCheck) {					// 숫자를 처음 눌렀을 때
                disp.setText(btn_num[i].getLabel() + ".");
                dotCheck = false;
            } else {						// 숫자를 누른게 처음이 아닐 때
                if (disp.getText().equals("0.") && btn_num[i].getLabel().equals("0"))
                    return; 				// 0 연타 막기
                if (!decimal) {				// 소수점 버튼 안눌렀을 때
                    String temp = disp.getText();
                    temp = temp.substring(0, temp.length() - 1);
                    disp.setText(temp + btn_num[i].getLabel() + ".");
                } else {					// 소수점 버튼 눌렀을 떄
                    String temp = disp.getText();
                    disp.setText(temp + btn_num[i].getLabel());
                }
            }
            return;
        }
    } // end for
    if (e.getSource() == btn_num[btn_num.length - 1]) {// 소수점 클릭시
        dotCheck = false;
        decimal = true;
        return;
    }
    if (e.getSource() == btn_num[btn_num.length - 2]) {// +/- 클릭시
        String temp = disp.getText();
        if (temp.equals("0.")) {
            return;
        } else {
            if (temp.charAt(0) != '-') {
                disp.setText("-" + temp);
            } else {
                disp.setText(temp.substring(1));
            }
        }
        return;
    } // end if
    for (int i = 0; i < btn_oper.length; i++) {// 연산자 클릭시
        if (e.getSource() == btn_oper[i]) {
            calc();
            operator = btn_oper[i].getLabel().charAt(0);
            dotCheck = true;
            decimal = false;
            return;
        }
    } // end for
    if (e.getSource() == btn_equ) {// 등호 클릭시
        calc();
        operator = '+';
        result = 0;
        return;
    }
    if (e.getSource() == btn_func[1]) {// CE 클릭시
        disp.setText("0.");
        dotCheck = true;
        decimal = false;
        return;
    }
    if (e.getSource() == btn_func[2]) {// C 클릭시
        disp.setText("0.");
        operator = '+';
        result = 0;
        dotCheck = true;
        decimal = false;
        return;
    }
    if (e.getSource() == btn_func[0]) {// backspace 클릭시
        String temp = disp.getText();
        if (temp.length() == 2) {// 정수 한 자리
            disp.setText("0.");
            dotCheck = true;
            decimal = false;
            operator = '+';
            return;
        }
        if (temp.length() == 3 && temp.charAt(0) == '-') {// 음수 한 자리
            disp.setText("0.");
            dotCheck = true;
            decimal = false;
            operator = '+';
            return;
        }
        if (temp.length() == 3 && temp.charAt(0) == '0') {// 소수 한 자리
            disp.setText("0.");
            dotCheck = true;
            decimal = false;
            operator = '+';
            return;
        }
        if (temp.charAt(temp.length() - 1) == '.') {	// 정수
            disp.setText(temp.substring(0, temp.length() - 2)+".");
        } else {										// 소수
            disp.setText(temp.substring(0, temp.length() - 1));
        }
        return;
    }
}

action event의 수행내용을 구현한다.


// calc() 메소드
public void calc() {// 계산 기능
    double value = Double.parseDouble(disp.getText());
    switch (operator) {
        case '+':
            result += value;
            break;
        case '-':
            result -= value;
            break;
        case '×':
            result *= value;
            break;
        case '÷':
            result /= value;
            break;
    }
    double temp = result - (int) result;

    if (temp > 0) {
        disp.setText(String.valueOf(result));
    } else {
        disp.setText(String.valueOf((int) result) + ".");
    }
}

결과값의 default는 double형이기에 int로 형변환한 결과값으로 빼주어 그 값이 0보다 큰지 아닌지로 정수와 소수를 구분한다. 소수면 그대로 출력하고 정수면 숫자의 뒤에 **. **이 붙는다



마치며


평소에 아무 생각없이 사용하던 계산기도 이렇게 만들기가 힘들었구나..

처음에는 막연히 어렵게만 느껴졌던 계산기였는데 원리를 알고 연습을 해보니 의외로 할만하다.

boolean 으로 스위치를 키고 끄듯이 활용 할 수 있는 방법을 배웠는데 앞으로 자주 보게 될 것 같다.

awt는 정말 비효율적이지만 dos창에서 벗어나려면 swing과 fx도 공부해야겠다.