JavaGUI实现科学计算器

一、设计思想

  1. 界面及布局
  2. 利用Java中awt、swing包里的工具对计算器布局设计(为了使运算可控,所以将文本区只能设为从Button输入)
  3. 给每个Button加监听器
    对于数字和运算符Button,让其在文本行中显示算术表达式
    LogClear:清理历史记录
    LogTextEnable:对历史记录能否操作Button
    BackSpace、C:BackSpace清除文本行中最后一个字符,C清除所有字符。
    =:对文本行中算术表达式进行计算并显示结果,将结果显示到历史记录中。
  4. 核心算法(自己想的算法解决问题,可能存在致命性错误)
    对字符串表达式进行计算
    设计思想:
  1. 先不考虑()、e、π
  2. 将算术表达式拆分为A+B-C形式,A、B、C中含有比 + - 更高级的运算符
  3. 对A、B、C进行判断,看其是否含有更高级的运算符,若没有,则直接进行加减运算。若有,则进行对更高级运算符的处理,看步骤4,然后进行加减运算处理。END
  4. 将A中表达式进行拆分为a*b/c形式,a、b、c中含有更高级运算符
    对a、b、c进行判断,看其是否含有更高级的运算符,若没有,则直接进行乘除运算。若有,则进行对更高级运算符的处理,看步骤5,然后进行乘除运算处理。
  5. 将a中表达式进行拆分为x^y^z(x的y*z次方或x的y次方的z次方,结果一样)形式,x、y、z中含有更高级运算符
    对x、y、z进行判断,看其是否含有更高级的运算符,若没有,则直接进行运算。若有,则进行对更高级运算符的处理,看步骤6,然后进行运算处理。
  6. 到了此步x、y、z中就只包含了一个数字,对其操作有开方(其与幂运算等级不影响结果)、cos、sin、tan、!(阶乘),若有运算级歧义可用()处理。
    对x、y、z扫描取出数字,先进行阶乘判断若有阶乘符号则对数字进行阶乘运算,因为阶乘只能对整数操作,其他运算有特别大几率产生小数。再进行开方判断……
  7. ()、e、π处理(若运算级优先级有问题可以用括号提升优先级)
    e、π其特点是只有一个字符可对表达式进行一次扫描,若有则调用Math包中Math.E、Math.PI对其替换
    ():对表达式进行一次遍历,利用List<StringBuffer>对表达式进行处理,若扫描到(则将下一个扫描的字符存储到下一个StringBuffer中,若扫描到)则对这一个StringBuffer进行计算,计算方法为1~6

二、算法实现

项目文件结构:

java 计算器菜单 javagui计算器_java

CalculatorFrame.java文件:对页面的设置

package com.zhao.calc.frame;

import java.awt.BorderLayout;

import javax.swing.JFrame;

public class CalculatorFrame extends JFrame {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public CalculatorFrame() {

		setTitle("计算器");		// 设置窗口标题
		setSize(1200, 600);		// 设置窗口大小
		add(new CalculatorPanel(), BorderLayout.CENTER);
		setVisible(true);		//设置可见
	}

}

CalculatorPanel.java文件:对面板布局的管理

package com.zhao.calc.frame;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.TextArea;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JTextField;

import com.zhao.calc.util.CalculatorMathUtils;

public class CalculatorPanel extends JPanel {
	private static final long serialVersionUID = 1L;
	private JPanel panel = null;
	private Font font = null;
	private JTextField display = null;
	private TextArea log = null;
	private String nowButton = null;
	private boolean logEnable = true; // log 使能 判别

	public CalculatorPanel() {
		setLayout(new BorderLayout()); // 设置为网格布局
		font = new Font("宋体", 4, 30); // 设置字体

		// 添加文本框
		display = new JTextField(""); // 默认置为空
		display.setEnabled(false); // display设置为不能编辑
		display.setFont(font);
		add(display, BorderLayout.NORTH); // 把文本框加在上面north里

		// 添加日志
		log = new TextArea(500, 30); // 大小为rows 500 columns 30
		log.setFont(new Font("宋体", 4, 20));
		log.setForeground(Color.BLUE); // 字体颜色 enable为true 可见
		log.setEnabled(false);
		log.setText("历史记录:\n");
		add(log, BorderLayout.EAST); // 把文本框加在上面east里

		// 监听操作按钮
		ActionListener command = new CommandAction();

		// panel是中间按钮的布局,放到布局管理器的center里
		panel = new JPanel();

		panel.setLayout(new GridLayout(8, 4)); // panel为网格布局 8行 4列

		// 设置按钮
		addButton("LogClear", command);
		addButton("LogTextEnable", command);
		addButton("BackSpace", command);
		addButton("C", command);

		addButton("e", command);
		addButton("π", command);
		addButton("tan", command);
		addButton("!", command);

		addButton("√", command);
		addButton("^", command);
		addButton("cos", command);
		addButton("sin", command);

		addButton("(", command);
		addButton(")", command);
		addButton("log", command);
		addButton("ln", command);

		addButton("7", command);
		addButton("8", command);
		addButton("9", command);
		addButton("+", command);

		addButton("4", command);
		addButton("5", command);
		addButton("6", command);
		addButton("-", command);

		addButton("1", command);
		addButton("2", command);
		addButton("3", command);
		addButton("*", command);

		addButton(".", command);
		addButton("0", command);
		addButton("=", command);
		addButton("/", command);
		// 将按钮添加到CENTER
		add(panel, BorderLayout.CENTER);
	}

