欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JavaGUI实现科学计算器

程序员文章站 2024-02-27 13:37:15
...

JavaGUI实现科学计算器

一、设计思想

  1. 界面及布局

    JavaGUI实现科学计算器

  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

二、算法实现

项目文件结构:

JavaGUI实现科学计算器

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();
	}
}

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

相关标签: GUI 计算器