首先说明此代码的界面布局基本上参考了: http://yuncode.net/code/c_50b0c000f0c2e62由于后面的运算符处理操作实在难以理解。
所以后面事件的处理是自己改写的,我觉得这样比较好理解。
/**
*
*/
package myJavaSwing;
import javax.swing.JFrame;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JButton;
import javax.swing.JTextField;
import javax.swing.JPanel;
import java.awt.GridLayout;
import java.awt.Color;
import java.awt.BorderLayout;
import java.awt.Container;
/**
* @author 花花
*简介:仿windows7计算器
*由于M键设计到存储器暂不支持M键的功能
*
*/
public class Calculator extends JFrame implements ActionListener {
//计算器的三个功能键名字
private final String COMMAND[]= {"Backspace","CE","C"};
//计算计算面板上的键名
private final String CALCULATE[]= {"7","8","9","/","sqrt","4",
"5","6","*","%","1","2","3","-","1/x","0","+/-",".","+","="};
//计算器上的M键名
private final String M[]= {" ","MC","MR","MS","M+"};
//定义三个功能按钮
JButton commands[]=new JButton[COMMAND.length];
//定义计算面板班的按钮
JButton calculate[]=new JButton[CALCULATE.length];
//定义M按钮
JButton m[]=new JButton[M.length];
//结果文本框
JTextField resultText=new JTextField();
//计算结果
private double result=0;
//文本框中之前是否有输入
private Boolean preferExist=false;
//操作符
private String op="=";
//是否按了操作符
private Boolean operate=false;
//中间值。如果连续操作,记录之前的值,避免被新值覆盖。
private double beforebefore=0;
//构造函数
public Calculator() {
super();//调用JFrame的构造方法,画出一个框架,其实可以不写,因为子类在构造时首先会调用父类的构造方法
//初始化计算器
init();
// 设置计算器的背景颜色
this.setBackground(Color.LIGHT_GRAY);
this.setTitle("计算器");
// 在屏幕(500, 300)坐标处显示计算器
this.setLocation(500, 300);
// 不许修改计算器的大小
this.setResizable(false);
// 使计算器中各组件大小合适
this.pack();
}
//初始化计算器
private void init()
{
this.setTitle("计算器");//相当于构造方法Calculator()中的super("计算器");
//文本框
//结果文本框中的内容采用右对齐方式
resultText.setHorizontalAlignment(JTextField.RIGHT);
//文本框中的内容为只读方式
resultText.setEditable(false);
//设置文本框背景为白色
resultText.setBackground(Color.white);
/*建一个面板放文本框
* 布局:边界布局*/
JPanel resultPanel=new JPanel();
resultPanel.setLayout(new BorderLayout());
resultPanel.add(resultText);
//初始化计算器上用于计算区域键的按钮,将这些键放在一个面板内
JPanel calcPanel=new JPanel();
//设置计算区域的面板布局,采用网格布局,4行5列,各组件之间的水平,竖直间隔都为3个像素
calcPanel.setLayout(new GridLayout(4,5,3,3));
for(int i=0;i<calculate.length;i++)
{
calculate[i]=new JButton(CALCULATE[i]);
calcPanel.add(calculate[i]);
//将这些键的字体颜色设为蓝色
calculate[i].setForeground(Color.blue);
}
//将运算符键用红色表示
for(int i=1;i<=calculate.length/5;i++)
{
calculate[i*5-2].setForeground(Color.red);
calculate[i*5-1].setForeground(Color.red);
}
/*初始化三个功能键按钮,将这些键放在一个面板内
* 布局:网格布局,1行3列。各组件之间的水平竖直间隔都为三个像素*/
JPanel commandPanel=new JPanel();
commandPanel.setLayout(new GridLayout(1,3,3,3));
for(int i=0;i<commands.length;i++)
{
commands[i]=new JButton(COMMAND[i]);
commandPanel.add(commands[i]);
//将这些键的字体颜色设为红色
commands[i].setForeground(Color.red);
}
/*初始化M键按钮,将其放在一个面板内
* 布局:网格布局,5行1列。各组件之间的水平竖直间隔为3
* m键字体颜色设为红色*/
JPanel mPanel=new JPanel();
mPanel.setLayout(new GridLayout(5,1,3,3));
for(int i=0;i<M.length;i++)
{
m[i]=new JButton(M[i]);
mPanel.add(m[i]);
m[i].setForeground(Color.red);
}
/*然后进行计算器的整体布局
* 先将运算操作部分和三个功能键的面板,合为一个面板panel1
* 布局:边界布局管理器。个组件之间水平竖直间隔都为3个像素
* 北:commandsPanel,中:calcPanel
*
* */
JPanel panel1=new JPanel();
panel1.setLayout(new BorderLayout(3,3));
panel1.add("North",commandPanel);
panel1.add("Center",calcPanel);
/*最后进行这三个面板的整体布局
* 布局:边界布局
* west:mPanel,north:commmandPanel,center:panel1*/
Container c=super.getContentPane();
c.add("North", resultPanel);
c.add("West",mPanel);
c.add("Center",panel1);
/*为各按钮添加事件侦查器,各按钮使用同一个事件侦查器,即本对象,因为本类implementls ActionListener*/
for(int i=0;i<commands.length;i++)
{
commands[i].addActionListener(this);
}
for(int i=0;i<M.length;i++)
{
m[i].addActionListener(this);
}
for(int i=0;i<calculate.length;i++)
{
calculate[i].addActionListener(this);
}
}
public void actionPerformed(ActionEvent e) {
//获取事件源的标签
String label=e.getActionCommand();
if(label.equals(COMMAND[0]))
{//用户按了Backspace键
handleBackspace();
}
else if(label.equals(COMMAND[1]))
{//用户按了CE键, 清除当前输入的数字
handleCE();
}
else if(label.equals(COMMAND[2]))
{//用户按了C键,清除之前的所有输入
resultText.setText("0");
//result=0;
}
else if("0123456789.".indexOf(label)>=0)//String.indexOf(String)返回char在String中的位置
{//用户按了数字键或小数点
handleCalcKey(label);
/*
if(!operate)
{
result=getNumberFromText();
}
*/
}
else if(label.equals("="))
{
handleEqual();
}
else
{//用户按了=号,这时开始计算,并将结果输出到文本框
handleOperator(label);
}
//M键涉及到存储器暂不做处理
}
//编写各种按钮的处理事件
//处理Backspace键被按下的事件
private void handleBackspace()
{
String text=resultText.getText();
int i=text.length();
if(i>0)
{
//退一格,将文本框中的最后一个字符去掉
text=text.substring(0,i-1);
resultText.setText(text);
}
else
{
resultText.setText("0");
}
/*
if(!operate)//重新读取退格后文本框中的数据
{
result=getNumberFromText();
}
*/
}
//处理CE键被按下的事件,清除当前输入的数字
private void handleCE()
{
String text=resultText.getText();
int i=text.length();
if(i>0)
{
//退一格,将文本框中的最后一个字符去掉
text=text.substring(0,i-1);
resultText.setText(text);
}
else
{
resultText.setText("0");
}
}
//处理数字键或小数点键被按下的事件
private void handleCalcKey(String number)
{
String tempStr=resultText.getText();
if(preferExist)//之前已有数字
{
if(number.equals("."))
{
if((tempStr.indexOf("."))<0)//说明之前不存在小数点,并且之前已有数字输入
{
resultText.setText(tempStr+".");
}
}
else
{
resultText.setText(tempStr+number);
}
}
else//还没输入数字
{
resultText.setText(number);
preferExist=true;
}
}
//如果用户一次计算多个数,连续运算,在两个数运算后其实相当于按了一次=,做了一次计算
private void calcMore()
{
if(operate==true)
{
result=beforebefore;
handleEqual();
}
}
/*处理运算符键被按下的事件,如果是单目运算符直接计算结果,
* 如果是双目运算符,将用户选择的运算符保存下来,便于输入第二个操作数后进行运算
*/
private void handleOperator(String operator)
{
//前一个数
result=getNumberFromText();
if (operator.equals("/"))
{
op="/";
calcMore();
}
else if (operator.equals("1/x"))
{
//op="1/x";
// 倒数运算
if (result== 0.0)
{
// 操作不合法
resultText.setText("零没有倒数");
}
else
{
result= 1/result;
}
}
else if (operator.equals("+"))
{
op="+";
calcMore();
}
else if (operator.equals("-"))
{
op="-";
calcMore();
}
else if (operator.equals("*"))
{
op="*";
calcMore();
}
else if (operator.equals("sqrt"))
{
//op="sqrt";
// 平方根运算
result= Math.sqrt(result);
}
else if (operator.equals("%"))
{
//op="%";
// 百分号运算,除以100
result= result/ 100;
}
else if (operator.equals("+/-"))
{
//op="+/-";
// 正数负数运算
result= result*(-1);
}
beforebefore=result;
preferExist=false;
operate=true;
}
//=.处理双目运算符。根据之前输入的操作符号进行计算,并将结果输出到文本框
private void handleEqual()
{
if(operate)//已经按过操作符
{
if (op.equals("/"))
{
// 除法运算
// 如果当前结果文本框中的值等于0
if (getNumberFromText() == 0.0)
{
// 操作不合法
resultText.setText("除数不能为零");
}
else
{
result/= getNumberFromText();
}
}
else if (op.equals("+"))
{
// 加法运算
result+= getNumberFromText();
}
else if (op.equals("-"))
{
// 减法运算
result-= getNumberFromText();
}
else if (op.equals("*"))
{
// 乘法运算
result*= getNumberFromText();
}
}
resultText.setText(Double.toString(result));
operate=false;
/*
* 这时不能将之后输入的数字再加到之前的结果后面,若要输入数字,
* 将之前的输入置为false,重新输入.
*/
preferExist=false;
}
//从文本框中获取第二个操作数
private double getNumberFromText()
{
double number=0;
if(resultText.getText()!=null)
{
number=Double.parseDouble(resultText.getText());
}
return number;
}
public static void main(String[] args)
{
Calculator cal=new Calculator();
cal.setSize(400,250);
cal.setVisible(true);
cal.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
参考代码:http://yuncode.net/code/c_50b0c000f0c2e62实在无法理解双目运算如何在没输入前获取第二个操作数,所以只好自己改写了。
/*之前在这个过程中总是容易让我比较困惑的问题就是:连续计算时,中间值会被当前文本框中的值覆盖问题.
* 于是添加了beforebefore这个变量,档连续计算时作为中间值。
* 例如:连续计算5+3+2
* (1)5+后,result=5,此时operate=true;beforebefore=result=5;
* (2)3+后,result=3,此时会调用calcMore判断是否是连续计算,if(operate==true)
* 说明之前已按过操作符,将beforebefore之前存的值赋给result,result=5;
* 所以利用beforebefore这个中间变量避免了连续计算时上一次的值被新输入的值覆盖,完成连续计算。
*
*/