반응형



자바로 만든 사칙연산 계산기 입니다.
인턴 출근하고 첫 번째 과제..
인터넷에서 가져온 녀석에 키보드 이벤트가 없어서 이벤트 추가해주고
키보드에 특수기호들 이름을 몰라서 걍 테스트로 System.out.print(블라블라);해서
콘솔에 나오는 숫자 그대로 넣어줬습니다..(부끄..어쨌든 잘 되네요..ㅎ;;)

기본적인 원리!!
입력한 숫자를 기억하고, 어떤 연산을 시켰는지 기억하면서 계산을 해나갑니다. 그리고 마지막 숫자가 들어 온 후 '='을 누르면 결과가 Text창에 뜨는 겁니다.

우선 GUI는 swing으로 덕지덕지 만들었습니다.
버튼들에 이벤트가 발생하면 무언가 일이 진행되게 합니다. 각각의 경우에 맞는 Listener와 Listener가 발견한 이벤트에 대해 할일을 만들어 주는 것이죠. 이벤트가 발생한 녀석이 어느 녀석이냐에따라 다른 일을 합니다. 이 땐 switch-case문을 사용했습니다.
에휴 설명이 허접해지네요ㅠㅠ
주석을 참고하세요^^ 설명을 위해서 주석을 엄청나게 써놨습니다... ㅎㅎ
아.. 프로그래밍 잘하고 싶다 ㅠ

그리고 인터넷에서 긁어온 소스의 닫기버튼에 대한 구현이 아래 처럼 되어 있어서 닫기 버튼을 눌러도 프로세스가 살아있더라구요..
엄청 띄웠더니 컴퓨터가 버벅 거려서 깜짝 놀랐습니다요..

addWindowListener(new WindowAdapter() {
public void windowClosed(WindowEvent e){
System.exit(0);
}
});

그래서 이러게 바꿔줬더니 잘 꺼지는 군요..

addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e){
System.exit(0);
}
});


코드는 아래와 같습니다. 아... 넘 길다 ㅠㅠ 첨부도 할게요...
딱 사칙연산만 하면 좀더 간단했을텐데.. 그래도 윈도우 계산기 켰을때 있는 녀석들은 다 있네요.^^;

 


package cal;
import javax.swing.*;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.*;
public class Calculator extends JFrame implements ActionListener, KeyListener{
 final int MAX_INPUT_LENGTH = 20; //최대한 입력 가능한 길이를 제한하고
 
 //각 모드별로 index를 부여
 final int INPUT_MODE = 0;
 final int RESULT_MODE = 1;
 final int ERROR_MODE = 2;
 int displayMode;
 
 boolean clearOnNextDigit;  //화면에 표시될 숫자를 지울지 말지 결정하는 녀석
 
 double lastNumber;   //마지막에 기억될 수
 String lastOperator;  // 마지막에 누른 연산자를 기억.
 
 private JLabel output;    //숫자가 표시될 공간
 private JButton buttons[];   //각 버튼을 배열로 생성할 것임.
 private JPanel masterPanel, btnPanel, ctrPanel; //버튼과 레이블을 배치할 공간
 
