IT 관련,,/Java관련 언어들

[GUI/Swing]자바 Swing을 이용한 계산기 프로그램

IT깡패's 2018. 7. 28. 13:48
728x90
반응형
SMALL

 

- 자바 GUI/Swing 추가 설명링크

자바 GUI(Swing)를 응용한 프로그램 1 - https://blog.naver.com/sky881012/221324988185

자바 GUI(Swing)를 응용한 프로그램 2 - https://blog.naver.com/sky881012/221325015915

 

안녕하세요~ IT깡패's입니다~

며칠전에 티스토리 초대장을 받고 티스토리 블로그 포스팅을 올리고 있습니다.

네이버블로그보다 상당히 편하고 좋네요~~ 그래서 네이버, 구글 둘 다 운영하려고 합니다~ㅎㅎ

아무튼 이번 포스팅은 자바 GUI/Swing을 이용해서 계산기 프로그램을 만들어보겠습니다~

다른 분들이 짠 계산기 코드를 참조해서 직접 제가 응용해보았습니다.

일단 GUI/Swing로 계산기를 만드려면 GUI/Swing으로 이것저것 기능이 들어간 틀이 필요한데, 저는 여러가지 틀과 함께 java소스파일을 3개로 나누어

만들었습니다.

 

자바 코드를 살펴보죠~~

CalGUI.java

 

package swingEtc;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Panel;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.StringTokenizer;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JTextField;

public class CalGUI extends JFrame implements ActionListener{

	CalLogic c = new CalLogic(); //계산 객체
	int check=-1,soch=0;
	
	
	@Override
	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub

		String mun;//text받아오는역할
		
