本博客鏈接:
https://blog.csdn.net/weixin_50301255/article/details/110731387
本文用Java的swing來實作一個簡單計算器,主要內容為圖形用戶界面GUI的實作以及運算運算式核心演算法的設計撰寫,
程式運行環境為Windows10 ,編譯環境為MyEclipse ,
一、具體功能:
1、:輸入,輸出
輸入:允許輸入帶有括號的完整計算式(例 8*(4-95)+5÷2*e-pi)
輸出:輸出Double型別的結果
輸出:整個運算運算式并保存于歷史記錄中
2、:功能
基本的加,減,乘,除,四則運算
平方運算
開方運算
求余運算
最終界面如下圖:

除了常規的數字按鈕和運算子,還有兩個常數e,pi(π),清空鍵AC,括號運算子(),平方(x^x)和開方(sqrt)運算子,輸入顯示框以及歷史記錄文本框,文本框的垂直滾動條和水平滾動條,
二、主要思想:
1:中綴運算式轉為后綴運算式
準備:
①后綴運算式佇列:postQueue,用于存盤逆波蘭運算式(其實不用佇列排序直接輸出也行)
②運算子堆疊:opStack,對用戶輸入的運算子進行處理,用于存盤運算子
演算法思想:
從左向右依次讀取算術運算式的元素X,分以下情況進行不同的處理:
(1)如果X是運算元,直接入隊
(2)如果X是運算子,再分以下情況:
a)如果堆疊為空,直接入堆疊,
b)如果X==”(“,直接入堆疊,
c)如果X==”)“,則將堆疊里的元素逐個出堆疊,并入隊到后綴運算式佇列中,直到第一個配對的”(”出堆疊,(注:“(”和“)”都不 入隊)
d)如果是其他運算子(+ - * /),則和堆疊頂元素進行比較優先級, 如果堆疊頂元素的優先級大于等于X,則出堆疊并把堆疊中彈出的元素入隊,直到堆疊頂元素的優先級小于X或者堆疊為空,彈出完這些元素后,才將遇到的運算子壓入到堆疊中,
(3)最后將堆疊中剩余的運算子全部入隊,
示意圖:

2、計算后綴運算式
準備:
需要用到一個結果堆疊Res_Stack :用于存放計算的中間程序的值和最終結果
演算法思想:
1、從左開始向右遍歷后綴運算式的元素,
2、如果取到的元素是運算元,直接入堆疊Res_Stack,如果是運算子,從堆疊中彈出2個數進行運算,然后把運算結果入堆疊
3、當遍歷完后綴運算式時,計算結果就保存在堆疊里了,
示意圖:

三、結果測驗