 //GUI를 생성해보자.
 public Calculator(){
  
  setBackground(Color.gray);   //프레임의 배경은 회색
  
  masterPanel = new JPanel();
  
  output = new JLabel("0", JLabel.RIGHT); // 레이블의 초기 값은 0
  output.setBackground(Color.WHITE);
  output.setOpaque(true);
  
  buttons = new JButton[23];
  
  btnPanel = new JPanel();
  
  //숫자 버튼 만듦0에서9까지.
  for (int i=0 ; i<=9 ; i++){
   buttons[i] = new JButton(String.valueOf(i));   
  }
  
  //연산 버튼 만듦.
  buttons[10] = new JButton("±");
  buttons[11] = new JButton(".");
  buttons[12] = new JButton("=");
  buttons[13] = new JButton("/");
  buttons[14] = new JButton("*");
  buttons[15] = new JButton("-");
  buttons[16] = new JButton("+");
  buttons[17] = new JButton("√");
  buttons[18] = new JButton("1/x");
  buttons[19] = new JButton("%");
  
  //컨트롤 버튼 만듦.
  buttons[20] = new JButton("←");
  buttons[21] = new JButton("CE");
  buttons[22] = new JButton("C");
  
  //각 버튼의 색을 다르게
  for(int i=0 ; i<buttons.length ; i++){
   if(i<10){
    buttons[i].setForeground(Color.black); //숫자 버튼들
   }else if(i>=10 && i<21){
    buttons[i].setForeground(Color.blue); //연산자 버튼들
   }else{
    buttons[i].setForeground(Color.red); //컨트롤 버튼들.
   }
  }
  
  //패널에 숫자버튼 및 연산자 버튼 배치
  btnPanel.setLayout(new GridLayout(4,5,2,2));
  
  for(int i=7; i<=9 ; i++){
   btnPanel.add(buttons[i]);
  }
  
  btnPanel.add(buttons[13]); // /
  btnPanel.add(buttons[17]); // √
  
  for(int i=4; i<=6 ; i++){
   btnPanel.add(buttons[i]);
  }
  
  btnPanel.add(buttons[14]); // *
  btnPanel.add(buttons[18]); // 1/x
  
  for(int i=1; i<=3 ; i++){
   btnPanel.add(buttons[i]);
  }
  
  btnPanel.add(buttons[15]); // -
  btnPanel.add(buttons[19]); // %
  
  btnPanel.add(buttons[0]); // 0
  btnPanel.add(buttons[10]); // ±
  btnPanel.add(buttons[11]); // .
  btnPanel.add(buttons[16]); // +
  btnPanel.add(buttons[12]); // =
  
  //컨트롤 패널에 컨트롤 버튼을 배치
  ctrPanel = new JPanel();
  ctrPanel.setLayout(new GridLayout(1,2,2,2));
  
  
  ctrPanel.add(buttons[20]);
  ctrPanel.add(buttons[21]);
  ctrPanel.add(buttons[22]);
  
  
  // 각 컴포넌트를 프레임에 추가
  masterPanel.setLayout(new BorderLayout());
  masterPanel.add(ctrPanel, BorderLayout.NORTH);
  masterPanel.add(btnPanel, BorderLayout.SOUTH);
  
  
  getContentPane().add(output, BorderLayout.NORTH);
  getContentPane().add(masterPanel,BorderLayout.SOUTH);
  requestFocus();
  
  //버튼 ActionListener, Keylistener 활성! 이놈들을 추가해야 버튼에 뭔일이 발생하는지 봅니다.
  for(int i=0 ; i<buttons.length ; i++){
   buttons[i].addActionListener(this);
   buttons[i].addKeyListener(this);
  }
    
  clearAll(); //모든 값을 초기화!!
  
  addWindowListener(new WindowAdapter() {
    public void windowClosing(WindowEvent e){
     System.exit(0);
    }
   }
  );  
 }
 /*생성자 끝~~~~*/
 
