- 자바 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와 스택에 대해서도 공부해 두셔야 할 것 같네요~
모두모두 화이팅~!! 개발자분들도 화이팅~
'IT 관련,, > Java관련 언어들' 카테고리의 다른 글
[웹/JSP]서블릿(servlet) 개념 및 기본 예제,, (0) | 2018.08.16 |
---|---|
[웹/jQuery] jQuery에 관한 개요 및 설정들,, (0) | 2018.08.14 |
[웹/JSP]jsp JDBC를 이용한 DB연동하기~ (0) | 2018.08.11 |
[웹/JSP]서블릿(Servlet)과 톰캣설치~ (0) | 2018.08.07 |
[JSP/서블릿]jsp 파일업로드,, (0) | 2018.08.06 |