分析:
1、可實作基本四則運算及平方、開方、求余運算,
2、運算運算式可顯示于輸入界面并保存于歷史記錄欄
3、輸入界面和歷史記錄欄皆可實作不斷字自動換行功能以及滾動條功能
4、不足之處:進行平方和開方運算時其保存在歷史記錄中的運算式會出現兩個等號及兩個結果,
四、完整源代碼(每行代碼已附有詳細注釋)
package software;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
//Calculator類,繼承JFrame框架,實作事件監聽器介面
public class Calculator extends JFrame implements ActionListener {
private String[] KEYS = { "7", "8", "9", "AC", "4", "5", "6", "-", "1", "2", "3", "+", "0", "e", "pi", "/", "sqrt",
"%", "x*x", "*", "(", ")", ".", "=" };
private JButton keys[] = new JButton[KEYS.length];
private JTextArea resultText = new JTextArea("0.0");// 文本域組件TextArea可容納多行文本;文本框內容初始值設為0.0
private JTextArea History = new JTextArea();// 歷史記錄文本框初始值設為空
private JPanel jp1=new JPanel();
private JPanel jp2=new JPanel();
private JScrollPane gdt1=new JScrollPane(resultText);//給輸入顯示屏文本域新建一個垂直滾動滑條
private JScrollPane gdt2=new JScrollPane(History);//給歷史記錄文本域新建一個垂直滾動滑條
// private JScrollPane gdt3=new JScrollPane(History);//給歷史記錄文本域新建一個水平滾動滑條
private JLabel label = new JLabel("歷史記錄");
private String b = "";
// 構造方法
public Calculator() {
super("Caculator");//“超”關鍵字,表示呼叫父類的建構式,
resultText.setBounds(20, 18, 255, 115);// 設定文本框大小
resultText.setAlignmentX(RIGHT_ALIGNMENT);// 文本框內容右對齊
resultText.setEditable(false);// 文本框不允許修改結果
History.setBounds(290, 40, 250,370);// 設定文本框大小
History.setAlignmentX(LEFT_ALIGNMENT);// 文本框內容右對齊
History.setEditable(false);// 文本框不允許修改結果
label.setBounds(300, 15, 100, 20);//設定標簽位置及大小
jp2.setBounds(290,40,250,370);//設定面板視窗位置及大小
jp2.setLayout(new GridLayout());
jp1.setBounds(20,18,255,115);//設定面板視窗位置及大小
jp1.setLayout(new GridLayout());
resultText.setLineWrap(true);// 激活自動換行功能
resultText.setWrapStyleWord(true);// 激活斷行不斷字功能
resultText.setSelectedTextColor(Color.RED);
History.setLineWrap(true);//自動換行
History.setWrapStyleWord(true);
History.setSelectedTextColor(Color.blue);
gdt1.setViewportView(resultText);//使滾動條顯示出來
gdt2.setViewportView(History);
gdt1.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);//設定讓垂直滾動條一直顯示
gdt2.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);//設定讓垂直滾動條一直顯示
gdt2.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);//設定讓水平滾動條一直顯示
jp1.add(gdt1);//將滾動條添加入面板視窗中
jp2.add(gdt2);
this.add(jp1);//將面板添加到總表單中
this.add(jp2);//將面板添加到總表單中
this.setLayout(null);
this.add(label);// 新建“歷史記錄”標簽
//this.add(resultText);// 新建文本框,該陳述句會添加進去一個新的JTextArea導致帶有滾動條的文本無法顯示或者發生覆寫
//this.add(History);// 新建歷史記錄文本框,該陳述句會添加進去一個新的JTextArea導致帶有滾動條的文本無法顯示
// 放置按鈕
int x = 20, y = 150;
for (int i = 0; i < KEYS.length; i++)
{
keys[i] = new JButton();
keys[i].setText(KEYS[i]);
keys[i].setBounds(x, y, 60, 40);
if (x < 215) {
x += 65;
} else {
x = 20;
y += 45;
}
this.add(keys[i]);
}
for (int i = 0; i < KEYS.length; i++)// 每個按鈕都注冊事件監聽器
{
keys[i].addActionListener(this);
}
this.setResizable(false);
this.setBounds(500, 200, 567, 480);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
}
// 事件處理
public void actionPerformed(ActionEvent e)
{
//History.setText(b);//使輸入的運算式顯示在歷史記錄文本框中
String label=e.getActionCommand();//獲得事件源的標簽
if(label=="=")//
{
resultText.setText(this.b);
History.setText(History.getText()+resultText.getText());
if(label=="=")//呼叫計算方法,得出最終結果
{
String s[]=houzhui(this.b);
String result=Result(s);
this.b=result+"";
//更新文本框,當前結果在字串b中,并未洗掉,下一次輸入接著此結果以實作連續運算
resultText.setText(this.b);
History.setText(History.getText()+"="+resultText.getText()+"\n");
}
}
else if(label=="AC")//清空按鈕,消除顯示屏文本框前面所有的輸入和結果
{
this.b="";
resultText.setText("0");//更新文本域的顯示,顯示初始值;
}
else if(label=="sqrt")
{
String n=kfys(this.b);
resultText.setText("sqrt"+"("+this.b+")"+"="+n);//使運算運算式顯示在輸入界面
History.setText(History.getText()+"sqrt"+"("+this.b+")"+"=");//獲取輸入界面的運算運算式并使其顯示在歷史記錄文本框
this.b=n;
}
else if(label=="x*x")
{
String m=pfys(this.b);
resultText.setText(this.b+"^2"+"="+m);//使運算運算式顯示在輸入界面
History.setText(History.getText()+this.b+"^2"+"=");//獲取輸入界面的運算運算式并使其顯示在歷史記錄文本框
this.b=m;
}
else if(label=="e"||label=="pi")
{
if(label=="e")
{
String m=String.valueOf(2.71828);//將e的值以字串的形式傳給m
this.b=this.b+m;//保留顯示m之前輸入的運算子或數字字符繼續下一步運算
resultText.setText(this.b);
// History.setText(History.getText()+this.b);
}
if(label=="pi")
{
String m=String.valueOf(3.14159265);
this.b=this.b+m;
resultText.setText(this.b);
// History.setText(History.getText()+this.b);
}
}
else
{
this.b=this.b+label;
resultText.setText(this.b);
// History.setText(History.getText()+this.b);
}
//History.setText(History.getText()+this.b);//使輸入的運算式顯示在歷史記錄文本框中
}
//將中綴運算式轉換為后綴運算式
private String[] houzhui(String str) {
String s = "";// 用于承接多位數的字串
char opStack[] = new char[100];// 靜態堆疊,對用戶輸入的運算子進行處理,用于存盤運算子
String postQueue[] = new String[100];// 后綴運算式字串陣列,為了將多位數存盤為獨立的字串
int top = -1, j = 0;// 靜態指標top,控制變數j
for (int i = 0; i < str.length(); i++)// 遍歷中綴運算式
// indexof函式,回傳字串首次出現的位置;charAt函式回傳index位置處的字符;
{
if ("0123456789.".indexOf(str.charAt(i)) >= 0) // 遇到數字字符的情況
{
s = "";// 作為承接字符,每次開始時都要清空
for (; i < str.length() && "0123456789.".indexOf(str.charAt(i)) >= 0; i++) {
s = s + str.charAt(i);
}
i--;
postQueue[j] = s;// 數字字符直接加入后綴運算式
j++;
} else if ("(".indexOf(str.charAt(i)) >= 0) {// 遇到左括號
top++;
opStack[top] = str.charAt(i);// 左括號入堆疊
} else if (")".indexOf(str.charAt(i)) >= 0) {// 遇到右括號
for (;;)// 堆疊頂元素回圈出堆疊,直到遇到左括號為止
{
if (opStack[top] != '(') {// 堆疊頂元素不是左括號
postQueue[j] = opStack[top] + "";// 堆疊頂元素出堆疊
j++;
top--;
} else { // 找到堆疊頂元素是左括號
top--;// 洗掉堆疊頂左括號
break;// 回圈結束
}
}
}
if ("*%/".indexOf(str.charAt(i)) >= 0)// 遇到高優先級運算子
{
if (top == -1) {// 若堆疊為空則直接入堆疊
top++;
opStack[top] = str.charAt(i);
} else {// 堆疊不為空,把堆疊中彈出的元素入隊,直到堆疊頂元素優先級小于x或者堆疊為空
if ("*%/".indexOf(opStack[top]) >= 0) {
// 堆疊頂元素也為高優先級運算子
postQueue[j] = opStack[top] + "";// 堆疊頂元素出堆疊進入后綴運算式
j++;
opStack[top] = str.charAt(i);// 當前運算子入堆疊
} else if ("(".indexOf(opStack[top]) >= 0) {// 堆疊頂元素為左括號,當前運算子入堆疊
top++;
opStack[top] = str.charAt(i);
} else if ("+-".indexOf(str.charAt(i)) >= 0) {// 遇到低優先級運算子
postQueue[j] = opStack[top] + "";// 堆疊頂元素出堆疊進入后最運算式
j++;
opStack[top] = str.charAt(i);// 當前元素入堆疊
}
}
} else if ("+-".indexOf(str.charAt(i)) >= 0) {
if (top == -1) {
top++;
opStack[top] = str.charAt(i);
} else {
if ("*%/".indexOf(opStack[top]) >= 0) {
// 堆疊頂元素也為高優先級運算子
postQueue[j] = opStack[top] + "";// 堆疊頂元素出堆疊進入后綴運算式
j++;
opStack[top] = str.charAt(i);// 當前運算子入堆疊
} else if ("(".indexOf(opStack[top]) >= 0) {// 堆疊頂元素為左括號,當前運算子入堆疊
top++;
opStack[top] = str.charAt(i);
} else if ("+-".indexOf(str.charAt(i)) >= 0) {// 遇到低優先級運算子
postQueue[j] = opStack[top] + "";// 堆疊頂元素出堆疊進入后最運算式
j++;
opStack[top] = str.charAt(i);// 當前元素入堆疊
}
}
}
}
for (; top != -1;) {// 遍歷結束后將堆疊中剩余元素依次出堆疊進入后綴運算式
postQueue[j] = opStack[top] + "";
j++;
top--;
}
return postQueue;
}
//開方運算方法
public String kfys(String str) {
String result = "";
double a = Double.parseDouble(str), b = 0;
b = Math.sqrt(a);
result = String.valueOf(b);//將運算結果轉換為string型別并賦給string型別的變數result
return result;
}
//平方運算方法
public String pfys(String str) {
String result = "";
double a = Double.parseDouble(str), b = 0;
b = Math.pow(a, 2);
result = String.valueOf(b);
return result;
}
// 計算后綴運算式,并回傳最終結果
public String Result(String str[]) {
String Result[] = new String[100];// 順序存盤的堆疊,資料型別為字串
int Top = -1;// 靜態指標Top
for (int i = 0; str[i] != null; i++) {
if ("+-*%/".indexOf(str[i]) < 0) {
Top++;
Result[Top] = str[i];
}
if ("+-*%/".indexOf(str[i]) >= 0)// 遇到運算子字符,將堆疊頂兩個元素出堆疊計算并將結果回傳堆疊頂
{
double x, y, n;
x = Double.parseDouble(Result[Top]);// 順序出堆疊兩個數字字串,并轉換為double型別
Top--;
y = Double.parseDouble(Result[Top]);
Top--;
if ("-".indexOf(str[i]) >= 0) {
n = y - x;
Top++;
Result[Top] = String.valueOf(n);// 將運算結果重新入堆疊
}
if ("+".indexOf(str[i]) >= 0) {
n = y + x;
Top++;
Result[Top] = String.valueOf(n);// 將運算結果重新入堆疊
}
if ("*".indexOf(str[i]) >= 0) {
n = y * x;
Top++;
Result[Top] = String.valueOf(n);// 將運算結果重新入堆疊
}
if ("/".indexOf(str[i]) >= 0)
{
if (x == 0)// 被除數不允許為0
{
String s = "error!";
return s;
} else {
n = y / x;
Top++;
Result[Top] = String.valueOf(n);// 將運算結果重新入堆疊
}
}
if ("%".indexOf(str[i]) >= 0)
{
if (x == 0)// 被除數不允許為0
{
String s = "error!";
return s;
} else {
n = y % x;
Top++;
Result[Top] = String.valueOf(n);// 將運算結果重新入堆疊
}
}
}
}
return Result[Top];// 回傳最終結果
}
// 主函式
public static void main(String[] args) {
Calculator a = new Calculator();
}
}
歡迎評論,指正!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/231578.html
標籤:java