 //마우스 입력에 대한 동작
 @Override
 public void actionPerformed(ActionEvent e){
  
  double result = 0;
  
  for(int i=0 ; i<buttons.length ; i++){
   if(e.getSource()==buttons[i]){
    if(i<10){
     addToDisplay(i);
     break;
    }else{
     switch(i){
      case 10: // ±
       processSingChange();
       break;
      case 11: // .
       addPoint();
       break;
      case 12: // =
       processEquals();
       break;
      case 13: // /
       processOperator("/");
       break;
      case 14: // *
       processOperator("*");
       break;
      case 15: // -
       processOperator("-");
       break;
      case 16: // +
       processOperator("+");
       break;
      case 17: // √
       if (displayMode != ERROR_MODE)
       {
          try
        {
         if (getDisplayString().indexOf("-") == 0)
             displayError("Invalid input for function!");
         result = Math.sqrt(getNumberInDisplay());
         displayResult(result);
        }
        catch(Exception ex)
        {
         displayError("Invalid input for function!");
         displayMode = ERROR_MODE;
        }
       }
       break;
      case 18: // 1/x
       if (displayMode != ERROR_MODE){
        try
        {
         if (getNumberInDisplay() == 0)
          displayError("영으로 나눌 수 없습니다.");
  
         result = 1 / getNumberInDisplay();
         displayResult(result);
        }
        
        catch(Exception ex) {
         displayError("영으로 나눌 수 없습니다.");
         displayMode = ERROR_MODE;
        }
       }
       break;
      case 19: // %
       if (displayMode != ERROR_MODE){
        try {
         result = getNumberInDisplay() / 100;
         displayResult(result);
        }
  
        catch(Exception ex) {
         displayError("Invalid input for function!");
         displayMode = ERROR_MODE;
        }
       }
       break;
      case 20: // ←
       backspace();
       break;
      case 21: //CE
       setDisplayString("0");
       clearOnNextDigit = true;
       displayMode = INPUT_MODE;
       break;
      case 22: //C
       clearAll();
       break;       
     }
    } 
   }
  }
 }
 
 
 //키보드 입력에 대한 동작
 public void keyPressed(KeyEvent e){
  int keycode = e.getKeyChar();
  //System.out.println(e.getKeyCode()+ "  "+ keycode ); 요걸로 특수기호 녀석들 코드를 알아냈습니다... ^^;;부끄
  switch(keycode){
   case KeyEvent.VK_0:
    addToDisplay(0);
    break;
   case KeyEvent.VK_1:
    addToDisplay(1);
    break;
   case KeyEvent.VK_2:
    addToDisplay(2);
    break;
   case KeyEvent.VK_3:
    addToDisplay(3);
    break;
   case KeyEvent.VK_4:
    addToDisplay(4);
    break;
   case KeyEvent.VK_5:
    addToDisplay(5);
    break;
   case KeyEvent.VK_6:
    addToDisplay(6);
    break;
   case KeyEvent.VK_7:
    addToDisplay(7);
    break;
   case KeyEvent.VK_8:
    addToDisplay(8);
    break;
   case KeyEvent.VK_9:
    addToDisplay(9);
    break;
   case 46: // .
    addPoint();    
    break;
   case 10: // =
    processEquals();
    break;
   case 47: // /
    processOperator("/");
    break;
   case 42: // *
    processOperator("*");
    break;
   case 43: // +
    processOperator("+");
    break;
   case 45: // -
    processOperator("-");
    break;
   case 8: //backspace
    backspace();
    break;
   case 27: //ESC
    clearAll();
    break;    
  }
 }
 private void clearAll() {
  setDisplayString("0");
  lastOperator = "0";
  lastNumber = 0;
  displayMode = INPUT_MODE;
  clearOnNextDigit = true;
 }
 
 private void backspace(){
  if (displayMode != ERROR_MODE){
   setDisplayString(getDisplayString().substring(0,
       getDisplayString().length() - 1));
   
   if (getDisplayString().length() < 1)
    setDisplayString("0");
  }
 }
 private void processOperator(String string) {
  if (displayMode != ERROR_MODE){
   double numberInDisplay = getNumberInDisplay();
   if (!lastOperator.equals("0")){
    try {
     double result = processLastOperator();
     displayResult(result);
     lastNumber = result;
    }catch(Exception e){}
   
   }else{
    lastNumber = numberInDisplay;
   }
   
   clearOnNextDigit = true;
   lastOperator = string;
  }
 }

 private double processLastOperator() throws Exception{
  double result = 0;
  double numberInDisplay = getNumberInDisplay();
  if (lastOperator.equals("/")){
   if (numberInDisplay == 0)
    throw (new Exception());
   result = lastNumber / numberInDisplay;
  }
   
  if (lastOperator.equals("*")){
   result = lastNumber * numberInDisplay;
  }
  if (lastOperator.equals("-")){
   result = lastNumber - numberInDisplay;
  }
  if (lastOperator.equals("+")){
   result = lastNumber + numberInDisplay;
  }
  
  return result;
 }
 private void processEquals() {
  double result = 0;
  if (displayMode != ERROR_MODE){
   try{
    result = processLastOperator();
    displayResult(result);
   }catch (Exception e){
    displayError("영으로 나눌 수 없습니다.");
   }
   lastOperator = "0";
  }
 }
 private void addPoint() {
  displayMode = INPUT_MODE;
  if (clearOnNextDigit)
   setDisplayString("");
  String inputString = getDisplayString();
 
  // 이미 점이 찍혀 있으면 안 찍음.
  if (inputString.indexOf(".") < 0)
   setDisplayString(new String(inputString + "."));
 }
 private void processSingChange() {
  if (displayMode == INPUT_MODE){
   String input = getDisplayString();
   if (input.length() > 0 && !input.equals("0")){
    if (input.indexOf("-") == 0)
     setDisplayString(input.substring(1));
    else
     setDisplayString("-" + input);
   }
  }else if (displayMode == RESULT_MODE){
   double numberInDisplay = getNumberInDisplay();
  
   if (numberInDisplay != 0)
    displayResult(-numberInDisplay);
  }
 }
 private void displayResult(double result) {
  setDisplayString(Double.toString(result));
  lastNumber = result;
  displayMode = RESULT_MODE;
  clearOnNextDigit = true;
 }
 private void displayError(String error) {
  setDisplayString(error);
  lastNumber = 0;
  displayMode = ERROR_MODE;
  clearOnNextDigit = true;
 }
 private double getNumberInDisplay() {
  String input = output.getText();
  return Double.parseDouble(input);
 }
 private void addToDisplay(int i) {
  if (clearOnNextDigit)
   setDisplayString("");
  
  String inputString = getDisplayString();
  
  if(inputString.indexOf("0") == 0){
   inputString = inputString.substring(1);
  }
  if(( !inputString.equals("0") || i>0 ) && inputString.length() < MAX_INPUT_LENGTH){
   setDisplayString(inputString + i);
  }
  
  displayMode = INPUT_MODE;
  clearOnNextDigit = false;
 }

