模擬windows10計算器的實現
- 2021 年 7 月 4 日
- 筆記
用戶介面部分:
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.HashMap;
import java.util.Vector;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.table.*;
public class caculate extends JFrame implements ActionListener,MouseListener {
JTextField contain1,contain2;//內容顯示區域
String midstring="";//用於需要計算表達式的更新
JComboBox sanjiao,hanshu;//三角學,函數下拉框
String resul[] =new String[100]; //存儲用戶點擊的命令
int resulkey=0; //計數
String data[]=new String[100]; //存儲按鈕的內容
int data1[]=new int[] {16,17,18,21,22,23,26,27,28,31,32,33}; //要切換的按鈕的位置
HashMap<String,String> map = new HashMap<>(); //存儲命令的鍵值對
JButton pan1Button[]=new JButton[6]; //panel1按鈕組
JButton pan2Button[]=new JButton[6]; //panel2按鈕組
JButton pan3Button[]=new JButton[6];
static JButton button[]=new JButton[35];
Color color;
Color color1=new Color(240,240,240);
Color color2=new Color(230,230,230);
Color color3=new Color(150,200,255);
public static void main(String[] args) {
// TODO Auto-generated method stub
caculate cacu=new caculate();
cacu.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
cacu.setSize(340,545);
cacu.setVisible(true);
}
public caculate() {
super("計算器");
this.setBackground(color1);
setLocationRelativeTo(getOwner());
setLayout(new GridBagLayout());
setMenuBar(change());
map.put("+","+");
map.put("-","-");
map.put("*","*");
map.put("/","/");
map.put("(","(");
map.put(")",")");
map.put("x^2","^");
map.put("x^3","^");
map.put("1/x","^");
map.put("e^x","^");
map.put("√x","^");
map.put("x^y","^");
map.put("10^x","^");
map.put("∛x","^");
map.put("√(y&x)","^");
map.put("2^x","^");
map.put("n!","#");
map.put("|x|","a");
map.put("exp","e");
map.put("mod","%");
map.put("log_yx","l");
map.put("log","l");
map.put("ln","l");
map.put("+/-","~");
map.put("sin","s");
map.put("sin^-1","S");
map.put("sinh","h");
map.put("cos","c");
map.put("cos^-1","C");
map.put("cosh","H");
map.put("tan","t");
map.put("tan^-1","T");
map.put("tanh","N");
map.put("rand","r");
map.put("ceil","q");
map.put("floor","f");
map.put("pi","p");
map.put("e","E");
map.put(".", ".");
contain1=new JTextField(10);
contain1.setBorder(BorderFactory.createEmptyBorder());
contain1.setHorizontalAlignment(JTextField.RIGHT);
contain1.setEditable(false);
contain1.setBackground(color1);
contain2=new JTextField(10);
contain2.setText("0");
contain2.setBorder(BorderFactory.createEmptyBorder());
contain2.setHorizontalAlignment(JTextField.RIGHT);
contain2.setBackground(color1);
contain2.setFont(new Font("楷體",Font.BOLD,32));
GridBagConstraints gridBag=new GridBagConstraints();
gridBag.fill=GridBagConstraints.BOTH;
gridBag.weightx=100;
gridBag.weighty=10;
addToBag(contain1,gridBag, 0,0,1,1);
addToBag(contain2,gridBag, 0,1,1,1);
gridBag.weightx=100;
gridBag.weighty=0;
JPanel pan1=new JPanel();
JPanel pan2=new JPanel();
JPanel pan3=new JPanel();
pan1.setBackground(color1);
pan1.setLayout(new GridLayout(1,6,0,0));
pan2.setBackground(color1);
pan2.setLayout(new GridLayout(1,6,0,0));
pan3.setBackground(color1);
pan3.setLayout(new GridLayout(1,6,0,0));
addToBag(pan1,gridBag,0,2,1,1);
addToBag(pan2,gridBag,0,3,1,1);
addToBag(pan3,gridBag,0,4,1,1);
String[] san= {"三角學","sin","cos","tan","sin^-1","cos^-1","tan^-1","sinh","cosh","tanh"};
sanjiao=detCbB(san);
pan3.add(sanjiao);
String[] han= {"函數","ceil","floor","rand"};
hanshu=detCbB(han);
pan3.add(hanshu);
JPanel pan=new JPanel();
pan.setBackground(color1);
pan.setLayout(new GridLayout(7,5,0,0));
gridBag.weightx=100;
gridBag.weighty=100;
addToBag(pan,gridBag,0,5,1,1);
getkey(data); //從文件中讀取按鈕數據
Initpan(data,pan);//初始化pan面板
Initpan1(data,pan1);//初始化pan1面板
Initpan2(data,pan2);//初始化pan2面板
}
void Initpan(String[] data,JPanel pan) {
int j=0;
for(int i=0;i<35;i++)
{
button[i]=new JButton(data[j++]);
button[i].setBackground(color1);
button[i].setBorder(BorderFactory.createMatteBorder(1, 1, 1, 1, color2));
pan.add(button[i]);
button[i].addActionListener(this);
button[i].addMouseListener(this);
}
for(int x:data1) {
button[x].setBackground(Color.white);
}
button[34].setBackground(color3);
}
void Initpan1(String[] data ,JPanel pan1) {
int j=41;
for(int i=0;i<5;i++) {
if(i<2) {
pan1Button[i]=new JButton(data[j++]);
pan1Button[i].addActionListener(this);
pan1Button[i].addMouseListener(this);
}
else
{
pan1Button[i]=new JButton(" ");
}
pan1Button[i].setBackground(color1);
pan1Button[i].setBorderPainted(false);
pan1.add(pan1Button[i]);
}
}
void Initpan2(String[] data,JPanel pan2) {
int j=43;
for(int i=0;i<6;i++) {
pan2Button[i]=new JButton(data[j++]);
pan2Button[i].setBackground(color1);
pan2Button[i].setBorderPainted(false);
pan2.add(pan2Button[i]);
if(i<2||i==5) {
pan2Button[i].setEnabled(false);
}
else
{
pan2Button[i].addActionListener(this);
pan2Button[i].addMouseListener(this);
}
}
}
void addToBag(Component c,GridBagConstraints gbc, int x,int y,int w,int h) {
gbc.gridx=x;
gbc.gridy=y;
gbc.gridheight=h;
gbc.gridwidth=w;
add(c,gbc);
}
//從文件中讀取數據
public void getkey(String[] param) {
try {
File file=new File("text.txt");
BufferedReader in=new BufferedReader(new InputStreamReader(new FileInputStream(file),"UTF8"));
boolean eof=false;
int flag=0;
while(!eof) {
String x=in.readLine();
if(x==null) {
eof=true;
}
else {
param[flag++]=x;
}
}
}
catch(IOException e) {}
}
//創建下拉組合框
public JComboBox detCbB(String[] Ordata) {
JComboBox example=new JComboBox(Ordata);
example.setBackground(color1);
example.setBorder(null);
//example.setForeground(color);
example.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
// TODO Auto-generated method stub
if(e.getStateChange()==ItemEvent.SELECTED) {
if(midstring.equals("=")) {
contain1.setText("");
midstring="";
}
if(e.getStateChange()==ItemEvent.DESELECTED) {
}
int k=example.getSelectedIndex();
if(Ordata[k]=="三角學"||Ordata[k]=="函數") {
}
else {
resul[resulkey++]=Ordata[k];
midstring+=Ordata[k];
contain1.setText(midstring);
}
}
}
});
return example;
}
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
String command=e.getActionCommand();
sanjiao.setSelectedIndex(0);
hanshu.setSelectedIndex(0);
if(midstring.equals("=")) {
contain1.setText("");
midstring="";
}
if(command.equals("2nd")) {
JButton butt=(JButton)e.getSource();
if(butt.getBackground()==color3) {
restoreButton();
butt.setBackground(color1);
color=color1;
}
else {
changeButton();
butt.setBackground(color3);
color=color3;
}
}
else
{
if(command.equals("=")) {
String result=changeType(resul);
System.out.println(result);
System.out.println(resulkey);
System.out.println(Cauculate.midtolast(result));
Double result1=Cauculate.CaculateLastStackExpression(Cauculate.midtolast(result));
contain2.setText(Double.toString(result1));
midstring="=";
resulkey=0;
}
else
{
if(command.equals("c"))//清除單個命令
{
if(midstring.length()>0)
{
int len=resul[resulkey-1].length();//獲取上一個命令的長度
midstring=midstring.substring(0, midstring.length()-len); //有問題
resulkey--;
}
command="";
}
if(command.equals("×")) //清除所有的命令
{
midstring="";
command="";
resulkey=0;
}
resul[resulkey++]=command;
midstring+=command;
if(command=="") {//糾正計數問題
resulkey--;
}
contain1.setText(midstring);
if(command.charAt(0)>'0'&&command.charAt(0)<'9')
{
contain2.setText(command);
}
}
}
}
private String changeType(String[] resul2) {
// TODO Auto-generated method stub
String ch="";
for(int i=0;i<resulkey;i++) {
if(!isNumber(resul2[i])) {
switch (resul2[i]) {
case "x^2":
ch+=map.get(resul2[i])+"2";
break;
case "x^3":
ch+=map.get(resul2[i])+"3";
break;
case "1/x":
ch+=map.get(resul2[i])+"(0-1)";
break;
case "e^x":
ch+='E'+map.get(resul2[i]);
break;
case "√x":
ch+=map.get(resul2[i])+"(1/2)";
break;
case "x^y":
ch+=resul2[i+1]+map.get(resul2[i])+resul2[i+2];
i+=2;
break;
case "10^x":
ch+="10"+map.get(resul2[i]);
break;
case "∛x":
ch+=map.get(resul2[i])+"(1/3)";
break;
case "√(y&x)":
ch+=resul2[i+1]+map.get(resul2[i])+(1/(Double.parseDouble(resul2[i+2])));
i+=2;
break;
case "log_yx":
ch+=resul2[i+1]+map.get(resul2[i])+resul2[i+2];
i+=2;
break;
case "log":
ch+="10"+map.get(resul2[i]);
break;
case "ln":
ch+="E"+map.get(resul2[i]);
break;
default:
ch+=map.get(resul2[i]);
break;
}
}
else {
ch+=resul2[i];
}
}
return ch;
}
public static boolean isNumber(String str) {
for(int i=0;i<str.length();i++) {
if(!Character.isDigit(str.charAt(i)))
{
return false;
}
}
return true;
}
private MenuBar change() {
MenuBar jmenubar=new MenuBar();
jmenubar.addNotify();
Menu ch=new Menu("==");
jmenubar.add(ch);
MenuItem item1=new MenuItem("Science");
ch.add(item1);
MenuItem item2=new MenuItem("繪圖");
ch.add(item2);
MenuItem item3=new MenuItem("標準");
ch.add(item3);
MenuItem item4=new MenuItem("程式設計師");
ch.add(item4);
Menu type=new Menu("Science");
jmenubar.add(type);
return jmenubar;
}
//按2nd改變按鈕
public void changeButton() {
int k=5;
for(int i=35;i<41;i++) {
button[k].setText(data[i]);
k+=5;
}
}
//按2nd復原按鈕
public void restoreButton() {
int k=5;
for(int i=35;i<41;i++) {
button[k].setText(data[k]);
k+=5;
}
}
@Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
if(e.getComponent().getClass().equals(button[0].getClass())) {
color=((JButton)e.getSource()).getBackground();
((JButton)e.getSource()).setBackground(new Color(220,220,220));
}
}
@Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
if(e.getComponent().getClass().equals(button[0].getClass())) {
((JButton)e.getSource()).setBackground(color);
}
}
}
表達式計算部分:
基本原理
將獲得的表達式由中綴轉化為後綴,利用java的棧進行相應的運算。
package tttt;
import java.util.*;
public class Cauculate {
//創建用於匹配運算符的字元數組
private static char[] trans1= {'+','-','*','/','#','^','a','e','%','l','~','s','S','h','H','c','C','t','T','N','r','q','f'};//總數組
private static char[] trans2= {'+','-','*','/','^','e','%','l'};//單目運算符
private static char[] trans3= {'a','#','~','s','S','h','H','c','C','t','T','N','q','f'};//雙目運算符
public static int transExp(char exp) {//運算符優先順序
int re = 0;
switch (exp) {
case '*':
case '/':
re = 2;
break;
case '+':
case '-':
re = 1;
break;
case '^':
re = 4;
break;
case '#':
case 'l':
case '~':
case 'e':
case 's':
case 'S':
case 'h':
case 'c':
case 'C':
case 'H':
case 't':
case 'T':
case 'N':
case 'a':
case 'q':
case 'f':
case 'r':
case '%':
re=3;
break;
}
return re;
}
public static String midtolast(String mid){//中綴表達式轉後綴表達式
Stack<Character>OperateorStack=new Stack<Character>();
Stack<String>LastStack=new Stack<String>();//後綴表達式棧;
int length=mid.length();
int index=0;//指向String掃描的當前位置;
char element;//
String num="";//
while(index<length){//掃描整個mid
element=mid.charAt(index);
if(element>='0'&&element<='9'){//得到一整個數據,例如'123'
num=num+element;
if(index==length-1) {
LastStack.push(num);
}
else {
char ch=mid.charAt(index+1);
if(ch=='.') {
num+=ch;
index++;
}
else
{
if(ch<'0'||ch>'9') {
LastStack.push(num);
num="";
}
}
}
}
else if(element=='E') {
LastStack.push(Double.toString(Math.E));
}
else if(element=='p') {
LastStack.push(Double.toString(Math.PI));
}
else if(element=='('){
OperateorStack.push(element);
}
else if(element==')'){
while(OperateorStack.peek()!='('){
LastStack.push(OperateorStack.pop().toString());//將左括弧到右括弧之間的操作符彈出
}
OperateorStack.pop();//讓左括弧出棧
}
else if(castele(element,trans1)){
if(OperateorStack.isEmpty()||OperateorStack.peek()=='('){//棧為空或棧頂元素為'('則直接入棧
OperateorStack.push(element);
}
else if(transExp(element)>transExp(OperateorStack.peek())){
OperateorStack.push(element);
}//如果element的優先順序高於棧頂元素則直接入棧
else if(transExp(element)<=transExp(OperateorStack.peek())){
while(!OperateorStack.isEmpty()&&OperateorStack.peek()!='('){
LastStack.push(OperateorStack.peek().toString());
OperateorStack.pop();
if(!OperateorStack.isEmpty()&&transExp(element)<=transExp(OperateorStack.peek())) {
continue;
}
else {
break;
}
}
OperateorStack.push(element);
}//如果element的優先順序低於或等於棧頂元素等於棧頂元素則將棧頂元素加入後綴表達棧中
}
index++;
}
while(!OperateorStack.isEmpty()){
LastStack.push(OperateorStack.pop().toString());
}
String LastStackExpression=LastStack.pop();
while(!LastStack.isEmpty()){
LastStackExpression=LastStack.pop()+" "+LastStackExpression;
}
return LastStackExpression;
}
public static double CaculateLastStackExpression(String LastStackExpression){
Stack<Double>operandStack=new Stack<Double>();//初始化一個操作數棧
String[] elements=LastStackExpression.split(" ");//將LastStackExpression以空格分隔開;
String element=null;//後綴表達式掃描到的單元;
char elementHead;
double operand=0,operand1=0,operand2=0;
for (int i = 0; i < elements.length; i++) {//依次掃描後綴表達式的單元
element=elements[i];
elementHead=element.charAt(0);
if (elementHead>='0'&&elementHead<='9') {//如果掃描到的是操作數串,將其轉換為double數據,並壓入操作數棧
operand=Double.parseDouble(element);
operandStack.push(operand);
}else if(castele(elementHead,trans2)){//如果掃描到的是運算符
operand1=operandStack.pop();//取操作數棧的棧頂
operand2=operandStack.pop();//取操作數棧的棧頂
operand=caculateResult(operand1,operand2,elementHead);//進行運算,得出返回結果
operandStack.push(operand);//將結果壓入操作數棧
}
else if(castele(elementHead,trans3)) {
operand1=operandStack.pop();
operand=caculateResult(operand1,0.0,elementHead);
operandStack.push(operand);
}
else if (elementHead=='r') {
operand=caculateResult(0.0,0.0,elementHead);
operandStack.push(operand);
}
}
return operandStack.pop() ;
}
public static double caculateResult(double operand1,double operand2,char operator){//返回的運算結果
double result=0;
switch (operator) {
case '+':
result=operand1+operand2;
break;
case '-':
result=operand2-operand1;
break;
case '*':
result=operand1*operand2;
break;
case '/':
result=operand2/operand1;
break;
case '^':
result=ScientificCalculator.Pow2(operand2,operand1);
break;
case '#':
result=ScientificCalculator.Factorial((int)operand1);
break;
case 'l':
result=ScientificCalculator.Log(operand2,operand1);
break;
case '~':
result=ScientificCalculator.Reverse(operand1);
break;
case 'e':
result=ScientificCalculator.Exp(operand2,(int)operand1);
break;
case 's':
result=ScientificCalculator.Sin(operand1,1);
break;
case 'S':
result=ScientificCalculator.Sin(operand1,2);
break;
case 'h':
result=ScientificCalculator.Sin(operand1,3);
break;
case 'c':
result=ScientificCalculator.Cos(operand1,1);
break;
case 'C':
result=ScientificCalculator.Cos(operand1,2);
break;
case 'H':
result=ScientificCalculator.Cos(operand1,3);
break;
case 't':
result=ScientificCalculator.Tan(operand1,1);
break;
case 'T':
result=ScientificCalculator.Tan(operand1,2);
break;
case 'N':
result=ScientificCalculator.Tan(operand1,3);
break;
case 'a':
result=ScientificCalculator.abs(operand1);
break;
case 'q':
result=ScientificCalculator.ceil(operand1);
break;
case 'f':
result=ScientificCalculator.floor(operand1);
break;
case 'r':
result=ScientificCalculator.rand();
break;
case '%':
result=ScientificCalculator.Mod(operand2,operand1);
break;
default:
break;
}
return result;
}
//判斷符號
public static boolean castele(char element,char[] Su) {
for(char x:Su) {
if(element==x)
return true;
}
return false;
}
}
單個函數部分:
單個按鈕功能的實現。
package tttt;
import java.lang.Math;
import java.util.HashMap;
import java.util.Map;
public class ScientificCalculator {
// 指數運算:x^2,1/x,e^x,平方根 " ^ "
static public double Pow2(double x,double n)
{
return Math.pow(x,n);
}
// 階乘運算: " # "
static public int Factorial(int x)
{
if (x <= 0)
{
throw new IllegalArgumentException("需要計算的參數必須為正數!");//拋出不合理參數異常
}
if (x == 1)
{
return 1;//跳出循環
}
else
{
return x * Factorial(x - 1);//遞歸
}
}
// 對數運算:log,ln 「 l 」
static public double Log(double base,double value)
{
return Math.log(value) / Math.log(base);
}
static public double Mod(double x,double y)
{
return x%y;
}
// 取反運算:+/- " ~ "
static public double Reverse(double x)
{
return -x;
}
// 科學計數法:x*e^n "e"
static public double Exp(double x,int n)
{
return x * Math.pow(10,n);
}
// sin、sin^-1(asin)、sinh、sinh^-1(asinh)
// 運算: degree:度數; sin:flag=1 " s "; sin^-1(asin):flag=2 " S "; sinh:flag=3 " h "
static public double Sin(double degree,int flag)
{
double radians = Math.toRadians(degree);
switch (flag)
{
case 1:
return Math.sin(radians);
case 2:
return Math.asin(radians);
case 3:
return Math.sinh(degree);
default:
throw new IllegalStateException("Unexpected value: " + flag);
}
}
// cos、cos^-1(acos)、cosh
// 運算: degree:度數; cos:flag=1 " c "; cos^-1(acos):flag=2 " C "; cosh:flag=3 " H "
static public double Cos(double degree,int flag)
{
double radians = Math.toRadians(degree);
switch (flag)
{
case 1:
return Math.cos(radians);
case 2:
return Math.acos(radians);
case 3:
return Math.cosh(degree);
default:
throw new IllegalStateException("Unexpected value: " + flag);
}
}
// tan、tan^-1(atan)、tanh
// 運算: degree:度數; tan:flag=1 " t "; tan^-1(atan):flag=2 " T "; tanh:fla g=3 " N "
static public double Tan(double degree,int flag)
{
double radians = Math.toRadians(degree);
switch (flag)
{
case 1:
return Math.tan(radians);
case 2:
return Math.atan(radians);
case 3:
return Math.tanh(degree);
default:
throw new IllegalStateException("Unexpected value: " + flag);
}
}
// 絕對值:|x| " a "
static public double abs(double x)
{
return Math.abs(x);
}
// 向上取整:ceil " q "
static public double ceil(double x)
{
return Math.ceil(x);
}
// 向下取整:floor " f "
static public double floor(double x)
{
return Math.floor(x);
}
// 取隨機數:rand " r "
static public double rand()
{
return Math.random();
}
public static void main(String[] args)
{
System.out.println(Exp(Math.PI,1));
}
}