Java计算器实验报告
计算机032
胡勇健
03095218
20xx年5月5日
目录
1.设计名称与要求
2.各模块功能的介绍和实现
3.系统的特色和不足
4.参考书
一. 实验名称及其要求:
A) 名称: java计算器的设计
B) 要求:1.实验目的:图形界面设计。
熟悉java.awt包中的组件,掌握图形界面设计方法,理解委托事件处理模型。
2.题意:
请设计并实现Windows系统中“计算器”的窗口及功能。
3.实验要求:
(1)设计图形界面添加菜单:窗口上添加各种组件及菜单,并处理组件及菜单的事件监听程序。
(2)运算:实现多种运算,保证运算正确性。
二. 各模块功能的介绍和实现:
A) GUI图形界面的组件:
a) 所用到的Java类库包:
java.awt.*;
java.awt.event.*;
javax.swing.*;
java.awt.datatransfer.*;
基本的图形界面组件来源于awt包。 事件的属性处理来源于awt.event包。 swing组件增加了awt包中所不具备的各种优越功能。 用于计算器与外部的程序进行复制粘贴。
b) 所用的各部分图形组件的定义:
Frame mainFrame; //主框架
JTextField answerText; //显示计算结果
JTextField memoryState; //显示计算器内存的使用情况 MenuBar menuGroup; //菜单栏
Menu editMenu,viewMenu,helpMenu; //编辑,查看,帮助菜单 MenuItem copyItem,pasteItem; //复制,粘贴 MenuItem standardModel; //标准型
CheckboxMenuItem numGroup; //数字分组
MenuItem aboutCal; //关于计算器
Button buttonBackSpace,buttonCE,buttonC; //退格,清除,清空按钮 Button buttonMC,buttonMR,buttonMS,buttonMADD; //内存操作按钮 Button buttonNum[]; //数字按钮
Button buttonAdd,buttonSub,buttonMul,buttonDiv; //+,-,*,/
Button buttonDot,buttonSign,buttonEqual; //. +/- =
Button buttonSqrt,buttonMod,buttonReciprocal;
//sqrt % 1/x
c) 组件的初始化以及对界面的排版
对主框架的初始化操作
void initMainFrame()函数是对主框架进行初始化,设置其框架大小270*250,
初始位置270*250,背景颜色Color.lightGray, 是否显示true,能否改变窗口大小false,以及增加了addWindowListener委托事件,当关闭窗口时调用System.exit(0) 系统指令,结束程序。
void initMainFrame() { mainFrame = new Frame("计算器"); } mainFrame.setSize(270,250); mainFrame.setLocation(200,140); mainFrame.setBackground(Color.lightGray); mainFrame.setResizable(false); mainFrame.addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e){ System.exit(0); } });
对文本框的初始化操作
initTextField() 是对文本 textBuffer answerText memoryState的初始化,
textBuffer 是用于对文本的缓冲处理,StringBuffer类优于String类是因为StringBuffer是对字符串直接操作,从而节省了内存。由于在这个计算器程序中,对字符串的操作量很大,因此,StringBuffer 在这方面体现出了其本身的优势。answerText 和 memoryState 用swing的组件JTextField是因为JTextField显示文本框时可以在文本框的右边显示,符合Windows自带计算器的特点。answerText 和 memoryState 的背景色为白色,都不能进行编辑。answerText为右对齐,大小为23个字符,而memoryState为2个字符。
void initTextField() { textBuffer = new StringBuffer(""); answerText = new JTextField(textBuffer.toString(),23); answerText.setHorizontalAlignment(JTextField.RIGHT);
} answerText.setEditable(false); answerText.setBackground(Color.white); memoryState = new JTextField(2); memoryState.setEditable(false); memoryState.setBackground(Color.white);
对各按钮的初始化操作
initButtons()函数是对各按钮进行初始化,为每一个按钮增加其标签并增加了 addActionListener(this) 功能,用于给各按钮增加属性,具体的功能代码,请见 actionPerformed(ActionEvent e);其中,数字按钮、四则运算按钮、小数点按钮都增加了键盘输入功能addKeyListener其参数为匿名类KeyListener的适配器new KeyAdapter(),当在键盘上按下相应的键时,为其增加相应的属性功能。
void initButtons() { buttonBackSpace = new Button("BackSpace"); buttonBackSpace.addActionListener(this); buttonCE = new Button(" CE "); buttonCE.addActionListener(this); buttonC = new Button(" C "); buttonC.addActionListener(this); buttonMC = new Button("MC"); buttonMC.addActionListener(this); buttonMR = new Button("MR"); buttonMR.addActionListener(this); buttonMS = new Button("MS"); buttonMS.addActionListener(this); buttonMADD = new Button("M+"); buttonMADD.addActionListener(this); buttonNum = new Button[10]; for (int i=0;i<buttonNum.length ;i++ ) { buttonNum[i] = new Button(Integer.toString(i)); buttonNum[i].addActionListener(this); buttonNum[i].addKeyListener(new KeyAdapter(){ public void keyPressed(KeyEvent e){ if (Character.isDigit(e.getKeyChar())) { textBuffer.append(e.getKeyChar());
} }); } } answerText.setText(textBuffer.toString()); AddNum(); buttonAdd = new Button("+"); buttonAdd.addActionListener(this); buttonAdd.addKeyListener(new KeyAdapter(){ public void keyPressed(KeyEvent e){ if (e.getKeyChar() == '+') AddFunction(1); } }); buttonSub = new Button("-"); buttonSub.addActionListener(this); buttonSub.addKeyListener(new KeyAdapter(){ public void keyPressed(KeyEvent e){ if (e.getKeyChar() == '-') AddFunction(2); } }); buttonMul = new Button("*"); buttonMul.addActionListener(this); buttonMul.addKeyListener(new KeyAdapter(){ public void keyPressed(KeyEvent e){ if (e.getKeyChar() == '*') AddFunction(3); } }); buttonDiv = new Button("/"); buttonDiv.addActionListener(this); buttonDiv.addKeyListener(new KeyAdapter(){ public void keyPressed(KeyEvent e){ if (e.getKeyChar() == '/') AddFunction(4); } }); buttonDot = new Button("."); buttonDot.addActionListener(this); buttonDot.addKeyListener(new KeyAdapter(){ public void keyPressed(KeyEvent e){
} if (e.getKeyChar() == '.') { textBuffer.append(e.getKeyChar()); answerText.setText(textBuffer.toString()); AddNum(); } } }); buttonSign = new Button("+/-"); buttonSign.addActionListener(this); buttonEqual = new Button("="); buttonEqual.addActionListener(this); buttonEqual.addKeyListener(new KeyAdapter(){ public void keyPressed(KeyEvent e){ if (e.getKeyChar() == '=') OnGo(); } }); buttonSqrt = new Button("sqrt"); buttonSqrt.addActionListener(this); buttonMod = new Button("%"); buttonMod.addActionListener(this); buttonReciprocal = new Button("1/x"); buttonReciprocal.addActionListener(this);
对菜单的初始化操作
initMenu()函数是对各菜单的初始化,先为其生成实例对象,再添加到MenuBar 的实例对象menuGroup中,MenuItem各项添加到相应的Menu中。
void initMenu() { /* * 先为各个菜单项生成实例对象,并为其设置相应的标签。MenuItem各项 * 还要设置 addActionListener(this) 增加委托事件任务。 */ menuGroup = new MenuBar(); editMenu = new Menu("编辑(E)"); viewMenu = new Menu("查看(V)");
helpMenu = new Menu("帮助(H)"); copyItem = new MenuItem("复制(C) Ctrl+C",new
MenuShortcut(KeyEvent.VK_C));
copyItem.addActionListener(this);
pasteItem = new MenuItem("粘贴(P) Ctrl+V",new
MenuShortcut(KeyEvent.VK_V));
pasteItem.addActionListener(this);
standardModel = new MenuItem("●标准型(T)");
} standardModel.addActionListener(this); numGroup = new CheckboxMenuItem("数字分组(I)",false); numGroup.addItemListener(this); aboutCal = new MenuItem("关于计算器(A)"); aboutCal.addActionListener(this); /* 再把各个菜单相继加入到 MenuBar 中 */ menuGroup.add(editMenu); menuGroup.add(viewMenu); menuGroup.add(helpMenu); editMenu.add(copyItem); editMenu.add(pasteItem); viewMenu.add(standardModel); viewMenu.add(numGroup); helpMenu.add(aboutCal);
对总框架的总体布局
OverallArrangement() 是根据mainFrame的框架大小,把文本框answerText,内存使用的情况文本框memoryState,内存操作键 MR MS M+ MC,退格键BackSpace清除键 CE ,清空键 C ,以及主键盘区的各键按照一定的比例位置加入到mainFrame中.
void OverallArrangement() { Panel textPanel = new Panel(); Panel upperPanel = new Panel(); Panel centerPanel = new Panel(); Panel mainPanel = new Panel(); Panel leftPanel = new Panel(); //文本框的容器 //计算器上部分的容器 //计算器中部的容器 //主键盘区的容器 //内存区的容器
Panel rightPanel = new Panel(); //数字及相应的操作键盘区
mainFrame.setMenuBar(menuGroup); //为主框架设置菜单栏 mainFrame.add(upperPanel,BorderLayout.NORTH); //把上容器放在主框架的北面 mainFrame.add(centerPanel); //把中容器放在主框架的中部
mainFrame.add(mainPanel,BorderLayout.SOUTH); //把主容器放在主框架的南面 /*设置主框架的上半部分*/ textPanel.add(answerText); upperPanel.add(textPanel);
//把文本框添加到文本容器中 //把文本容器放入上容器中
/*设置主框架的中部*/
//采用流式布局,各组件相互间隔10个像素
centerPanel.setLayout(new FlowLayout(FlowLayout.CENTER,10,10));
centerPanel.add(memoryState); //把内存记忆框放在中容器中 centerPanel.add(buttonBackSpace); //把退格键放在中容器中 centerPanel.add(buttonCE); //把清除键放在中容器中 centerPanel.add(buttonC); //把清空键放在中容器中 /*设置主框架的下半部分*/
leftPanel.setLayout(new GridLayout(4,1,0,2)); //左下角的容器采用4*1的网式布局 leftPanel.add(buttonMC); //添加MC leftPanel.add(buttonMR); //添加MR leftPanel.add(buttonMS); //添加MS leftPanel.add(buttonMADD); //添加M+
mainPanel.add(leftPanel,BorderLayout.WEST);//把此容器放在主容器的西面
/*设置主键盘区*/
rightPanel.setLayout(new GridLayout(4,5,3,3)); //采用4*5的网式布局,相互间隔3各像素 /*添加各键*/
rightPanel.add(buttonNum[7]); rightPanel.add(buttonNum[8]); rightPanel.add(buttonNum[9]); rightPanel.add(buttonDiv); rightPanel.add(buttonSqrt); rightPanel.add(buttonNum[4]);
} rightPanel.add(buttonNum[5]); rightPanel.add(buttonNum[6]); rightPanel.add(buttonMul); rightPanel.add(buttonMod); rightPanel.add(buttonNum[1]); rightPanel.add(buttonNum[2]); rightPanel.add(buttonNum[3]); rightPanel.add(buttonSub); rightPanel.add(buttonReciprocal); rightPanel.add(buttonNum[0]); rightPanel.add(buttonSign); rightPanel.add(buttonDot); rightPanel.add(buttonAdd); rightPanel.add(buttonEqual); mainPanel.add(rightPanel,BorderLayout.CENTER);
计算器构造函数是对各布局函数的调用
SimpleCalculator() { initMainFrame(); initTextField(); initButtons(); initMenu(); OverallArrangement(); reSet(); mainFrame.setVisible(true); }
B) 计算运算部分程序的执行过程:
a) 运算部分变量的定义
stringBuffer textBuffer; //记录数值的字符串 int numDot; //小数点的个数 int operator; //操作符:1-加法 2-减法 3-乘法 4-除法 double firstValue,secondValue,result; //第一、二个数及结果 boolean enterSecond; //是否已经输入了第二个数 int forFirOrSec; //此时输入的是第一个还是第二个数 boolean b_remFir,b_remSec,b_remFun; //指示是否此时还记的上次的数和运算符
int remFun; double remFir,remSec; boolean isNumGroup=false; boolean canBeBack; double memory; //记住上次的运算符 // 记住上次参加运算的第一二个数 //记录是否为数字分组 //是否可以使用退格键 //用于内存操作时保存的数据
b) 各功能函数简介
reset函数
reSet() 是把各属性设置为原始值,当按下
void reSet()
{
answerText.setText("0.");
textBuffer = new StringBuffer("");
numDot=0;
remFun = operator = 0;
firstValue = secondValue = result = 0.0;
enterSecond = false;
forFirOrSec = 1;
b_remFir = b_remSec = b_remFun = false;
remFir = remSec = 0.0;
canBeBack = true;
}
showScreen函数
showScreen() 是当按下了数字键后,在屏幕上显示。如果有数字分组项,则调用数字分组函数。如为整数则在其后只显示一个小数点,例如:数值5 应该显示为 5. 若为小数,则直接显示。
void showScreen() { if (numDot==0) answerText.setText(textBuffer.toString()+"."); else answerText.setText(textBuffer.toString()); if (isNumGroup == true) { showNumGroup(); } }
showScreenValue函数
showScreenValue() 是用于显示计算后的结果值,具体的功能同上。
void showScreenValue() { int resInteger = (int)result; if ( Math.abs(result-resInteger) == 0 ) { StringBuffer tmp = new StringBuffer(Double.toString(result)); tmp.deleteCharAt(tmp.length()-1); answerText.setText(tmp.toString()); } else answerText.setText(Double.toString(result)); if (isNumGroup == true) { showNumGroup(); } } showNumGroup函数
数字分组的显示:每隔三位显示一个逗号以示分隔。
void showNumGroup() { int i,cnt=0; String string = answerText.getText(); String interge,fraction; interge = fraction = string; for (i=0;i<string.length();i++) { if (string.charAt(i)=='.') { interge = string.substring(0,i); fraction = string.substring(i+1,string.length()); break; } } StringBuffer sb = new StringBuffer(interge); sb.reverse(); for (i=0;i<sb.length() ;i++ ) { if (Character.isDigit(sb.charAt(i))) { cnt++; if (cnt>3) {
} cnt = 0; sb.insert(i,","); } } } sb.reverse(); answerText.setText(sb.toString()+"."+fraction); deleteNumGroup函数
deleteNumGroup() 是当已经数字分组时,再次按下该键,消除数字分组的效果;
当输入了四则运算符时,先进行判断各种双目运算的可能性,若不是第一次运算操作则先把上一次的操作完成并在屏幕上显示,并记录下当前的操作符,否则存入操作符。
void AddFunction(int op) { //如果此时第二个数存在.则运算,例如输入2+3=5后按*4 + if (b_remFir==true && b_remFun==false && enterSecond==true) { if (operator == 1) result = remFir + secondValue; else if (operator == 2) result = remFir - secondValue; else if (operator == 3) result = remFir * secondValue; else if (operator == 4) result = remFir / secondValue; b_remFir = true; remFir = result; enterSecond = false; forFirOrSec = 2; operator = op; showScreenValue(); void deleteNumGroup() { StringBuffer sb = new StringBuffer(answerText.getText()); for (int i=0;i<sb.length() ;i++ ) { if (sb.charAt(i)==',') { sb.deleteCharAt(i); } } answerText.setText(sb.toString()); } AddFunction函数
} } //如果此时第二个数存在.则运算,例如输入2+3后按*键 else if (b_remFir==false && b_remFun==false && enterSecond==true) { if (operator == 1) result = firstValue + secondValue; else if (operator == 2) result = firstValue - secondValue; else if (operator == 3) result = firstValue * secondValue; else if (operator == 4) result = firstValue / secondValue; b_remFir = true; remFir = result; enterSecond = false; forFirOrSec = 2; operator = op; showScreenValue(); } else { operator = op; forFirOrSec = 2; } b_remFun = false; remFun = 0; textBuffer = new StringBuffer(""); AddNum函数
把屏幕上的值存入result 和 firstValue secondValue 中。
void AddNum() { if (forFirOrSec == 1) { result = firstValue = Double.parseDouble(textBuffer.toString()); b_remFir = false; remFir = 0; } else if (forFirOrSec == 2) { enterSecond = true; secondValue = Double.parseDouble(textBuffer.toString()); b_remSec = false; remSec = 0; } }
OnGo函数
当按下了等于号时,先对各种键盘的输入方法进行判断,并对每种情况进行正确的操作。
void OnGo() { //如果记着第一,二个数和运算符,即上次算完后未输入数,而再次按= if (b_remFir==true && b_remSec==true && b_remFun==true) { if (remFun==1) result = remFir + remSec; else if (remFun==2) result = remFir - remSec; else if (remFun==3) result = remFir * remSec; else if (remFun==4) result = remFir / remSec; } b_remFir=true; b_remSec=true; b_remFun=true; remFir = result; remSec = remSec; remFun = remFun; //只记的第一数,如算完2+3=5后按*4=
else if (b_remFir==true && b_remSec==false && b_remFun==false) {
if (operator == 1) result = remFir + secondValue;
else if (operator == 2) result = remFir - secondValue;
else if (operator == 3) result = remFir * secondValue;
else if (operator == 4) result = remFir / secondValue;
b_remFir=true; b_remSec=true; b_remFun=true;
remFir = result; remSec = secondValue; remFun = remFun;
}
//记住了第一个数,未输入第二个数,输入了运算符.如算完2+3=5后按*=结果为5*5=25;
else if (b_remFir==true && b_remSec==true && b_remFun==false) { secondValue = remFir; if (operator == 1) result = remFir + secondValue; else if (operator == 2) result = remFir - secondValue; else if (operator == 3) result = remFir * secondValue; else if (operator == 4) result = remFir / secondValue; } b_remFir=true; b_remSec=true; b_remFun=true; remFir = result; remSec = secondValue; remFun = remFun; //第一二个数和运算符都不记的,记全重新输入,如算完2+3=5后输入4*6= else if (b_remFir==false && b_remSec==false && b_remFun==false)
代码:
} { } if (enterSecond == false) secondValue = firstValue; if (operator == 1) result = firstValue + secondValue; else if (operator == 2) result = firstValue - secondValue; else if (operator == 3) result = firstValue * secondValue; else if (operator == 4) result = firstValue / secondValue; b_remFir=true; b_remSec=true; b_remFun=true; remFir = result; remSec = secondValue; remFun = remFun; showScreenValue(); textBuffer = new StringBuffer(""); firstValue = secondValue = 0; forFirOrSec = 1; enterSecond = false; canBeBack = false;
/**
*实验名称: 计算器
*
*1.实验目的:图形界面设计。
* 熟悉java.awt包中的组件,掌握图形界面设计方法,理解委托事件处理模型。 *
*2.题意:
* 请设计并实现Windows系统中“计算器”的窗口及功能。
*
*3.实验要求:
* (1)设计图形界面添加菜单:窗口上添加各种组件及菜单,并处理组件及菜单的事件监听程序。
* (2)运算:实现多种运算,保证运算正确性。
*
*
*作者:计算机032 胡勇健 03095218
*/
import java.awt.*;
import java.awt.event.*;
import java.awt.datatransfer.*;
import javax.swing.*;
public class SimpleCalculator extends TextField implements ActionListener,ItemListener {
//私有成员变量的定义:
/*以下为计算机的各部分组件*/
Frame mainFrame; // JTextField answerText; // JTextField memoryState; //情况
MenuBar menuGroup; // Menu editMenu,viewMenu,helpMenu; // MenuItem copyItem,pasteItem; // MenuItem standardModel; // CheckboxMenuItem numGroup; // MenuItem aboutCal; // Button buttonBackSpace,buttonCE,buttonC; // Button buttonMC,buttonMR,buttonMS,buttonMADD; // Button buttonNum[]; // Button buttonAdd,buttonSub,buttonMul,buttonDiv; //+,-,*,/ Button buttonDot,buttonSign,buttonEqual; //. +/- = Button buttonSqrt,buttonMod,buttonReciprocal; //sqrt % 1/x
/*以下为运算时所用到的变量*/
StringBuffer textBuffer; // int numDot; // int operator; //3-乘法 4-除法
double firstValue,secondValue,result; // boolean enterSecond; //数
int forFirOrSec; //是第二个数
boolean b_remFir,b_remSec,b_remFun; //次的数和运算符
int remFun; // double remFir,remSec; // 一二个数
boolean isNumGroup=false; // boolean canBeBack; //主框架
显示计算结果
显示计算器内存的使用菜单栏
编辑,查看,帮助菜单 复制,粘贴 标准型 数字分组 关于计算器
退格,清除,清空按钮 内存操作按钮 数字按钮 记录数值的字符串 小数点的个数
操作符:1-加法 2-减法第一、二个数及结果 是否已经输入了第二个此时输入的是第一个还指示是否此时还记的上记住上次的运算符 记住上次参加运算的第记录是否为数字分组 是否可以使用退格键
double memory; //用于内存操作时保存的数据
/*以下为本计算器与系统其他资源数据交换的变量*/
Clipboard clipbd = getToolkit().getSystemClipboard();
//结束私有成员变量的定义。
//构造函数:
SimpleCalculator()
{
initMainFrame();
initTextField();
initButtons();
initMenu();
OverallArrangement();
reSet();
mainFrame.setVisible(true);
}
//结束构造函数。
//对各GUI组件进行的操作函数
/*
* void initMainFrame()函数是对主框架进行初始化,设置其框架大小270*250, * 初始位置270*250,背景颜色Color.lightGray, 是否显示true,能否改变窗 * 口大小false,以及增加了addWindowListener委托事件,当关闭窗口时调用 * System.exit(0) 系统指令,结束程序。
*/
void initMainFrame()
{
mainFrame = new Frame("计算器");
mainFrame.setSize(270,250);
mainFrame.setLocation(200,140);
mainFrame.setBackground(Color.lightGray);
mainFrame.setResizable(false);
mainFrame.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
/*
* initTextField() 是对文本 textBuffer answerText memoryState得初始化, * textBuffer 是用于对文本的缓冲处理,StringBuffer类优于String类是因为 * StringBuffer是对字符串直接操作,从而节省了内存。由于在这个计算器程 * 序中,对字符串的操作量很大,因此,StringBuffer 在这方面体现出了其本身 * 的优势。answerText 和 memoryState 用swing的组件JTextField是因为JTextField
* 显示文本框时可以在文本框的右边显示,符合Windows自带计算器的特点。 * answerText 和 memoryState 的背景色为白色,都不能进行编辑。answerText * 为右对齐,大小为23个字符,而memoryState为2个字符。
*/
void initTextField()
{
textBuffer = new StringBuffer("");
answerText = new JTextField(textBuffer.toString(),22);
answerText.setHorizontalAlignment(JTextField.RIGHT);
answerText.setEditable(false);
answerText.setBackground(Color.white);
memoryState = new JTextField(2);
memoryState.setEditable(false);
memoryState.setBackground(Color.white);
}
/*
* initButtons()函数是对各按钮进行初始化,为每一个按钮增加其标签 * 并增加了 addActionListener(this) 功能,用于给各按钮增加属性, * 具体的功能代码,请见 actionPerformed(ActionEvent e);其中,数字 * 按钮、四则运算按钮、小数点按钮都增加了键盘输入功能addKeyListener * 其参数为匿名类KeyListener的适配器new KeyAdapter(),当在键盘上按下 * 相应的键时,为其增加相应的属性功能。
*/
void initButtons()
{
buttonBackSpace = new Button("BackSpace");
buttonBackSpace.addActionListener(this);
buttonCE = new Button(" CE ");
buttonCE.addActionListener(this);
buttonC = new Button(" C ");
buttonC.addActionListener(this);
buttonMC = new Button("MC");
buttonMC.addActionListener(this);
buttonMR = new Button("MR");
buttonMR.addActionListener(this);
buttonMS = new Button("MS");
buttonMS.addActionListener(this);
buttonMADD = new Button("M+");
buttonMADD.addActionListener(this);
buttonNum = new Button[10];
for (int i=0;i<buttonNum.length ;i++ )
{
buttonNum[i] = new Button(Integer.toString(i)); buttonNum[i].addActionListener(this);
buttonNum[i].addKeyListener(new KeyAdapter(){ public void keyTyped(KeyEvent e){
if (Character.isDigit(e.getKeyChar())) {
textBuffer.append(e.getKeyChar());
answerText.setText(textBuffer.toString()); AddNum();
}
}
});
}
buttonAdd = new Button("+");
buttonAdd.addActionListener(this);
buttonAdd.addKeyListener(new KeyAdapter(){
public void keyTyped(KeyEvent e){
if (e.getKeyChar() == '+')
AddFunction(1);
}
});
buttonSub = new Button("-");
buttonSub.addActionListener(this);
buttonSub.addKeyListener(new KeyAdapter(){
public void keyTyped(KeyEvent e){
if (e.getKeyChar() == '-')
AddFunction(2);
}
});
buttonMul = new Button("*");
buttonMul.addActionListener(this);
buttonMul.addKeyListener(new KeyAdapter(){
public void keyTyped(KeyEvent e){
if (e.getKeyChar() == '*')
AddFunction(3);
}
});
buttonDiv = new Button("/");
buttonDiv.addActionListener(this);
buttonDiv.addKeyListener(new KeyAdapter(){
public void keyTyped(KeyEvent e){
if (e.getKeyChar() == '/')
AddFunction(4);
}
});
buttonDot = new Button(".");
buttonDot.addActionListener(this);
buttonDot.addKeyListener(new KeyAdapter(){
public void keyTyped(KeyEvent e){
if (e.getKeyChar() == '.')
{
textBuffer.append(e.getKeyChar());
answerText.setText(textBuffer.toString()); AddNum();
}
}
});
buttonSign = new Button("+/-");
buttonSign.addActionListener(this);
buttonEqual = new Button("=");
buttonEqual.addActionListener(this);
buttonEqual.addKeyListener(new KeyAdapter(){ public void keyTyped(KeyEvent e){
if (e.getKeyChar() == '=')
OnGo();
}
});
buttonSqrt = new Button("sqrt");
buttonSqrt.addActionListener(this);
buttonMod = new Button("%");
buttonMod.addActionListener(this);
buttonReciprocal = new Button("1/x");
buttonReciprocal.addActionListener(this);
}
/*
* initMenu()函数是对各菜单的初始化,先为其生成实例对象,再添加到
* MenuBar 的实例对象 menuGroup 中,MenuItem 各项添加到相应的 Menu中。 */
void initMenu()
{
/*
* 先为各个菜单项生成实例对象,并为其设置相应的标签。MenuItem各项 * 还要设置 addActionListener(this) 增加委托事件任务。
*/
menuGroup = new MenuBar();
editMenu = new Menu("编辑(E)");
viewMenu = new Menu("查看(V)");
helpMenu = new Menu("帮助(H)");
copyItem = new MenuItem("复制(C) Ctrl+C",new
MenuShortcut(KeyEvent.VK_C));
copyItem.addActionListener(new CopyNum());
pasteItem = new MenuItem("粘贴(P) Ctrl+V",new
MenuShortcut(KeyEvent.VK_V));
pasteItem.addActionListener(new PasteNum());
standardModel = new MenuItem("●标准型(T)");
standardModel.addActionListener(this);
numGroup = new CheckboxMenuItem("数字分组(I)",false);
numGroup.addItemListener(this);
aboutCal = new MenuItem("关于计算器(A)");
aboutCal.addActionListener(this);
/* 再把各个菜单相继加入到 MenuBar 中 */
menuGroup.add(editMenu);
menuGroup.add(viewMenu);
menuGroup.add(helpMenu);
editMenu.add(copyItem);
editMenu.add(pasteItem);
viewMenu.add(standardModel);
viewMenu.add(numGroup);
helpMenu.add(aboutCal);
}
/*
* OverallArrangement() 是根据mainFrame的框架大小,把文本框answerText, * 内存使用的情况文本框memoryState,内存操作键 MR MS M+ MC,退格键BackSpace * 清除键 CE ,清空键 C ,以及主键盘区的各键按照一定的比例位置加入到mainFrame * 中.
*/
void OverallArrangement()
{
Panel textPanel = new Panel(); //文本框的容器
Panel upperPanel = new Panel(); //计算器上部分的容器
Panel centerPanel = new Panel(); //计算器中部的容器
Panel mainPanel = new Panel(); //主键盘区的容器
Panel leftPanel = new Panel(); //内存区的容器
Panel rightPanel = new Panel(); //数字及相应的操作键盘区
mainFrame.setMenuBar(menuGroup); //为主框架设置菜单栏
mainFrame.add(upperPanel,BorderLayout.NORTH); //把上容器放在主框架的北面
mainFrame.add(centerPanel); //把中容器放在主框架的中部
mainFrame.add(mainPanel,BorderLayout.SOUTH); //把主容器放在主框架的南面
/*设置主框架的上半部分*/
textPanel.add(answerText); //把文本框添加到文本容器中
upperPanel.add(textPanel); //把文本容器放入上容器中
/*设置主框架的中部*/
//采用流式布局,各组件相互间隔10个像素
centerPanel.setLayout(new FlowLayout(FlowLayout.CENTER,10,10));
centerPanel.add(memoryState); //把内存记忆框放在中容器中
centerPanel.add(buttonBackSpace); //把退格键放在中容器中
centerPanel.add(buttonCE); //把清除键放在中容器中
centerPanel.add(buttonC); //把清空键放在中容器中
/*设置主框架的下半部分*/
leftPanel.setLayout(new GridLayout(4,1,0,5)); //容器采用4*1的网式布局
leftPanel.add(buttonMC); // leftPanel.add(buttonMR); // leftPanel.add(buttonMS); // leftPanel.add(buttonMADD); // mainPanel.add(leftPanel,BorderLayout.WEST); //放在主容器的西面
/*设置主键盘区*/
rightPanel.setLayout(new GridLayout(4,5,5,5)); //的网式布局,相互间隔5各像素
/*添加各键*/
rightPanel.add(buttonNum[7]);
rightPanel.add(buttonNum[8]);
rightPanel.add(buttonNum[9]);
rightPanel.add(buttonDiv);
rightPanel.add(buttonSqrt);
rightPanel.add(buttonNum[4]);
rightPanel.add(buttonNum[5]);
rightPanel.add(buttonNum[6]);
rightPanel.add(buttonMul);
rightPanel.add(buttonMod);
rightPanel.add(buttonNum[1]);
rightPanel.add(buttonNum[2]);
rightPanel.add(buttonNum[3]);
rightPanel.add(buttonSub);
rightPanel.add(buttonReciprocal);
rightPanel.add(buttonNum[0]);
rightPanel.add(buttonSign);
rightPanel.add(buttonDot); 左下角的添加MC 添加MR 添加MS 添加M+ 把此容器采用4*5
rightPanel.add(buttonAdd);
rightPanel.add(buttonEqual);
mainPanel.add(rightPanel,BorderLayout.CENTER);
}
//结束对各GUI组件进行的操作函数。
/*
* actionPerformed(ActionEvent e) 是为各按钮及菜单项添加相应的属性 */
public void actionPerformed(ActionEvent e)
{
Object event = e.getSource(); //所按下的按钮的命令
//如果按下的是数字键
for (int i=0;i<buttonNum.length;i++)
{
if (event == buttonNum[i])
{
textBuffer.append(e.getActionCommand());
showScreen();
AddNum();
canBeBack = true;
}
}
//如果按下的是小数点
if (event == buttonDot)
{
if (textBuffer.indexOf(".") == -1)
{
numDot = 1;
textBuffer.append(".");
showScreen();
}
}
//如果按下的是退格键
if (event == buttonBackSpace && canBeBack == true)
{
if (textBuffer.length() > 0)
{
if (textBuffer.length()==1)
textBuffer = new StringBuffer("0");
else textBuffer.deleteCharAt(textBuffer.length()-1); showScreen();
AddNum();
}
}
//如果按下的是清除键
if (event == buttonCE)
{
reSet();
}
//如果按下的是清空键
if (event == buttonC)
{
reSet();
}
//如果按下的是正负标志键
if (event == buttonSign)
{
if (result!=0)
{
result*=-1;
textBuffer=new StringBuffer(Double.toString(result)); AddNum();
showScreenValue();
}
}
//如果按下的是加法键
if (event == buttonAdd) AddFunction(1);
//如果按下的是减法键
if (event == buttonSub) AddFunction(2);
//如果按下的是乘法键
if (event == buttonMul) AddFunction(3);
//如果按下的是除法键
if (event == buttonDiv) AddFunction(4);
//如果按下的是等号键
if (event == buttonEqual) OnGo();
//如果按下的是根号键
if (event == buttonSqrt)
{
if (result < 0)
{
answerText.setText("负数不能开根号"); }
else
{
result = Math.sqrt(result);
showScreenValue();
b_remFir = true; remFir = result; enterSecond = false; forFirOrSec = 2; }
}
//如果按下的是百分号键
if (event == buttonMod)
{
result /= 100;
showScreenValue();
b_remFir = true; remFir = result; enterSecond = false; forFirOrSec = 2; }
//如果按下的是倒数键
if (event == buttonReciprocal)
{
result = 1/result;
showScreenValue();
b_remFir = true; remFir = result; enterSecond = false; forFirOrSec = 2; }
//内存键操作部分
//如果按下的是MC键
if (event == buttonMC)
{
memory = 0;
memoryState.setText("");
}
//如果按下的是MR键
if (event == buttonMR)
{
//若memory值为整数,怎把小数点后的零给去掉。
int resInteger = (int)memory;
if ( Math.abs(memory-resInteger) == 0 )
{
StringBuffer tmp = new StringBuffer(Double.toString(memory)); tmp.deleteCharAt(tmp.length()-1);
answerText.setText(tmp.toString());
}
else answerText.setText(Double.toString(memory));
if (isNumGroup == true)
{
showNumGroup();
}
}
//如果按下的是MS键
if (event == buttonMS)
{
memory = Double.parseDouble(textBuffer.toString());
memoryState.setText("M");
}
//如果按下的是M+键
if (event == buttonMADD)
{
memory += Double.parseDouble(textBuffer.toString());
}
//如果按下的是关于计算器键
if (event == aboutCal)
{
JOptionPane jop = new JOptionPane();
jop.showMessageDialog(mainFrame,"计算器1.00版\n开发者:胡勇健"); }
}//End actionPerformed(ActionEvent e)
/*
* itemStateChanged(ItemEvent e) 时为菜单项添加相应的属性
*/
public void itemStateChanged(ItemEvent e)
{
Object event = e.getSource();
//如果按下的是数字分组键
if (event == numGroup)
{
if (isNumGroup == true)
{
isNumGroup = false;
deleteNumGroup();
}
else
{
isNumGroup = true;
showNumGroup();
}
}
}
// reSet() 是把各属性设置为原始值
void reSet()
{
answerText.setText("0.");
textBuffer = new StringBuffer("");
numDot=0;
remFun = operator = 0;
firstValue = secondValue = result = 0.0;
enterSecond = false;
forFirOrSec = 1;
b_remFir = b_remSec = b_remFun = false;
remFir = remSec = 0.0;
canBeBack = true;
}
// showScreen() 是当按下了数字键后,在屏幕上显示。如果有数字分组项, // 则调用数字分组函数。如为整数则在其后只显示一个小数点,例如:数值
// 5 应该显示为 5. 若为小数,则直接显示。
void showScreen()
{
if (numDot==0)
answerText.setText(textBuffer.toString()+".");
else
answerText.setText(textBuffer.toString());
if (isNumGroup == true)
{
showNumGroup();
}
}
// showScreenValue() 是用于显示计算后的结果值,具体的功能同上。 void showScreenValue()
{
int resInteger = (int)result;
if ( Math.abs(result-resInteger) == 0 )
{
StringBuffer tmp = new StringBuffer(Double.toString(result)); tmp.deleteCharAt(tmp.length()-1);
answerText.setText(tmp.toString());
}
else answerText.setText(Double.toString(result));
if (isNumGroup == true)
{
showNumGroup();
}
}
// 数字分组的显示:每隔三位显示一个逗号以示分隔。
void showNumGroup()
{
int i,cnt=0;
String string = answerText.getText();
String interge,fraction;
interge = fraction = string;
for (i=0;i<string.length();i++)
{
if (string.charAt(i)=='.')
{
interge = string.substring(0,i);
fraction = string.substring(i+1,string.length()); break;
}
}
StringBuffer sb = new StringBuffer(interge);
sb.reverse();
for (i=0;i<sb.length() ;i++ )
{
if (Character.isDigit(sb.charAt(i)))
{
cnt++;
if (cnt>3)
{
cnt = 0;
sb.insert(i,",");
}
}
}
sb.reverse();
answerText.setText(sb.toString()+"."+fraction);
}
//deleteNumGroup() 是当已经数字分组时,再次按下该键,消除数字分组的效果; void deleteNumGroup()
{
StringBuffer sb = new StringBuffer(answerText.getText());
for (int i=0;i<sb.length() ;i++ )
{
if (sb.charAt(i)==',')
{
sb.deleteCharAt(i);
}
}
answerText.setText(sb.toString());
}
//当输入了四则运算符时
void AddFunction(int op)
{
//如果此时第二个数存在.则运算,例如输入2+3=5后按*4 +
if (b_remFir==true && b_remFun==false && enterSecond==true) {
if (operator == 1) result = remFir + secondValue;
else if (operator == 2) result = remFir - secondValue;
else if (operator == 3) result = remFir * secondValue;
else if (operator == 4) result = remFir / secondValue;
b_remFir = true; remFir = result; enterSecond = false; forFirOrSec = 2; operator = op;
showScreenValue();
}
//如果此时第二个数存在.则运算,例如输入2+3后按*键
else if (b_remFir==false && b_remFun==false && enterSecond==true) {
if (operator == 1) result = firstValue + secondValue;
else if (operator == 2) result = firstValue - secondValue; else if (operator == 3) result = firstValue * secondValue; else if (operator == 4) result = firstValue / secondValue;
b_remFir = true; remFir = result; enterSecond = false; forFirOrSec = 2; operator = op;
showScreenValue();
}
else
{
operator = op;
forFirOrSec = 2;
}
b_remFun = false; remFun = 0;
textBuffer = new StringBuffer("");
}
// 把屏幕上的值存入result 和 firstValue secondValue 中。
void AddNum()
{
if (forFirOrSec == 1)
{
result = firstValue = Double.parseDouble(textBuffer.toString()); b_remFir = false; remFir = 0;
}
else if (forFirOrSec == 2)
{
enterSecond = true;
secondValue = Double.parseDouble(textBuffer.toString()); b_remSec = false; remSec = 0;
}
}
//当按下了等于号时
void OnGo()
{
//如果记着第一,二个数和运算符,即上次算完后未输入数,而再次按= if (b_remFir==true && b_remSec==true && b_remFun==true)
{
if (remFun==1) result = remFir + remSec;
else if (remFun==2) result = remFir - remSec;
else if (remFun==3) result = remFir * remSec;
else if (remFun==4) result = remFir / remSec;
b_remFir=true; b_remSec=true; b_remFun=true;
remFir = result; remSec = remSec; remFun = remFun;
}
//只记的第一数,如算完2+3=5后按*4=
else if (b_remFir==true && b_remSec==false && b_remFun==false) {
if (operator == 1) result = remFir + secondValue;
else if (operator == 2) result = remFir - secondValue; else if (operator == 3) result = remFir * secondValue; else if (operator == 4) result = remFir / secondValue;
b_remFir=true; b_remSec=true; b_remFun=true;
remFir = result; remSec = secondValue; remFun = remFun; }
//记住了第一个数,未输入第二个数,输入了运算符.如算完2+3=5后按*=结果为5*5=25;
else if (b_remFir==true && b_remSec==true && b_remFun==false) {
secondValue = remFir;
if (operator == 1) result = remFir + secondValue;
else if (operator == 2) result = remFir - secondValue; else if (operator == 3) result = remFir * secondValue; else if (operator == 4) result = remFir / secondValue;
b_remFir=true; b_remSec=true; b_remFun=true;
remFir = result; remSec = secondValue; remFun = remFun; }
//第一二个数和运算符都不记的,记全重新输入,如算完2+3=5后输入4*6= else if (b_remFir==false && b_remSec==false && b_remFun==false) {
if (enterSecond == false) secondValue = firstValue;
if (operator == 1) result = firstValue + secondValue;
else if (operator == 2) result = firstValue - secondValue; else if (operator == 3) result = firstValue * secondValue; else if (operator == 4) result = firstValue / secondValue;
b_remFir=true; b_remSec=true; b_remFun=true;
remFir = result; remSec = secondValue; remFun = remFun;
}
showScreenValue();
// if (result - (int)result == 0) textBuffer = new
StringBuffer(Integer.toString((int)result));
// else textBuffer = new StringBuffer(Double.toString(result)); textBuffer = new StringBuffer("");
firstValue = secondValue = 0;
forFirOrSec = 1;
enterSecond = false;
canBeBack = false;
}
//以下定义的两个私有成员类是用于复制和粘贴文本区的数字的:
private class CopyNum implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
StringBuffer selection = new StringBuffer(answerText.getText()); if (selection == null)
return;
if ( selection.charAt(selection.length()-1)=='.' )
{
selection.deleteCharAt(selection.length()-1);
}
StringSelection clipString = new
StringSelection(selection.toString());
clipbd.setContents(clipString,clipString);
}
};
private class PasteNum implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
Transferable clipData = clipbd.getContents(SimpleCalculator.this); try
{
String clipString =
(String)clipData.getTransferData(DataFlavor.stringFlavor);
for (int i=0;i<clipString.length();i++)
{
if ( !(Character.isDigit(clipString.charAt(i)) || clipString.charAt(i)=='.') )
{
clipString = new String("0.");
break;
}
}
answerText.setText(clipString);
}
catch (Exception ex)
{
System.out.println("Couldn't get contents in format: "+ DataFlavor.stringFlavor.getHumanPresentableName()); }
}
};
public static void main(String args[])
{
new SimpleCalculator();
}
}