 private void setDisplayString(String string) {
  output.setText(string);
 }

 private String getDisplayString() {
  return output.getText();
 }
 
 public static void main(String args[]){
  Calculator cal = new Calculator();
  cal.setTitle("Calculator");
  cal.setSize(300,300);
  cal.pack();
  cal.setVisible(true);
  cal.setResizable(false);  
 }
 @Override
 public void keyReleased(KeyEvent arg0) {}
 @Override
 public void keyTyped(KeyEvent arg0) {}
}

반응형
반응형





지금 인턴하고 있는 회사 첫 출근에 과장님께 과제로 받은 것이
자신있는 언어로 사칙연산이 가능한 계산기를 만들고 키보드와 연동하라는 것이었습니다. 
그나마 익숙한 자바로 사칙연산하는 계산기를 만들며 생각난 것이
파이썬으로 하면 정말 간단한 솔루션이 나올것 같은 예감이 들었습니다.
역시나 구글링을 하니 제 예감이 적중했더군요.
50줄도 안되는 계산기입니다...

파이썬에는 eval()이라는 내장 함수가 있습니다.
이 eval() 함수는 인자로 받은 텍스트 데이터를 파이썬 인터프리터가 번역할 수 있는 파이썬 코드로 변환합니다.
GUI는 tkinter 모듈을 이용하면 간단히 만들 수 있군요.

예를 들어 result =eval("1+2*3/4") 이라고 하면 인자에 들어간  텍스트를 파이썬 코드로 변환하여
result에는 1+2*3/4 의 연산 결과인 2.25가 들어가게 되는 것이죠.

정말 획기적이지 않나요??
텍스트 창 안의 내용을 그대로 계산하는 초간단 계산기 였습니다.!!
키보드와 바로 연동되는 것은 아니지만
텍스트 창 안에 수식을 입력하면 바로 계산되어 나왔습니다.

역시 파이썬이 강력한 이유는 유용한 내장함수와 다양한 모듈들 이겠지요!!

코드 출처 : http://lexlove.egloos.com/10763317
#calculator.py
#-*-coding=utf-8-*-
#GUI를 만들어주는 tkinter 모듈을 임포트!
from tkinter import *

#이벤트 처리함수
def enter(btn):
    if btn == 'C':
        ent.delete(0, END)
    elif btn == '=':
        #eval()함수는 텍스트로된 데이터를 바로 파이썬 코드로 변환합니다.대박..
        #그래서 ent라는 곳에 입력된 수식을 바로 계산해 냅니다.
        ans = eval(ent.get())
        ent.delete(0, END)
        ent.insert(0, ans)
    else:
        #C와 =을 제외한 버튼은 그대로 ent에 추가.
        ent.insert(END, btn)

def quit():
    root.destroy()
    root.quit()
#창만들기
root=Tk()
root.title('계산기')

#숫자 입력란 만들기
ent=Entry(root)
ent.insert(0, ' ')
ent.pack(pady=5)

#숫자 버튼 만들기
buttons = ['7410', '852=', '963+', 'C/*-']
for col in buttons:
    frm=Frame(root)
    frm.pack(side=LEFT)
    for row in col :
        btn=Button(frm, text=row, command=(lambda char=row: enter(char)))
        btn.pack(fill=X, padx=5, pady=5)

#프로그램 실행
root.mainloop()
반응형

+ Recent posts