==== 2018年4月19日 17:56:20 更新 ===
项目地址在:https://github.com/qiao1406/java_calcultor/tree/dev
这两个星期学习了swing模块的一些内容,学习了java的GUI编程,自己动手写了一个计算器
首先是整个计算器的图形框架类CalFrame类
package Calculator;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class CalFrame extends JFrame {
//配色
private final static Color OP_COLOR = new Color(251, 150, 110);
private final static Color NUM_COLOR = new Color(36, 147, 190);
private final static Color EQUAL_COLOR = new Color(239, 187, 36);
private final static Color CLR_COLOR = new Color(50, 252, 75);
private final static Color DEL_COLOR = new Color(0, 152, 120);
private final static Font FONT1 = new Font("黑体", Font.BOLD, 20);
private final static Font FONT2 = new Font("微软雅黑", Font.PLAIN, 20);
private final static Font FONT3 = new Font("微软雅黑", Font.PLAIN, 15);
private JButton num0 = new JButton("0");
private JButton num1 = new JButton("1");
private JButton num2 = new JButton("2");
private JButton num3 = new JButton("3");
private JButton num4 = new JButton("4");
private JButton num5 = new JButton("5");
private JButton num6 = new JButton("6");
private JButton num7 = new JButton("7");
private JButton num8 = new JButton("8");
private JButton num9 = new JButton("9");
private JButton decimalPoint = new JButton(".");
private JButton addButton = new JButton("+");
private JButton minusButton = new JButton("-");
private JButton mulButton = new JButton("X");
private JButton divButton = new JButton("÷");
private JButton equalButton = new JButton("=");
private JButton leftBracket = new JButton("(");
private JButton rightBracket = new JButton(")");
private JButton clearButton = new JButton("Clear");
private JButton deleteButton = new JButton("Del");
private JLabel equationLabel = new JLabel("算式");
private JLabel resultLabel = new JLabel("结果");
private JTextArea equation = new JTextArea(2,30);
private JTextArea result = new JTextArea(1,30);
private JPanel jp1 = new JPanel();
private JPanel jp2 = new JPanel();
public CalFrame () {
equation.setEditable(false);
result.setEditable(false);
//颜色,字体设置
colorAndFontSettings();
//添加动作
actionSettings();
//设置各个组成部分的位置
positionSettings();
//其他设置
setLayout( new GridLayout(2,1));
add(jp1);
add(jp2);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
setTitle("QiaoCalculator v2.3");
setSize(500, 400);
setLocation(200, 200);
setVisible(true);
}
public static void main ( String[] args ) {
new CalFrame();
}
private void colorAndFontSettings () {
equationLabel.setFont(FONT2);
resultLabel.setFont(FONT2);
equation.setFont(FONT3);
result.setFont(FONT3);
num0.setBackground(NUM_COLOR);
num1.setBackground(NUM_COLOR);
num2.setBackground(NUM_COLOR);
num3.setBackground(NUM_COLOR);
num4.setBackground(NUM_COLOR);
num5.setBackground(NUM_COLOR);
num6.setBackground(NUM_COLOR);
num7.setBackground(NUM_COLOR);
num8.setBackground(NUM_COLOR);
num9.setBackground(NUM_COLOR);
decimalPoint.setBackground(NUM_COLOR);
addButton.setBackground(OP_COLOR);
addButton.setFont(FONT1);
minusButton.setBackground(OP_COLOR);
minusButton.setFont(FONT1);
mulButton.setBackground(OP_COLOR);
mulButton.setFont(FONT1);
divButton.setBackground(OP_COLOR);
divButton.setFont(FONT1);
leftBracket.setBackground(OP_COLOR);
leftBracket.setFont(FONT1);
rightBracket.setBackground(OP_COLOR);
rightBracket.setFont(FONT1);
equalButton.setBackground(EQUAL_COLOR);
equalButton.setFont(FONT1);
clearButton.setBackground(CLR_COLOR);
deleteButton.setBackground(DEL_COLOR);
}
private void actionSettings () {
num0.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
equation.setText(equation.getText() + "0");
}
});
num1.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
equation.setText(equation.getText() + "1");
}
});
num2.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
equation.setText(equation.getText() + "2");
}
});
num3.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
equation.setText(equation.getText() + "3");
}
});
num4.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
equation.setText(equation.getText() + "4");
}
});
num5.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
equation.setText(equation.getText() + "5");
}
});
num6.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
equation.setText(equation.getText() + "6");
}
});
num7.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
equation.setText(equation.getText() + "7");
}
});
num8.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
equation.setText(equation.getText() + "8");
}
});
num9.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
equation.setText(equation.getText() + "9");
}
});
decimalPoint.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
equation.setText(equation.getText() + ".");
}
});
addButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
equation.setText(equation.getText() + "+");
}
});
minusButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
equation.setText(equation.getText() + "-");
}
});
mulButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
equation.setText(equation.getText() + "X");
}
});
divButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
equation.setText(equation.getText() + "÷");
}
});
leftBracket.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
equation.setText(equation.getText() + "(");
}
});
rightBracket.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
equation.setText(equation.getText() + ")");
}
});
equalButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String cmd = equation.getText();
Calculate cl = new Calculate();
String resultMsg = cl.calResult(cmd);
if ( resultMsg.equals("算式格式错误") || resultMsg.equals("除数不能为0") ) {
JOptionPane.showMessageDialog(null, resultMsg, "错误", JOptionPane.WARNING_MESSAGE);
}
else {
result.setText(resultMsg);
}
}
});
clearButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
equation.setText("");
result.setText("");
}
});
deleteButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if( !( equation.getText().equals("")) ) {
StringBuffer sb = new StringBuffer();
sb.append(equation.getText());
sb.delete(sb.length()-1 , sb.length());
equation.setText(sb.toString());
}
}
});
}
private void positionSettings () {
jp1.add(equationLabel);
jp1.add(equation);
jp1.add(resultLabel);
jp1.add(result);
equationLabel.setBounds(0, 0, 50, 30);
equationLabel.setLocation(0, 0);
equation.setBounds(50, 0, 150, 30);
equation.setLocation(50, 0);
resultLabel.setBounds(0, 30, 50, 30);
resultLabel.setLocation(0, 30);
result.setBounds(50, 30, 150, 30);
result.setLocation(50, 30);
jp2.setLayout(new GridLayout(4, 5));
// line-1
jp2.add(num7);
jp2.add(num8);
jp2.add(num9);
jp2.add(addButton);
jp2.add(leftBracket);
// line-2
jp2.add(num4);
jp2.add(num5);
jp2.add(num6);
jp2.add(minusButton);
jp2.add(rightBracket);
// line-3
jp2.add(num1);
jp2.add(num2);
jp2.add(num3);
jp2.add(mulButton);
jp2.add(clearButton);
// line-4
jp2.add(num0);
jp2.add(decimalPoint);
jp2.add(equalButton);
jp2.add(divButton);
jp2.add(deleteButton);
jp1.setLocation(0, 0);
jp1.setVisible(true);
jp2.setLocation(0, 100);
jp2.setVisible(true);
}
}
package Calculator;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import sun.security.krb5.internal.ccache.CCacheInputStream;
public class Calculate {
private Stack numStack = new Stack();
private Stack sybStack = new Stack();
public String calResult ( String equation ) {
//替换乘除号
equation = equation.replace("X", "*");
equation = equation.replace("÷", "/");
//处理负号
equation = negativeNumTransfer(equation);
if ( !checkFormat(equation) ) {
return "算式格式错误";
}
equation += "#";
StringBuffer tempNum = new StringBuffer();
StringBuffer exp = new StringBuffer().append(equation);
while ( exp.length() != 0 ) {
String temp = exp.substring(0,1);
exp.delete(0, 1);
if( isNum(temp) ) { // temp是数字
tempNum.append(temp);
}
else { // temp不是数字
if (!"".equals(tempNum.toString())) {
// 当表达式的第一个符号为括号
double num = Double.parseDouble(tempNum.toString());
numStack.push(num);
tempNum.delete(0, tempNum.length());
}
// 用当前取得的运算符与栈顶运算符比较优先级:若高于,则因为会先运算,放入栈顶;若等于,因为出现在后面,
// 所以会后计算,所以栈顶元素出栈,取出操作数运算;若小于,则同理,取出栈顶元素运算,将结果入操作数栈。
// 判断当前运算符与栈顶元素优先级,取出元素,进行计算(因为优先级可能小于栈顶元素,还小于第二个元素等等,需要用循环判断)
while ( !compare(temp.charAt(0)) && (!sybStack.empty()) ) {
double a = numStack.pop();
double b = numStack.pop();
char ope = sybStack.pop();
// 进行简单的计算
if( simpleCal(ope, a, b) == false ) {
return "除数不能为0";
}
}
// 判断当前运算符与栈顶元素优先级, 如果高,或者低于平,计算完后,将当前操作符号,放入操作符栈
refreshSybStack(temp);
}
}
return getResultStr(numStack.pop());
}
private void refreshSybStack ( String temp) {
if (temp.charAt(0) != '#') {
sybStack.push(new Character(temp.charAt(0)));
if (temp.charAt(0) == ')') {// 当栈顶为'(',而当前元素为')'时,则是括号内以算完,去掉括号
sybStack.pop();
sybStack.pop();
}
}
}
private boolean simpleCal ( char ope, double a, double b ) {
double result = 0;
switch (ope) {
case '+':
result = b + a;
numStack.push(result);
break;
case '-':
result = b - a;
numStack.push(result);
break;
case '*':
result = b * a;
numStack.push(result);
break;
case '/':
if ( a == 0.0 ) {
return false;
}
else {
result = b / a;
numStack.push(result);
break;
}
}
return true;
}
private String negativeNumTransfer( String equation ) {
// 处理算式,将表示负数的部分进行改动,转成calResult方法支持的
if( equation.length() <= 1 ) {
return equation;
}
StringBuffer str = new StringBuffer().append(equation);
for ( int i = 0; i < str.length()-1; ++i ) {
if( !str.substring(i, i+1).equals("-") ) {
continue;
}
if ( i == 0 ) {
char temp = str.charAt(1);
if( isNumChar(temp) || isDecimalPoint(temp) || isLeftBracket(temp) ) {
str.insert(0, "0");
i++;
}
}
else {
char last = str.charAt(i-1);
char next = str.charAt(i+1);
if( isLeftBracket(last) &&
( isNumChar(next) || isDecimalPoint(next) || isLeftBracket(next) ) ) {
str.insert(i, "0");
i++;
}
}
}
return str.toString();
}
private boolean checkFormat ( String equation ) {
char[] c = equation.toCharArray();
int singleBracket = 0;
for( int i = 0; i < c.length; ++i ) {
if( isLeftBracket(c[i]) ) {
singleBracket++;
}
if ( isRightBracket(c[i]) ) {
singleBracket--;
}
if ( i == 0 ) { //第1个元素只能是[0-9]或者是左括号
if( !isLeftBracket(c[i]) && !isNumChar(c[i]) ) {
return false;
}
}
else if ( isNumChar(c[i]) || isDecimalPoint(c[i]) ) { //数字左边不能是右括号
if ( isRightBracket(c[i-1]) ) {
return false;
}
}
else if( isLeftBracket(c[i]) ) { // 左括号的左边不能是数字和右括号
if ( isNumChar(c[i-1]) || isDecimalPoint(c[i-1]) || isRightBracket(c[i-1]) ) {
return false;
}
}
else { // 右括号和四则运算符的左边只能是数字或者右括号
if ( !isNumChar(c[i-1]) && !isRightBracket(c[i-1]) ) {
return false;
}
}
}
return singleBracket == 0;
}
private static boolean isNum ( String temp ) {
return temp.matches("[0-9]") || temp.equals(".");
}
private static boolean isLeftBracket ( char c ) {
return c == '(';
}
private static boolean isRightBracket ( char c ) {
return c == ')';
}
private static boolean isDecimalPoint ( char c ) {
return c == '.';
}
private static boolean isNumChar ( char c ) {
return ( c >= '0' && c <= '9' );
}
private boolean compare (char str) {
if ( sybStack.empty() ) {
// 当为空时,显然 当前优先级最低,返回高
return true;
}
char last = (char) sybStack.lastElement();
// 如果栈顶为'('显然,优先级最低,')'不可能为栈顶。
if (last == '(') {
return true;
}
switch (str) {
case '#':
return false;// 结束符
case '(':
// '('优先级最高,显然返回true
return true;
case ')':
// ')'优先级最低,
return false;
case '*': {
// '*/'优先级只比'+-'高
if (last == '+' || last == '-')
return true;
else
return false;
}
case '/': {
if (last == '+' || last == '-')
return true;
else
return false;
}
// '+-'为最低,一直返回false
case '+':
return false;
case '-':
return false;
}
return true;
}
private String getResultStr ( double result ) {
StringBuffer s = new StringBuffer().append( result + "" );
if ( s.substring(s.length() - 2).equals(".0") ) {
s.delete( s.length()-2 , s.length() );
}
return s.toString();
}
}
附:版本信息日志
版本v1.0[2016年8月16日 07:01:32]
1.实现了两个数之间的四则运算
2.添加了对除法中除数为0的处理
版本v1.1[2016年8月17日 05:01:18]
优化界面
给按钮添加了颜色
版本v1.2[2016年8月17日 05:02:05]
进一步优化界面
增加异常处理
添加v1分支
版本v2.0[2016年8月25日 06:05:21]
增加了对四则运算的支持
增加了括号和小数点,数据类型改成double
优化了界面,式子和结果分行显示
版本v2.1[2016年8月25日 19:35:08]
增加了对式子格式的检查方法checkFormat
增加了对double类型除法0的判断
优化代码结构,将Calculate类的calResult方法模块化
版本v2.2[2016年8月26日 23:28:49]
增加了对负数的支持
改变了字体,使得界面更加友好
版本v2.3[2016年8月27日 19:25:19]
将异常结果用弹窗的形式来呈现
优化代码结构,将CalFrame类的构造方法的代码进行模块化