		switch(e.getActionCommand()){ //getActionCommand() 버튼의 텍스트를 얻어옴 , getSource() 이벤트를 발생한 컴포넌트 얻기
		case "0":
			ch("0");
			break;
		case "1":
			ch("1");
			break;
		case "2":
			ch("2");
			break;
		case "3":
			ch("3");
			break;
		case "4":
			ch("4");
			break;
		case "5":
			ch("5");
			break;
		case "6":
			ch("6");
			break;
		case "7":
			ch("7");
			break;
		case "8":
			ch("8");
			break;
		case "9":
			ch("9");
			break;
		
		//숫자만 두번째 텍스트까지 유지
		case "←":
			mun = jfsum.getText();
			mun= mun.substring(0, mun.length()-1);
			jfsum.setText(mun);
			jf.setText("");
			break;
		case "x2":
			mun = jfsum.getText();
			StringTokenizer t = new StringTokenizer(mun, "+/*-", true);// "+-*"구분값
			String na = null;
			double re = 0;
			
			while (t.hasMoreTokens())
			{
				String x1 = t.nextToken();
			 	na = x1;
			}
			System.out.println(na);
			jfsum.setText(Double.parseDouble(na)*Double.parseDouble(na)+"");
			break;
			
			
		case "√":
			mun = jfsum.getText();
			StringTokenizer t1 = new StringTokenizer(mun, "+/*-", true);// "+-*"구분값
			String na1 = null;
			double re1 = 0;
			
			while (t1.hasMoreTokens())
			{
				String x1 = t1.nextToken();
			 	na1 = x1;
			}
			System.out.println(na1);
			jfsum.setText(Math.sqrt(Double.parseDouble(na1))+"");
			break;

	
 		case "mc":
			jf.setText("");
			jfsum.setText("");
			soch=0; //소수초기화
			break;	
		case "+":
			jf.setText("");
			jfsum.setText(jfsum.getText()+"+");
			break;
		case "-":
			jf.setText("");
			jfsum.setText(jfsum.getText()+"-");
			break;
		case "*":
			jf.setText("");
			jfsum.setText(jfsum.getText()+"*");
			break;
		case "/":
			jf.setText("");
			jfsum.setText(jfsum.getText()+"/");
			break;
		case ".":
			soch=1;//소수계산
			String str = jf.getText();
			jf.setText(str+".");
			jfsum.setText(jfsum.getText()+".");
			break;
			
		case "=":
			c.cal(jfsum.getText());
			double result = c.cal(jfsum.getText());
			if(soch==1)
			{
				jf.setText(result+"");//setText안에는 문자열이 들어가니까
				jfsum.setText(result+"");
			}
			else
			{
				jf.setText((int)result+"");//setText안에는 문자열이 들어가니까
				jfsum.setText((int)result+"");
			}
			check = 0; // =을 쓰고 나서는 초기화
			break;
			
		}
	}
	
	
	
	
	JTextField jfsum,jf;
	String[] str = {"←","√","mc","x2","+","7","8","9","-","4","5","6","*","1","2","3","/","0",".","="};
	JButton[] b = new JButton[20];
	JButton clear;
	Font jffont = new Font("arian", Font.BOLD, 40);//폰트 설정
	Font bfont = new Font("arian", Font.BOLD, 20);//폰트 설정
	
	CalGUI()
	{
		setTitle("계산기");  //이름
		setSize(500, 500); //크기
		setLayout(new BorderLayout());
		getContentPane().setBackground(Color.PINK);//뒷배경 판넬
		
		//------------메뉴바 만들기------------------
		JMenuBar mb= new JMenuBar();
		JMenu menu1 = new JMenu("보기(v)");
		menu1.setMnemonic('v'); //단축키 사용 alt+v
		JMenuItem item1 = new JMenuItem("Open");
		item1.setMnemonic('o');
		menu1.add(item1);
		
		JMenu menu2 = new JMenu("도움말(H)");
		menu2.setMnemonic('H');
		JMenuItem item2 = new JMenuItem("Help");
		item2.setMnemonic('h');
		menu2.add(item2);
		   
		mb.add(menu1);
		mb.add(menu2);
		setJMenuBar(mb);//프레임에 menubar 붙이기
		
		//------------버튼 달기---------------------
		
		//첫번째 패널 만들기
		
		Panel tp = new Panel();//textField 판넬,첫번쨰 판넬
		tp.setLayout(new GridLayout(2,1));
		jfsum = new JTextField(getWidth());
		jf = new JTextField(getWidth());
		jf.setFont(jffont);
		jfsum.setHorizontalAlignment(JTextField.RIGHT);
		jf.setHorizontalAlignment(JTextField.RIGHT);
		jf.setEditable(false);
		tp.add(jfsum);
		tp.add(jf);
		
		//두번째 패널 만들기(버튼)
		Panel bp = new Panel();
		bp.setLayout(new GridLayout(5,4));
		for(int i=0;i<20;i++)
		{
			b[i]=new JButton(str[i]);
			b[i].addActionListener(this);
			b[i].setFont(bfont);
			bp.add(b[i]);
		}
		
			
		add(BorderLayout.NORTH,tp);  //TextField panel을 Frame에 붙이기
		add(BorderLayout.CENTER,bp); //버튼 panel을 Frame에 붙이기
		
		
		
		//-------------프레임 위치-------------------
		Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
		setLocation((dim.width/2)-(getWidth()/2), (dim.height/2)-(getHeight()/2)); //중앙에 배치
		//여기서 주의할점 getWidth()를 하는데 만약 setSize를 밑에줄에 적어주면 0으로 잡히기 떄문에 크기값을 위에서 잡아줄것.	
		setResizable(false);//크기 고정
	}
	
	public void ch(String a){  // = 이후인지 전인지 판별 , = 사용한다음 숫자를 누르면 바로 두번째 textField는 초기화 되어야함.
		if(check == 0)
		{
			jfsum.setText(jfsum.getText()+a);
			jf.setText(""+a);
			check=-1;
		}
		else
		{
			jf.setText(jf.getText()+a);
			jfsum.setText(jfsum.getText()+a);
		}
		
	}
	
		