	// 添加button 添加事件
	public void addButton(String label, ActionListener listener) {
		JButton button = new JButton(label);
		button.setFont(font); // 设置按钮字体
		button.addActionListener(listener); // 添加监听器
		panel.add(button); // 将按钮添加到panel中
	}

	// 单击按钮执行命令的监听器
	class CommandAction implements ActionListener {
		@Override
		public void actionPerformed(ActionEvent event) {
			// 获得产生事件的按钮名称
			nowButton = event.getActionCommand();
			// 将按钮的名称打印到display中
			if (nowButton != "BackSpace" && nowButton != "=" && nowButton != "LogClear"
					&& nowButton != "LogTextEnable") {
				// 如果是BackSace = LogClear LogTextEnable就不打印这个了
				display.setText(display.getText() + nowButton);
			}

			if (nowButton.equals("=")) {
				// 如果是等于号,就计算结果 并打印日志
				log.append(display.getText() + "\n= " + CalculatorMathUtils.calcString(display.getText()) + "\n");
				display.setText(CalculatorMathUtils.calcString(display.getText()));
			}

			if (nowButton.equals("BackSpace")) {
				// 回退一个字符
				StringBuffer sb = new StringBuffer(display.getText());
				if (sb.length() != 0) {
					display.setText(sb.substring(0, sb.length() - 1));
				}
			}
			if (nowButton.equals("C")) {
				// 清空
				display.setText("");
			}
			if (nowButton.equals("LogClear")) {
				// 清空历史记录
				log.setText("历史记录:\n");
			}
			if (nowButton.equals("LogTextEnable")) {
				// 设置历史记录 使能
				log.setEnabled(logEnable);
				logEnable = !logEnable;
			}
		}
	}
}

CalculatorMathUtils.java文件:对算术表达式的处理的工具类

package com.zhao.calc.util;

import java.util.ArrayList;
import java.util.List;

