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