//C버튼은 계산기를 완전히 초기화시킵니다. 계산했던 내용을 모두 지웁니다. 다른 계산을 하기 전에는 계산기를 리셋하는 것이 좋습니다.
//CE버튼은 모두 지우는 것이 아니라, 방금 전에 최종적으로 입력했던 숫자 1개만 지웁니다. 수식을 입력하다가 오타가 났을 때 지우는 버튼입니다.
public static void main(String[] args) {
	
	// TODO Auto-generated constructor stub
			CalGUI c = new CalGUI();
			c.setVisible(true);
}
}

 

계산기 틀이 전반적으로 틀이 들어간 코드입니다. 0~9까지의 글씨가 써진 버튼을 만들고 클릭하면 위에 텍스트 영역에 나타나게 됩니다. 그리고 +, -, =등

다양한 사칙연산 기능이 되게끔 만들었습니다. √를 누르면 제곱근도 계산하게 됩니다.

 

다음은 다른 세부 기능이 들어간 코드 두개를 살펴보겠습니다.
Calculator.java

 

package swingEtc;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class Calculator {
   
    private String[] delim = { "+", "-", "*", "/" , "(", ")" };
    private Stack tokenStack = new Stack();
    private Stack exprStack = new Stack();
    private List postOrderList = new ArrayList();
    
    private void makeTokens(String s) {
        StringBuffer tokenBuf = new StringBuffer();
        int argSize = s.length();
        String token = null;
        for(int i = 0; i < argSize; i++) {
            token = s.substring(i, i+1);
            if(!isDelim(token)) {
                tokenBuf.append(token);
                
                if(i == argSize - 1) {
                    tokenStack.push(tokenBuf.toString());
                }
            } else {
                if(tokenBuf.length() > 0) {
                    tokenStack.push(tokenBuf.toString());
                    tokenBuf = new StringBuffer();
                }
                
                tokenStack.push(token);
            }
        }
    }
    
    /**
     * 구분자인지 검사
     * @param s
     * @return
     */
    private boolean isDelim(String s) {
        boolean bDelim = false;
        
        int delimSize = delim.length;
        for(int i = 0; i < delimSize; i++) {
            if(delim[i].equals(s)) {
                bDelim = true;
                break;
            }
        }
        
        return bDelim;
    }
    
    /**
     * 연산자인지 검사
     * @param s
     * @return
     */
    private boolean isOpcode(String s) {
        boolean opcode = isDelim(s);
        
        if("(".equals(s) || ")".equals(s)) {
            opcode = false;
        }
        
        return opcode;
    }

    /**
     * PostOrder로 변환
     * @param expr
     * @return
     */
    private void convertPostOrder(String expr) {
        for(String token : tokenStack) {
            if(isDelim(token)) {
                exprAppend(token);
            } else {
                postOrderList.add(token);
            }
        }
        
        // exprStack에 자료가 남아 있으면 출력한다
        String item = null;
        while(!exprStack.isEmpty()) {
            item = exprStack.pop();
            postOrderList.add(item);
        }
    }
    
    /**
     * 연산자를 비교해서 postorder방식에 표시 할지 스택에 넣을지 확인
     * @param postOrderBuf
     */
    private void exprAppend(String token) {
        // '(' 일 경우 스택에 넣는다
        if("(".equals(token)) {
            exprStack.push(token);
            return;
        }
        
        // ')' 일 경우 '('가 나올 때 까지 출력한다
        if(")".equals(token)) {
            String opcode = null;
            while(true) {
                opcode = exprStack.pop();
                if("(".equals(opcode)) {
                    break;
                }
                
                postOrderList.add(opcode);
            }
            
            return;
        }
        
        // 연산자일 경우 스택에서 pop하여 낮은 우선순위를 만날때 까지 출력하고 자신을 push
        if(isOpcode(token)) {
            String opcode = null;
            while(true) {
                if(exprStack.isEmpty()) {
                    exprStack.push(token);
                    break;
                }
                
                opcode = exprStack.pop();
                if(exprOrder(opcode) > exprOrder(token)) {
                    postOrderList.add(opcode);
                } else {
                    exprStack.push(opcode);
                    exprStack.push(token);
                    break;
                }
            }
            
            return;
        }
    }
    
    /**
     * 값을 계산한다
     * @return
     */
    public double calculate(String expr) {
        // 토근을 만든다
        makeTokens(expr);
        
        // postOrder로 변환
        convertPostOrder(expr);
        
        Stack calcStack = new Stack();
    
        // postOrder 리스트의 값을 calcStack에 저장
        for(String s : postOrderList) {
            calcStack.push(s);
            calcPostOrder(calcStack);
        }
        
        // 스택의 최종 값을 반환한다
        double result = Double.parseDouble(calcStack.pop());
        
        return result;
    }
    
    /**
     * 스택에서 pop연산을 하여 계산 가능하면 계산 후 값을 스택에 넣는다
     * @param calcStack
     */
    private void calcPostOrder(Stack calcStack) {
        // 연산자가 아니면 계산을 하지 않는다
        if(!isOpcode(calcStack.lastElement())) {
            return;
        }
        
        // 3개를 꺼내야 하므로 3개 이상인지 검사
        String op1 = null;
        String op2 = null;
        String opcode = null;
        if(calcStack.size() >= 3) {
            opcode = calcStack.pop();
            op1 = calcStack.pop();
            op2 = calcStack.pop();
            
            // 값을 계산하여 스택에 넣는다
            double result = calculateByOpCode(op1, op2, opcode);
            calcStack.push(Double.toString(result));
        }
    }
    
    private double calculateByOpCode(String op1, String op2, String opcode) {
        double d1 = Double.parseDouble(op1);
        double d2 = Double.parseDouble(op2);
        
        double result = 0.0;
        if("+".equals(opcode)) {
            result =  d2 + d1;
        } else if("-".equals(opcode)) {
            result =  d2 - d1;
        } else if("*".equals(opcode)) {
            result =  d2 * d1;
        } else if("/".equals(opcode)) {
            result =  d2 / d1;
        }
        
        return result;
    }
    
    /**
     * 연산자 순위를 리턴한다
     * @param s1
     * @param s2
     * @return
     */
    public int exprOrder(String s) {
        int order = -1;
        if("-".equals(s) || "+".equals(s)) {
            order = 0;
        } else if("*".equals(s) || "/".equals(s)) {
            order = 1;
        }
        
        return order;
    }
    
    
    public static void main(String[] args) {
        Calculator cal = new Calculator();
        System.out.println(cal.calculate("1.2+11*4"));
    }    
    
}

 

 


CalLogic.java

 

 

package swingEtc;

import java.util.StringTokenizer;

public class CalLogic {
	
	public double cal(String str) {

		StringTokenizer t = new StringTokenizer(str, "+-*/", true);

	}	

 

Calculator.java는 본격적인 계산기 프로그램의 기능코드고, 마지막 CalLogic.java는 자바 StringTokenizer함수를 사용한 코드입니다.

StringTokenizer함수란, String을 token단위로 끊어서 사용하는 함수입니다.

출력결과도 한번 살펴보시면 이해하기 쉬울것같네요~

 

그리고 연산을 막하다가 계산이 초과하면 Infinity가 뜨게 됩니다~

초과계산이죠~~

 

어느정도는 저런 단어가 안뜨게 되고 조정도가 넘어가면 뜨게 됩니다. 또 저기서 계산하게 되면 예외처리가 뜨면서 자바에 계속 메시지가 뜨게됩니다.

자바 계산기 코딩도 많이 알아둬야 되지만 StringTokenizer와 스택에 대해서도 공부해 두셔야 할 것 같네요~

모두모두 화이팅~!! 개발자분들도 화이팅~

728x90
반응형
LIST