public class CalculatorMathUtils {
	// 对算术表达式进行计算
	public static String calcString(String str) {
		// 对 e π 进行替换
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < str.length(); i++) {
			if (str.charAt(i) == 'e') {
				sb.append(Math.E);
				continue;
			}
			if (str.charAt(i) == 'π') {
				sb.append(Math.PI);
				continue;
			}
			sb.append(str.charAt(i));
		}
		str = sb.toString();
		// 对 ( ) 进行处理
		List<StringBuffer> list = new ArrayList<StringBuffer>();
		int level = 0;
		list.add(new StringBuffer());
		for (int i = 0; i < str.length(); i++) {
			if (str.charAt(i) == '(') {
				list.add(new StringBuffer());
				level++;
				continue;
			}
			if (str.charAt(i) == ')') {
				list.get(level - 1).append(String.valueOf(calcString(list.get(level).toString())));
				list.remove(level);
				level--;
				continue;
			}
			list.get(level).append(str.charAt(i));
		}
		return calcLevel1(list.get(level).toString());
	}

	/*
	 *  第一层级 + - 运算
	 */
	private static String calcLevel1(String str) {
		
		/* 对负号进行处理 
		 * 对 1+-5 1--5进行计算 
		 * 第四层级 cos- -> cos sin- -> -sin 
		 * log- ln- √- 报错
		*/
		str = str.replace("--", "+");
		str = str.replace("+-", "-");
		str = str.replace("*+", "*");
		str = str.replace("/+", "/");
		str = str.replace("^+", "^");
		if (str.contains("cos-")) {
			str = str.replace("cos-", "cos");
		}
		if (str.contains("sin-")) {
			str = str.replace("sin-", "-sin");
		}
		if (str.contains("tan-")) {
			str = str.replace("tan-", "-tan");
		}
		if (str.contains("log-") || str.contains("ln-") || str.contains("√-")) {
			return "error:log- ln- √-";
		}
		str = str.replace("--", "+");
		str = str.replace("+-", "-");

		StringBuffer sb = new StringBuffer(str);
		int commandCount = 0;// 符号数量

		int j = 0;// 计数器
		// 计算有+ -个运算符,就有n+1个数字
		for (j = 0; j < sb.length() - 1; j++) {
			// 对第一个数符号进行处理
			if (j == 0 && sb.charAt(j) == '-') {
				continue;
			}
			if (j == 0 && sb.charAt(j) == '+') {
				continue;
			}
			String flag = "" + str.charAt(j) + str.charAt(j + 1);
			if (flag.equals("*-") || flag.equals("/-") || flag.equals("^-")) {
				j++;
				continue;
			}
			if (sb.charAt(j) == '+' || sb.charAt(j) == '-')
				commandCount++;
		}

		// 初始化符号数组
		char[] command = new char[commandCount];
		// 初始化数字数组(用字符串表示)
		String[] num = new String[commandCount + 1];
		for (j = 0; j < num.length; j++) {
			num[j] = "";
		}

		// 遍历一遍,吧每个数字存进数字数组,每个符号存进符号数组
		int k = 0;
		for (j = 0; j < sb.length(); j++) {
			// 对第一个数是否为负数进行处理
			if (j == 0 && sb.charAt(j) == '-') {
				num[k] += sb.charAt(j);
				continue;
			}
			if (j == 0 && sb.charAt(j) == '+') {
				continue;
			}
			// 对 *- /- ^- 进行处理
			if (j + 1 < sb.length()) {
				String flag = "" + sb.charAt(j) + sb.charAt(j + 1);
				if (flag.equals("*-") || flag.equals("/-") || flag.equals("^-")) {
					num[k] += flag;
					j++;
					continue;
				}
			}
			//对 + - 运算符进行保存
			if (sb.charAt(j) == '+' || sb.charAt(j) == '-') {
				command[k] = sb.charAt(j);
				k++;
				continue;
			}
			// 将数字及更高级运算保存在num[k]中
			num[k] += sb.charAt(j);
		}
		// 当num[i]中有更高级运算时对num[i]传入到calcLevel2(num[i])方法中进行解决
		for (int i = 0; i < num.length; i++) {
			if (num[i].contains("*") || num[i].contains("/") || num[i].contains("^") || num[i].contains("cos")
					|| num[i].contains("sin") || num[i].contains("tan")|| num[i].contains("log") || num[i].contains("ln") || num[i].contains("!")
					|| num[i].contains("√")) {
				num[i] = calcLevel2(num[i]);
			}
		}
		// 如果只包含一个数 返回这个数的值
		if (num.length == 1) {
			return num[0];
		}
		double result = 0;
		for (int i = 0; i < commandCount; i++) {
			// 取前两个数,和第一个操作符,运算
			double num1 = 0;
			double num2 = 0;
			try {
				num1 = Double.parseDouble(num[i]);
				num2 = Double.parseDouble(num[i + 1]);
			} catch (NumberFormatException e) {
				e.printStackTrace();
			}
			//取+ - 运算符进行运算
			char cc = command[i];
			if (cc == '+') {
				result = num1 + num2;
			} else if (cc == '-') {
				result = num1 - num2;
			}
			num[i + 1] = String.valueOf(result);
		}
		return String.valueOf(result);
	}

	/*
	 *  第二层级 * / 运算
	 */
	private static String calcLevel2(String str) {
		StringBuffer sb = new StringBuffer(str);
		int commandCount = 0;// 符号数量

		int j = 0;// 计数器
		// 计算有多少个运算符,就有n+1个数字
		for (j = 0; j < sb.length(); j++) {
			if (sb.charAt(j) == '*' || sb.charAt(j) == '/')
				commandCount++;
		}

		// 初始化符号数组
		char[] command = new char[commandCount];
		// 初始化数字数组(用字符串表示)
		String[] num = new String[commandCount + 1];
		for (j = 0; j < num.length; j++) {
			num[j] = "";
		}

		// 遍历一遍,吧每个数字存进数字数组,* /符号存进符号数组
		int k = 0;
		for (j = 0; j < sb.length(); j++) {
			if (sb.charAt(j) == '*' || sb.charAt(j) == '/') {
				command[k] = sb.charAt(j);
				k++;
				continue;
			}
			// 将数字及更高级运算保存在num[k]中
			num[k] += sb.charAt(j);
		}
		// 当num[i]中有更高级运算时对num[i]传入到calcLevel3(num[i])方法中进行解决
		for (int i = 0; i < num.length; i++) {
			if (num[i].contains("^") || num[i].contains("cos") || num[i].contains("sin") || num[i].contains("tan")|| num[i].contains("log")
					|| num[i].contains("ln") || num[i].contains("!") || num[i].contains("√")) {
				num[i] = calcLevel3(num[i]);
			}
		}
		// 如果只包含一个数 返回这个数的值
		if (num.length == 1) {
			return num[0];
		}
		double result = 0;
		for (int i = 0; i < commandCount; i++) {
			// 取前两个数,和第一个操作符,运算
			double num1 = 0;
			double num2 = 0;
			try {
				num1 = Double.parseDouble(num[i]);
				num2 = Double.parseDouble(num[i + 1]);
			} catch (NumberFormatException e) {
				e.printStackTrace();
			}
			char cc = command[i];
			if (cc == '*') {
				result = num1 * num2;
			} else if (cc == '/') {
				result = num1 / num2;
			}
			num[i + 1] = String.valueOf(result);
		}
		return String.valueOf(result);
	}

	/*
	 *  第三层级 ^ 运算
	 */
	private static String calcLevel3(String str) {
		StringBuffer sb = new StringBuffer(str);
		int commandCount = 0;// 符号数量

		int j = 0;// 计数器
		// 计算有多少个运算符,就有n+1个数字
		for (j = 0; j < sb.length(); j++) {
			if (sb.charAt(j) == '^')
				commandCount++;
		}

		// 初始化数字数组(用字符串表示)
		String[] num = new String[commandCount + 1];
		for (j = 0; j < num.length; j++) {
			num[j] = "";
		}

		// 遍历一遍,吧每个数字存进数字数组,^符号存进符号数组
		int k = 0;
		for (j = 0; j < sb.length(); j++) {
			if (sb.charAt(j) == '^') {
				k++;
				continue;
			}
			num[k] += sb.charAt(j);
		}
		for (int i = 0; i < num.length; i++) {
			if (num[i].contains("cos") || num[i].contains("sin")|| num[i].contains("tan") || num[i].contains("log") || num[i].contains("ln")
					|| num[i].contains("!") || num[i].contains("√")) {
				num[i] = calcLevel4(num[i]);
			}
		}
		// 如果只包含一个数 返回这个数的值
		if (num.length == 1) {
			return num[0];
		}
		double result = 1;
		for (int i = 1; i < num.length; i++) {
			result *= Double.parseDouble(num[i]);
		}
		result = Math.pow(Double.parseDouble(num[0]), result);
		return String.valueOf(result);
	}

	/*
	 *  第四层级 cos sin ! √ 运算
	 *  若 嵌套使用建议采用 () 
	 */
	private static String calcLevel4(String str) {
		StringBuffer sb = new StringBuffer(str);
		String num = "";
		for (int i = 0; i < sb.length(); i++) {
			if (sb.charAt(i) <= '9' && sb.charAt(i) >= '0' || sb.charAt(i) == '.') {
				num += sb.charAt(i);
			}
		}
		if (str.contains("!")) {
			try {
				num = String.valueOf(factorial(Integer.parseInt(num)));
			} catch (NumberFormatException e) {
				e.printStackTrace();
			}
		}
		if (str.contains("√")) {
			try {
				num = String.valueOf(Math.sqrt(Double.parseDouble(num)));
			} catch (NumberFormatException e) {
				e.printStackTrace();
			}
		}
		if (str.contains("cos")) {
			try {
				num = String.valueOf(Math.cos(Double.parseDouble(num)));
			} catch (NumberFormatException e) {
				e.printStackTrace();
			}
		}
		if (str.contains("sin")) {
			try {
				num = String.valueOf(Math.sin(Double.parseDouble(num)));
			} catch (NumberFormatException e) {
				e.printStackTrace();
			}
		}
		if (str.contains("tan")) {
			try {
				num = String.valueOf(Math.tan(Double.parseDouble(num)));
			} catch (NumberFormatException e) {
				e.printStackTrace();
			}
		}
		if (str.contains("log")) {
			try {
				num = String.valueOf(Math.log10(Double.parseDouble(num)));
			} catch (NumberFormatException e) {
				e.printStackTrace();
			}
		}
		if (str.contains("ln")) {
			try {
				num = String.valueOf(Math.log(Double.parseDouble(num)));
			} catch (NumberFormatException e) {
				e.printStackTrace();
			}
		}
		return num;
	}

	// 求n的阶乘 n!
	public static int factorial(int n) {
		if (n == 0) {
			return 1;
		}
		int num = n;
		for (int i = n; i > 1; i--) {
			num *= (i - 1);
		}
		return num;
	}
}

testMathUtils.java文件:对算术表达式的测试。(这个就不发了。嘿嘿!)

Main.java文件:运行主函数的类

package com.zhao.calc.test;

import com.zhao.calc.frame.CalculatorFrame;

public class Main {
	public static void main(String[] args) {
		new CalculatorFrame();
	}
}

没有进行错误的一些处理,有什么问题随时欢迎评论。