简易计算器
1.任务介绍
- 学会分析“简易计算器”任务的实现思路;
- 根据思路独立完成“简易计算器”的源代码编写、编译和运行;
- 掌握正则表达式来判定数字键或者数据是否合法;
- 掌握String类常用方法的使用,如:contains方法等;
- 掌握Java异常处理机制;
- 熟练掌握Swing包(JTextField控件、JButton控件和控件数组)的使用,以及常用布局方式的使用;
- 掌握GUI开发过程中如何处理组件上发生的界面事件。
2.运行结果
3.实现思路
界面布局实现思路:
- 根据实验要求,利用GridBagLayout布局将每个组件放在合适的位置,利用GridBagConstraints类中的Insets方法实现组件间隔;
- 利用数组存放每个组件显示的文本。
事件处理实现思路:
- 设计ComputerListener接口继承按钮触发事件ActionListener接口以增加其抽象方法实现将界面事件传至PoliceListen类(PoliceListen类实现接口ComputerListener)做事件处理。
计算功能实现思路:
【输入合法机制】
- 避免第一位为符号: 设置判断当第一位按非数字使不处理 ;
- 当第一位为零,第二位也为零:设置判断当第一位为零时输入数字无效 ;
- 避免首位为零,其后出现多个零(即0001):判断该输入的倒数第二位是否为符号,倒数第一位是否为0,在对按钮0。是则不做处理;
- 避免输出数字不合法(多个小数点 即6.6.6):利用循环以符号位为分割线,判该数字是否存在已存在小数点 即 每个运算符号后的数字至多存在一个小数点;
- 排除多符号一起串连(即8+9+6/5): 点击运算符触发事件并判断前一位是否为符号,是则不做处理。
【计算字符串】
-
判断最后一位是否为运算符: 利用String类中的charAt()方法提取最后一位进行判断,是则提示错误,否则运算;
-
字符和数字分离: 两次利用StringTokenizer类进行字符串提取分析分别得到数字序列和运算符序列;
-
将数字序列和运算符序列存放在两个链表中链表的删除较为便利 ;
-
根据优先级计算:设置两个循环(当符号链表中的数据不为空则继续),第一个循环计算所有得乘除,即符号前后得两个数乘除,结果放在第一个数中删除第一个数和删除符号;第二个循环计算所有的加减,结果放在第一个数中删除第一个数和删除符号。
4.UML图
5.实现代码
Text.java
package calculator;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
PoliceListen policeListen = new PoliceListen();
Win win = new Win();
win.setComputerListener(policeListen);
}
}
Win.java(窗口 View)
package calculator;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class Win extends JFrame {
JTextField jTextField;
JTextArea jTextArea;
JButton jButton[] = new JButton[20];
JLabel jLabel;
ComputerListener computerListener;
public Win() {
init();
setTitle("计算器");
setSize(600, 600);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
void init() {
GridBagLayout layout = new GridBagLayout();
this.setLayout(layout);
String[] strings = { "7", "8", "9", "/", "C", "4", "5", "6", "*", "Sqrt", "1", "2", "3", "-", "1/X", "+/-", "0",
".", "+", "=" };
for (int i = 0; i < jButton.length; i++) {
jButton[i] = new JButton(strings[i]);
// this.add(jButton[i]);
}
jTextArea = new JTextArea();
JScrollPane jScrollPane = new JScrollPane(jTextArea);
jTextField = new JTextField();
jLabel = new JLabel();
GridBagConstraints s = new GridBagConstraints();// 定义一个GridBagConstraints,
s.fill = GridBagConstraints.BOTH;
s.gridwidth = 1;
s.gridheight = 6;
s.weightx = 0;
s.weighty = 0;
s.insets = new Insets(5, 5, 2, 2);
s.ipadx = 200;
s.ipady = 10;
// jTextArea.setSize();
layout.setConstraints(jScrollPane, s);
this.add(jScrollPane);
s.ipadx = 10;
s.ipadx = 10;
// this.add(jTextArea);
s.gridwidth = 5;
s.gridheight = 1;
s.weightx = 0;
s.weighty = 0;
layout.setConstraints(jTextField, s);
this.add(jTextField);
JPanel jPanel1 = new JPanel();
s.gridwidth = 0;
s.weightx = 0;
s.weighty = 0;
layout.setConstraints(jPanel1, s);
this.add(jPanel1);
for (int i = 1; i < jButton.length + 1; i++) {
if (i % 5 == 0) {
s.gridwidth = 1;
s.weightx = 0;
s.weighty = 0;
layout.setConstraints(jButton[i - 1], s);
this.add(jButton[i - 1]);
jPanel1 = new JPanel();
s.gridwidth = 0;
s.weightx = 0;
s.weighty = 0;
layout.setConstraints(jPanel1, s);
this.add(jPanel1);
} else {
s.gridwidth = 1;
s.weightx = 0;
s.weighty = 0;
layout.setConstraints(jButton[i - 1], s);
this.add(jButton[i - 1]);
}
}
}
void setComputerListener(ComputerListener computerListener) {
this.computerListener = computerListener;
computerListener.setJTextArea(jTextArea);
computerListener.setJTextField(jTextField);
for (int i = 0; i < jButton.length; i++) {
computerListener.setJBTextbotton(jButton);
jButton[i].addActionListener(computerListener);
}
}
}
PoliceListen.java(Controller)
package calculator;
import java.awt.event.ActionEvent;
import java.util.LinkedList;
import java.util.StringTokenizer;
import javax.swing.JButton;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class PoliceListen implements ComputerListener {
JTextArea jTextArea;
JTextField jTextField;
JButton jButton[] = new JButton[20];
double answer = 0;
@Override
public void actionPerformed(ActionEvent e) {
Operation(e);
}
void Operation(ActionEvent e) {
if (e.getActionCommand().equals("C")) {// 输入框置空
jTextField.setText(null);
}
if (jTextField.getText().length() == 0) {// 保证第一位为数字
if (e.getActionCommand().matches("[\\d]")) {
jTextField.setText(e.getActionCommand());
}
} else if (jTextField.getText().length() == 1 // 在第一位为零情况下,第二位非数字排除开始 001的情况
&& ((jTextField.getText().charAt(0) + "").equals("0")) && e.getActionCommand().matches("[\\d]")) {
} else if (jTextField.getText().length() == 1 // 在第一位为零情况下,第二位非数字排除开始 001的情况
&& !(jTextField.getText().charAt(0) + "").equals("0")) {
if (!e.getActionCommand().equals("=")) {
jTextField.setText(jTextField.getText() + e.getActionCommand());
}
} else {
// 保证第三位开始若输入"0" 判断前两位是否为符号,前一位是否为"0" 排除 (+-*/00)情况
if (e.getActionCommand().matches("[\\d]")) {
String string2 = jTextField.getText().charAt(jTextField.getText().length() - 2) + "";
String string1 = jTextField.getText().charAt(jTextField.getText().length() - 1) + "";
if ((string2.equals("+") || string2.equals("/") || string2.equals("*") || string2.equals("-"))
&& string1.equals("0")) {
} else {
jTextField.setText(jTextField.getText() + e.getActionCommand());
}
}
// 以符号位为分割点 保证输入"数字"合法
if (e.getActionCommand().equals(".")) {
int count = 0;
for (int i = 0; i < jTextField.getText().length(); i++) {
String string = jTextField.getText().charAt(i) + "";
if (string.equals(".")) {
count = 1;
}
if (string.equals("+") || string.equals("/") || string.equals("*") || string.equals("-")) {
count = 0;
}
}
if (count == 0) {
jTextField.setText(jTextField.getText() + e.getActionCommand());
}
}
if (e.getActionCommand().equals("+") || e.getActionCommand().equals("/") || e.getActionCommand().equals("*")
|| e.getActionCommand().equals("-")) {
String string = String.valueOf(jTextField.getText().charAt(jTextField.getText().length() - 1));
if (string.matches("[\\d]")) {
jTextField.setText(jTextField.getText() + e.getActionCommand());
}
}
if (e.getActionCommand().equals("=")) {
String lastFlagString = jTextField.getText().charAt(jTextField.getText().length() - 1) + "";
if (lastFlagString.matches("[\\d]")) {
calculate();
} else {
jTextField.setText("输入非法,以符号结尾");
}
}
}
if (e.getActionCommand().equals("+/-")) {
jTextArea.append("+/- :" + answer + "=" + -answer + "\n");
}
if (e.getActionCommand().equals("1/X")) {
if (answer != 0) {
jTextArea.append("1/X" + answer + "=" + 1 / answer + "\n");
} else {
jTextArea.append("除数为零\n");
}
}
if (e.getActionCommand().equals("Sqrt")) {
jTextArea.append("Sqrt:" + answer + "=" + Math.sqrt(answer) + "\n");
}
}
void calculate() {
LinkedList<Double> operater_Number = new LinkedList<Double>();
LinkedList<String> operater_Flag = new LinkedList<String>();
StringTokenizer fenxi_Number = new StringTokenizer(jTextField.getText(), "+-*/");
StringTokenizer fenxi_Flag = new StringTokenizer(jTextField.getText(), "0123456789.");
int count_Number = fenxi_Number.countTokens();
for (int i = 0; i < count_Number; i++) {
operater_Number.add(Double.parseDouble(fenxi_Number.nextToken()));
}
int count_Flag = fenxi_Flag.countTokens();
for (int i = 0; i < count_Flag; i++) {
operater_Flag.add(fenxi_Flag.nextToken());
}
while (operater_Flag.size() != 0 && operater_Number.size() > 1) {
for (int i = 0; i < operater_Flag.size(); i++) {
boolean exit = false;
if (operater_Flag.get(i).equals("*")) {
operater_Number.set(i, operater_Number.get(i) * operater_Number.get(i + 1));
exit = true;
}
if (operater_Flag.get(i).equals("/")) {
operater_Number.set(i, (operater_Number.get(i) / operater_Number.get(i + 1) * 1.0));
exit = true;
}
if (exit == true) {
operater_Flag.remove(i);
operater_Number.remove(i + 1);
i = i - 1;
}
}
for (int i = 0; i < operater_Flag.size(); i++) {
boolean exit = false;
if (operater_Flag.get(i).equals("+")) {
operater_Number.set(i, operater_Number.get(i) + operater_Number.get(i + 1));
exit = true;
}
if (operater_Flag.get(i).equals("-")) {
operater_Number.set(i, operater_Number.get(i) - operater_Number.get(i + 1));
exit = true;
}
if (exit == true) {
operater_Flag.remove(i);
operater_Number.remove(i + 1);
i = i - 1;
}
}
}
this.answer = operater_Number.get(0);
jTextArea.append(jTextField.getText() + "=" + operater_Number.get(0) + "\n");
jTextField.setText(null);
operater_Flag.clear();
operater_Number.clear();
}
@Override
public void setJTextArea(JTextArea jTextArea) {
// TODO Auto-generated method stub
this.jTextArea = jTextArea;
}
@Override
public void setJTextField(JTextField jTextField) {
// TODO Auto-generated method stub
this.jTextField = jTextField;
}
@Override
public void setJBTextbotton(JButton jButton[]) {
// TODO Auto-generated method stub
this.jButton = jButton;
}
}
ComputerListener.java
package calculator;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public interface ComputerListener extends ActionListener {
public void setJTextArea(JTextArea jTextArea);
public void setJTextField(JTextField jTextField);
public void setJBTextbotton(JButton jButton[]);
}
GridBagDemo.java【关于GridBag笔记】
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class GridBagDemo extends JFrame {
public static void main(String args[]) {
GridBagDemo demo = new GridBagDemo();
}
public GridBagDemo() {
init();
this.setSize(300, 300);
this.setVisible(true);
}
JButton j1;
JButton j2;
JButton j3;
JPanel j4;
JComboBox j5;
JTextField j6;
JButton j7;
JList j8;
JTextArea j9;
void init() {
// GridBagConstraints gridBagConstraints = new GridBagConstraints();
j1 = new JButton("打开");
j2 = new JButton("保存");
j3 = new JButton("另存为");
j4 = new JPanel();
String[] str = { "java笔记", "C#笔记", "HTML5笔记" };
j5 = new JComboBox(str);
j6 = new JTextField();
j7 = new JButton("清空");
j8 = new JList(str);
j9 = new JTextArea();
j9.setBackground(Color.PINK);// 为了看出效果,设置了颜色
GridBagLayout layout = new GridBagLayout();
this.setLayout(layout);
this.add(j1);// 把组件添加进jframe
this.add(j2);
this.add(j3);
this.add(j4);
this.add(j5);
this.add(j6);
this.add(j7);
this.add(j8);
this.add(j9);
GridBagConstraints s = new GridBagConstraints();// 定义一个GridBagConstraints,
// 是用来控制添加进的组件的显示位置
s.fill = GridBagConstraints.BOTH;
// 该方法是为了设置如果组件所在的区域比组件本身要大时的显示情况
// NONE:不调整组件大小。
// HORIZONTAL:加宽组件,使它在水平方向上填满其显示区域,但是不改变高度。
// VERTICAL:加高组件,使它在垂直方向上填满其显示区域,但是不改变宽度。
// BOTH:使组件完全填满其显示区域。
s.gridwidth = 3;// 该方法是设置组件水平所占用的格子数,如果为0,就说明该组件是该行的最后一个
s.weightx = 0;// 该方法设置组件水平的拉伸幅度,如果为0就说明不拉伸,不为0就随着窗口增大进行拉伸,0到1之间
s.weighty = 0;// 该方法设置组件垂直的拉伸幅度,如果为0就说明不拉伸,不为0就随着窗口增大进行拉伸,0到1之间
layout.setConstraints(j1, s);// 设置组件
s.gridwidth = 1;
// s.insets = new Insets(5, 5, 5, 5);
s.weightx = 0;
s.weighty = 0;
layout.setConstraints(j2, s);
s.gridwidth = 1;
s.weightx = 0;
s.weighty = 0;
layout.setConstraints(j3, s);
s.gridwidth = 0;// 该方法是设置组件水平所占用的格子数,如果为0,就说明该组件是该行的最后一个
s.weightx = 0;// 不能为1,j4是占了4个格,并且可以横向拉伸,
// 但是如果为1,后面行的列的格也会跟着拉伸,导致j7所在的列也可以拉伸
// 所以应该是跟着j6进行拉伸
s.weighty = 0;
layout.setConstraints(j4, s);
s.gridwidth = 2;
s.weightx = 0;
s.weighty = 0;
layout.setConstraints(j5, s);
;
s.gridwidth = 4;
s.weightx = 1;
s.weighty = 0;
layout.setConstraints(j6, s);
;
s.gridwidth = 0;
s.weightx = 0;
s.weighty = 0;
layout.setConstraints(j7, s);
;
s.gridwidth = 2;
s.weightx = 0;
s.weighty = 1;
layout.setConstraints(j8, s);
;
s.gridwidth = 5;
s.weightx = 0;
s.weighty = 1;
layout.setConstraints(j9, s);
}
}
6.总结感悟
错误分析:
a) 输入一个数中多个小数点;
b) 分析器的StringTokenizer的是否错误;
c) 正则表达式的使用错误。
错误解决:
a) 以运算符为分割,运算符后的数字之多只有一个小数点;
b) 在分析器使用分析字符串中的标点符号时未排除”0”,最后在单步调试中发现错误;
c) “[±*/]” 该正则表达式可以匹配”.”,导致浪费大量的时间检查在”.”的触发事件上。
通过本次实验学习到了以下几点:
a) 该开始入手实验时无从下手,一边考虑如何布局,一边考虑如何输出合法,一边考虑如何实现计算,一心三用,没有主次先后的编程观念。浪费比较多的时间;而后有了步骤,先将组件间的布局做好,在考虑输入数据的合法,最后在合法的情况下实现计算;
b) 学习到了一种新的布局方式GridBagLayout布局,该布局也是一种类似网格布局,改进GridLayout布局不能改变组件在网格中的大小的,组件间的间隔问题;
c) 本次实验未使用 WindowBuilding插件,主要的原因时想检验以下自己在暑假看课本的成果,以及个人认为在使用插件时容易将代码弄乱。不过在布局方面花费比较多的时间。但也熟悉了几个布局的特点,以及他们的常用方法;
d) 本次实验最大的收获就是熟悉掌握了一个类中实例的对象在利用构造方 法在各个类中的重复使用,以及复习接口的相关知识。