这是我在java课程设计上的一个作品。老师要求很简单,我尽量做得完善,在要求之外,做了不少。
在小数点,一些windows计算器怪异的地方(3+=+9++4=),参考网上的算法完成。
算法简介:
[=]的功能:
1.如果前次为一次有效的右数输入则将当前数赋给右数变量。
2.检查符变量是否存在运算符,若存在则计算表达式左数 运算符 右数,并将结果赋给左数变量,同时显示。若不存在,则不作操作。
3.清空串变量。
[四则运算符]的功能:
1.若前次为一次运算数输入,则执行[=]。
2.将当前数赋给左右数变量,将运算符赋给符变量。
3.清空串变量。
算法具体链接:http://blog.csdn.net/haochen_net/archive/2008/10/25/3143290.aspx
Cal类的实现:
import java.awt.BorderLayout;
import java.awt.CheckboxMenuItem;
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.Menu;
import java.awt.MenuBar;
import java.awt.MenuItem;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.text.html.HTMLDocument.HTMLReader.IsindexAction;
public class Cal extends JFrame implements ActionListener {
// 菜单
MenuBar myMenuBar = new MenuBar();
// JPanel
JPanel pdisplay = new JPanel();
JPanel pm = new JPanel(new GridLayout(5, 1, 0, 5));
JPanel pc = new JPanel(new GridLayout(1, 3, 5, 0));
JPanel pb = new JPanel(new GridLayout(4, 5, 5, 5));
JPanel pbc = new JPanel(new BorderLayout(5, 5));
JPanel pbcm = new JPanel();
static// 显示
JTextField tftext = new JTextField(25);
JTextField tfm = new JTextField(5);
// 按钮字符定义及按钮
String strB[] = { "MC", "MR", "MS", "M+", "Backspace", "CE", "C", "7", "8",
"9", "/", "sqrt", "4", "5", "6", "*", "%", "1", "2", "3", "-",
"1/x", "0", "+/-", ".", "+", "=" };
JButton[] jb = new JButton[27];
public Cal() {
super("计算机-荞叶制作");
addMenu();
initDisplay();
initPbcm();
Container pane = this.getContentPane();
pane.setLayout(new BorderLayout(10, 5));
pane.add(pdisplay, BorderLayout.NORTH);
pane.add(pbcm, BorderLayout.CENTER);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setBounds(300, 200, 400, 260);
this.setResizable(false);
this.setVisible(true);
}
// 一些类变量
static StringBuilder text = new StringBuilder("0");// 显示符
StringBuilder number = new StringBuilder("0");// 当前数.
double rightOper;// 右数
double leftOper;// 左数
double result;// 结果
int operator;// 操作符,默认为0,没有操作符
int isFloat = 0;// 0不是浮点型,1输入了一个.2真正的浮点
boolean isZero = true;// 0显示清空状态,不能输入0.输入1-9进入1状态.可以输入0-9进入2;
boolean isNeg;// 默认为正数
boolean isExcp;// 默认没有异常.
StringBuilder m = new StringBuilder("0");// 存储数串变量
int isRightInput = 0;// 一次有效右输入,输入运算符后=1;再输入数字后=2;
// //////////////////////////////////////////////////////////////////////////////////////
/**
* number是用于给leftOper和rightOper赋值的.纯纯的能够转化为Double类型的StringBuilder.
* 当然text,number,m考虑到大量的String连接和转换,StringBuilder效率更高.
* */
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
if (cmd == "0" || cmd == "1" || cmd == "2" || cmd == "3" || cmd == "4"
|| cmd == "5" || cmd == "6" || cmd == "7" || cmd == "8"
|| cmd == "9") {
if (isExcp)// 如果是三种错误之一,就不响应了.只有CE和C能够响应
return;
if (isRightInput == 1)// 如果是待一次有效右输入.也就是前一次输入的是运算符.
isRightInput = 2;// 进阶真正的右输入
if (isZero) {// 处于清空状态
number = new StringBuilder(cmd);// number直接为一个数字串
isZero = false;// 有一位数字后,不在处于清空.后面就可以输入运算符,单目,.,+/-
} else {
if (isFloat == 1) {// 待浮点状态,前一次输入的是.
number.append('.');// number这时加入.
isFloat = 2;// 真正的浮点.
}
number.append(cmd);// 数字后连接数字.
if (number.charAt(0) == '0' && isFloat != 2)// 如果不是浮点,
number.deleteCharAt(0);// 但以0开头就删去.这种方法不优雅,但想不出更好的.
}
text = number;// 只要输入数字,无条件地显示.
} else if (cmd == ".") {
if (isExcp)
return;
if (isFloat == 0)// 如果不是浮点型
isFloat = 1;// 待浮点型.
} else if (cmd == "+/-") {
if (isZero || isExcp)// 清空状态或异常.
return;
if (isNeg) {// 如果是负数就变为正数,如果是正数就变为负数.
isNeg = false;
number.deleteCharAt(0);// delete和insert操作可以推迟到完成数字输入状态后,根据isNeg来判断更好.
} else {
isNeg = true;
number.insert(0, '-');
}
text = number;
}
// 双目运算功能
else if (cmd == "+" || cmd == "-" || cmd == "*" || cmd == "/") {
if (isExcp)
return;
if (isRightInput == 0)
isRightInput = 1;// 变为待一次有效右输入状态.
if (isRightInput == 2) {// 如果已经是一次有效右输入了.就相当于'='.比如1+2+的时候.
rightOper = Double.parseDouble(number.toString());// 当前的number给右数.
try {
result = Util.calculate(leftOper, rightOper, operator);// 根据三个变量计算。如果/时右数为0,就抛异常.
} catch (ArithmeticException ae) {
isExcp = true;
if (leftOper == 0)// 左数,右数同时为0时.
text = new StringBuilder("函数结果未定义。");
else
text = new StringBuilder("除数不能为零。");
}
rightOper = leftOper = result;// 把得到的结果给左数,同时也给右数.
text = new StringBuilder(String.valueOf(result));
isZero = true;
isRightInput = 1;// 直接就是1状态.不经过0
}
if (operator == 0)// 如果运算符没有.如:1+
rightOper = leftOper = Double.parseDouble(number.toString());// 左数和右数均赋值.
// 据cmd初始化operator.此步一定进行,不管是运算符功能还是=功能.
if (cmd == "+")// 很无奈的是不能用switch.enum太繁.
operator = 1;
else if (cmd == "-")
operator = 2;
else if (cmd == "*")
operator = 3;
else
operator = 4;
isZero = true;
}
// 单目运算
else if (cmd == "sqrt") {
if (isExcp)
return;
double dnum = Double.parseDouble(number.toString());
if (dnum < 0) {// 如果当前数为负,就错误.
isExcp = true;
text = new StringBuilder("函数输入无效。");
} else {
result = Math.sqrt(dnum);
number = text = new StringBuilder(String.valueOf(result));
if (operator == 0)// 有运算符必赋值给右数.
leftOper = result;
else {
rightOper = result;
}
isZero = true;
}
} else if (cmd == "%") {
if (isExcp)
return;
double dnum = Double.parseDouble(number.toString());
result = leftOper * dnum / 100;// 这种规则让人很难适应,有点小变态.
number = text = new StringBuilder(String.valueOf(result));
if (operator == 0)
leftOper = result;
else {
rightOper = result;
}
isZero = true;
} else if (cmd == "1/x") {
if (isExcp)
return;
double dnum = Double.parseDouble(number.toString());
if (dnum == 0) {
isExcp = true;
text = new StringBuilder("除数不能为零。");
} else {
result = 1 / Double.parseDouble(number.toString());
number = text = new StringBuilder(String.valueOf(result));
if (operator == 0)
leftOper = result;
else {
rightOper = result;
}
isZero = true;
}
} else if (e.getActionCommand() == "=") {
if (isExcp)
return;
double dnum = Double.parseDouble(number.toString());
if (isRightInput == 2) {// 一次有效的右输入.如1+2=-2.如1+2=3=.就不响应3.
rightOper = dnum;// 当前数赋给右数.
isRightInput = 0;// =号破坏一次右输入,必须得以+-*/开头,后接数字
}
if (operator != 0) {// 1+2=
try {
result = Util.calculate(leftOper, rightOper, operator);
} catch (ArithmeticException ae) {
isExcp = true;
if (leftOper == 0)// 左数,右数同时为0时.
text = new StringBuilder("函数结果未定义。");
else
text = new StringBuilder("除数不能为零。");
}
leftOper = result;
} else
// 1=
result = dnum;
text = new StringBuilder(String.valueOf(result));
isZero = true;
} else if (e.getActionCommand() == "关于计算器") {
String temp = "java模拟windows高模仿实用计算器.\n荞叶制作.qq:494053175 \n blog:sina wangflood";
JOptionPane.showMessageDialog(null, temp, "关于计算器",
JOptionPane.INFORMATION_MESSAGE);
}
// BackSpace功能
else if (cmd == "Backspace") {
if (isExcp)
return;
if ((!isNeg && number.length() < 2)// 正数剩一位时,负数剩二位时.直接跳到0
|| (isNeg && number.length() < 3)) {
isZero = true;
number = new StringBuilder("0");
} else
number = number.deleteCharAt(number.length() - 1);// 每次删除最后一位.
text = number;
} else if (cmd == "CE") {
isZero = true;
isExcp = false;// 清异常.
text = number;
} else if (cmd == "C") {
operator = 0;// 清运算符.
isZero = true;
leftOper = 0;// 清左数
rightOper = 0;// 清右数.
result = 0;// 清结果.
number = text = new StringBuilder("0");// 清当前数
isExcp = false;// 清异常
isRightInput = 0;// 清一次有效右输入.
} else if (cmd == "MC") {
if (isExcp)// 同样也响应不了.异常的时候.
return;
m = new StringBuilder("0");
} else if (cmd == "MR") {// 显示存储数到display.
if (isExcp)
return;
isRightInput = 2;
number = text = m;
} else if (cmd == "MS") {
if (isExcp)
return;
m = number;// 将当前数赋给m.
} else if (cmd == "M+") {// 当前数与m相加赋给m
if (isExcp)
return;
m = new StringBuilder(String.valueOf((Double.parseDouble(m
.toString()) + Double.parseDouble(number.toString()))));
} else {// 一般不给出现这种情况.我们都会上天堂的.
System.out.println("欢迎来到地狱!");
}
// 按任何键都会触发的.
tftext.setText(text.toString());
if (m.length() != 0)// m不空的话就显示M
tfm.setText("M");
else
tfm.setText("");
if (isZero) {// 为清空状态.浮点状态和负数状态回到默认.
isFloat = 0;
isNeg = false;
}
}
private void initDisplay() {
tftext.setHorizontalAlignment(JTextField.RIGHT);
pdisplay.add(tftext);
tftext.setText("0.");
tfm.setHorizontalAlignment(JTextField.CENTER);
tfm.setEditable(false);
pm.add(tfm);
}
private void initPbcm() {
// 生成按钮
for (int i = 0; i < 27; i++) {
jb[i] = new JButton(strB[i]);
}
for (int i = 0; i < 4; i++) {
jb[i].addActionListener(this);
pm.add(jb[i]);
}
for (int i = 4; i < 7; i++) {
jb[i].addActionListener(this);
pc.add(jb[i]);
}
for (int i = 7; i < 27; i++) {
jb[i].addActionListener(this);
pb.add(jb[i]);
}
pbc.add(pc, BorderLayout.NORTH);
pbc.add(pb, BorderLayout.CENTER);
pbcm.add(pm);
pbcm.add(pbc);
}
private void addMenu() {
this.setMenuBar(myMenuBar);
// 以下是编辑菜单项
Menu editMenu = new Menu("编辑");
myMenuBar.add(editMenu);
MenuItem menuitemcopy = new MenuItem("复制");
MenuItem menuitemplaste = new MenuItem("粘贴");
MenuItem menuitemload = new MenuItem("用户登录");
editMenu.add(menuitemload);
editMenu.add(menuitemcopy);
editMenu.add(menuitemplaste);
menuitemload.addActionListener(this);
menuitemcopy.addActionListener(this);
menuitemplaste.addActionListener(this);
// 以下是编辑菜单项
Menu watchMenu = new Menu("查看");
myMenuBar.add(watchMenu);
MenuItem menuitemstandard = new MenuItem("标准型");
MenuItem menuitemsencien = new MenuItem("科学型");
watchMenu.add(menuitemstandard);
watchMenu.add(menuitemsencien);
watchMenu.addSeparator();
watchMenu.add(new MenuItem("数字分组"));
menuitemstandard.addActionListener(this);
menuitemsencien.addActionListener(this);
// 以下是帮助菜单项
Menu helpMenu = new Menu("帮助");
myMenuBar.add(helpMenu);
CheckboxMenuItem menuitemhelp = new CheckboxMenuItem("帮助主题", false);
MenuItem menuitemaboutcal = new MenuItem("关于计算器");
helpMenu.add(menuitemhelp);
helpMenu.addSeparator();
helpMenu.add(menuitemaboutcal);
menuitemhelp.addActionListener(this);
menuitemaboutcal.addActionListener(this);
}
public static void main(String[] args) {
new Cal();
}
}
Util.java辅助类
package wang.window.impl;
public class Util {
/** DoubleString格式化显示.如果有小数点,只对小数点前面进行格式化. */
private String DoubleFormat(String str) {
StringBuilder sb = new StringBuilder();
int length = str.length();
int left = length % 3;
int count = 0;
if (left == 0)
left = 3;
String tail = "";
if (str.contains(".")) {
int index = str.indexOf('.');
tail = str.substring(index);
str = str.substring(0, index);
}
for (int i = 0; i < str.length(); i++) {
if (i == left)
sb.append(",");
else if (i > left) {
count++;
if (count % 3 == 0)
sb.append(",");
}
sb.append(str.charAt(i));
}
sb.append(tail);
return sb.toString();
}
private void display() {
}
/** 根据两double类型的操作数,和操作符,计算后返回double类型结果 */
public static double calculate(double leftOper, double rightOper,
int operator) {
double result = 0;
switch (operator) {
case 1:
result = leftOper + rightOper;
break;
case 2:
result = leftOper - rightOper;
break;
case 3:
result = leftOper * rightOper;
break;
case 4:
if (leftOper == 0)
throw new ArithmeticException();
result = leftOper / rightOper;
break;
default:
System.out.println("欢迎来到地狱!");
break;
}
return result;
}
public String format(int isfloat, boolean isNeg, StringBuilder text) {
int start = 0;//.前一个位置
int end;//-后一个位置
int count = 0;//计数
if (isfloat != 2)
start = text.length() - 1;//java里数组的长度不用扫描?
if (isNeg)
end = 1;
else
end = 0;
StringBuilder sb = new StringBuilder();
for (int i = text.length() - 1; i >= 0; i++) {
char temp = text.charAt(i);
if (isfloat == 2) {
if (temp == '.')
start = i - 1;
}
if (i == start && i <= end) {
if (count == 2)
sb.append(",");//插入,的条件
count = (count + 1) % 3;
}
sb.append(temp);
}
return sb.reverse().toString();//逆序
}
}
运行界面:
有些地方还没有完善。高手飘过,探讨改进啊。