Java編寫(xiě)簡(jiǎn)單計(jì)算器的完整實(shí)現(xiàn)過(guò)程
前言
本文用Java的swing來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)單計(jì)算器,主要內(nèi)容為圖形用戶(hù)界面GUI的實(shí)現(xiàn)以及運(yùn)算表達(dá)式核心算法的設(shè)計(jì)編寫(xiě)。
程序運(yùn)行環(huán)境為Windows10 ,編譯環(huán)境為MyEclipse 。
一、具體功能:
1、:輸入,輸出
輸入:允許輸入帶有括號(hào)的完整計(jì)算式(例 8*(4-95)+5÷2*e-pi)
輸出:輸出Double類(lèi)型的結(jié)果
輸出:整個(gè)運(yùn)算表達(dá)式并保存于歷史記錄中
2、:功能
基本的加,減,乘,除,四則運(yùn)算
平方運(yùn)算
開(kāi)方運(yùn)算
求余運(yùn)算
最終界面如下圖:

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

2、計(jì)算后綴表達(dá)式
準(zhǔn)備:
需要用到一個(gè)結(jié)果棧Res_Stack :用于存放計(jì)算的中間過(guò)程的值和最終結(jié)果
算法思想:
1、從左開(kāi)始向右遍歷后綴表達(dá)式的元素。
2、如果取到的元素是操作數(shù),直接入棧Res_Stack,如果是運(yùn)算符,從棧中彈出2個(gè)數(shù)進(jìn)行運(yùn)算,然后把運(yùn)算結(jié)果入棧
3、當(dāng)遍歷完后綴表達(dá)式時(shí),計(jì)算結(jié)果就保存在棧里了。
示意圖:

三、結(jié)果測(cè)試

分析:
1、可實(shí)現(xiàn)基本四則運(yùn)算及平方、開(kāi)方、求余運(yùn)算。
2、運(yùn)算表達(dá)式可顯示于輸入界面并保存于歷史記錄欄
3、輸入界面和歷史記錄欄皆可實(shí)現(xiàn)不斷字自動(dòng)換行功能以及滾動(dòng)條功能
4、不足之處:進(jìn)行平方和開(kāi)方運(yùn)算時(shí)其保存在歷史記錄中的表達(dá)式會(huì)出現(xiàn)兩個(gè)等號(hào)及兩個(gè)結(jié)果。
四、完整源代碼(每行代碼已附有詳細(xì)注釋)
package software;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
//Calculator類(lèi),繼承JFrame框架,實(shí)現(xiàn)事件監(jiān)聽(tīng)器接口
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可容納多行文本;文本框內(nèi)容初始值設(shè)為0.0
private JTextArea History = new JTextArea();// 歷史記錄文本框初始值設(shè)為空
private JPanel jp1=new JPanel();
private JPanel jp2=new JPanel();
private JScrollPane gdt1=new JScrollPane(resultText);//給輸入顯示屏文本域新建一個(gè)垂直滾動(dòng)滑條
private JScrollPane gdt2=new JScrollPane(History);//給歷史記錄文本域新建一個(gè)垂直滾動(dòng)滑條
// private JScrollPane gdt3=new JScrollPane(History);//給歷史記錄文本域新建一個(gè)水平滾動(dòng)滑條
private JLabel label = new JLabel("歷史記錄");
private String b = "";
// 構(gòu)造方法
public Calculator() {
super("Caculator");//“超”關(guān)鍵字,表示調(diào)用父類(lèi)的構(gòu)造函數(shù),
resultText.setBounds(20, 18, 255, 115);// 設(shè)置文本框大小
resultText.setAlignmentX(RIGHT_ALIGNMENT);// 文本框內(nèi)容右對(duì)齊
resultText.setEditable(false);// 文本框不允許修改結(jié)果
History.setBounds(290, 40, 250,370);// 設(shè)置文本框大小
History.setAlignmentX(LEFT_ALIGNMENT);// 文本框內(nèi)容右對(duì)齊
History.setEditable(false);// 文本框不允許修改結(jié)果
label.setBounds(300, 15, 100, 20);//設(shè)置標(biāo)簽位置及大小
jp2.setBounds(290,40,250,370);//設(shè)置面板窗口位置及大小
jp2.setLayout(new GridLayout());
jp1.setBounds(20,18,255,115);//設(shè)置面板窗口位置及大小
jp1.setLayout(new GridLayout());
resultText.setLineWrap(true);// 激活自動(dòng)換行功能
resultText.setWrapStyleWord(true);// 激活斷行不斷字功能
resultText.setSelectedTextColor(Color.RED);
History.setLineWrap(true);//自動(dòng)換行
History.setWrapStyleWord(true);
History.setSelectedTextColor(Color.blue);
gdt1.setViewportView(resultText);//使?jié)L動(dòng)條顯示出來(lái)
gdt2.setViewportView(History);
gdt1.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);//設(shè)置讓垂直滾動(dòng)條一直顯示
gdt2.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);//設(shè)置讓垂直滾動(dòng)條一直顯示
gdt2.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);//設(shè)置讓水平滾動(dòng)條一直顯示
jp1.add(gdt1);//將滾動(dòng)條添加入面板窗口中
jp2.add(gdt2);
this.add(jp1);//將面板添加到總窗體中
this.add(jp2);//將面板添加到總窗體中
this.setLayout(null);
this.add(label);// 新建“歷史記錄”標(biāo)簽
//this.add(resultText);// 新建文本框,該語(yǔ)句會(huì)添加進(jìn)去一個(gè)新的JTextArea導(dǎo)致帶有滾動(dòng)條的文本無(wú)法顯示或者發(fā)生覆蓋
//this.add(History);// 新建歷史記錄文本框,該語(yǔ)句會(huì)添加進(jìn)去一個(gè)新的JTextArea導(dǎo)致帶有滾動(dòng)條的文本無(wú)法顯示
// 放置按鈕
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++)// 每個(gè)按鈕都注冊(cè)事件監(jiān)聽(tīng)器
{
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);//使輸入的表達(dá)式顯示在歷史記錄文本框中
String label=e.getActionCommand();//獲得事件源的標(biāo)簽
if(label=="=")//
{
resultText.setText(this.b);
History.setText(History.getText()+resultText.getText());
if(label=="=")//調(diào)用計(jì)算方法,得出最終結(jié)果
{
String s[]=houzhui(this.b);
String result=Result(s);
this.b=result+"";
//更新文本框,當(dāng)前結(jié)果在字符串b中,并未刪除,下一次輸入接著此結(jié)果以實(shí)現(xiàn)連續(xù)運(yùn)算
resultText.setText(this.b);
History.setText(History.getText()+"="+resultText.getText()+"\n");
}
}
else if(label=="AC")//清空按鈕,消除顯示屏文本框前面所有的輸入和結(jié)果
{
this.b="";
resultText.setText("0");//更新文本域的顯示,顯示初始值;
}
else if(label=="sqrt")
{
String n=kfys(this.b);
resultText.setText("sqrt"+"("+this.b+")"+"="+n);//使運(yùn)算表達(dá)式顯示在輸入界面
History.setText(History.getText()+"sqrt"+"("+this.b+")"+"=");//獲取輸入界面的運(yùn)算表達(dá)式并使其顯示在歷史記錄文本框
this.b=n;
}
else if(label=="x*x")
{
String m=pfys(this.b);
resultText.setText(this.b+"^2"+"="+m);//使運(yùn)算表達(dá)式顯示在輸入界面
History.setText(History.getText()+this.b+"^2"+"=");//獲取輸入界面的運(yùn)算表達(dá)式并使其顯示在歷史記錄文本框
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之前輸入的運(yùn)算符或數(shù)字字符繼續(xù)下一步運(yùn)算
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);//使輸入的表達(dá)式顯示在歷史記錄文本框中
}
//將中綴表達(dá)式轉(zhuǎn)換為后綴表達(dá)式
private String[] houzhui(String str) {
String s = "";// 用于承接多位數(shù)的字符串
char opStack[] = new char[100];// 靜態(tài)棧,對(duì)用戶(hù)輸入的操作符進(jìn)行處理,用于存儲(chǔ)運(yùn)算符
String postQueue[] = new String[100];// 后綴表達(dá)式字符串?dāng)?shù)組,為了將多位數(shù)存儲(chǔ)為獨(dú)立的字符串
int top = -1, j = 0;// 靜態(tài)指針top,控制變量j
for (int i = 0; i < str.length(); i++)// 遍歷中綴表達(dá)式
// indexof函數(shù),返回字串首次出現(xiàn)的位置;charAt函數(shù)返回index位置處的字符;
{
if ("0123456789.".indexOf(str.charAt(i)) >= 0) // 遇到數(shù)字字符的情況
{
s = "";// 作為承接字符,每次開(kāi)始時(shí)都要清空
for (; i < str.length() && "0123456789.".indexOf(str.charAt(i)) >= 0; i++) {
s = s + str.charAt(i);
}
i--;
postQueue[j] = s;// 數(shù)字字符直接加入后綴表達(dá)式
j++;
} else if ("(".indexOf(str.charAt(i)) >= 0) {// 遇到左括號(hào)
top++;
opStack[top] = str.charAt(i);// 左括號(hào)入棧
} else if (")".indexOf(str.charAt(i)) >= 0) {// 遇到右括號(hào)
for (;;)// 棧頂元素循環(huán)出棧,直到遇到左括號(hào)為止
{
if (opStack[top] != '(') {// 棧頂元素不是左括號(hào)
postQueue[j] = opStack[top] + "";// 棧頂元素出棧
j++;
top--;
} else { // 找到棧頂元素是左括號(hào)
top--;// 刪除棧頂左括號(hào)
break;// 循環(huán)結(jié)束
}
}
}
if ("*%/".indexOf(str.charAt(i)) >= 0)// 遇到高優(yōu)先級(jí)運(yùn)算符
{
if (top == -1) {// 若棧為空則直接入棧
top++;
opStack[top] = str.charAt(i);
} else {// 棧不為空,把棧中彈出的元素入隊(duì),直到棧頂元素優(yōu)先級(jí)小于x或者棧為空
if ("*%/".indexOf(opStack[top]) >= 0) {
// 棧頂元素也為高優(yōu)先級(jí)運(yùn)算符
postQueue[j] = opStack[top] + "";// 棧頂元素出棧進(jìn)入后綴表達(dá)式
j++;
opStack[top] = str.charAt(i);// 當(dāng)前運(yùn)算符入棧
} else if ("(".indexOf(opStack[top]) >= 0) {// 棧頂元素為左括號(hào),當(dāng)前運(yùn)算符入棧
top++;
opStack[top] = str.charAt(i);
} else if ("+-".indexOf(str.charAt(i)) >= 0) {// 遇到低優(yōu)先級(jí)運(yùn)算符
postQueue[j] = opStack[top] + "";// 棧頂元素出棧進(jìn)入后最表達(dá)式
j++;
opStack[top] = str.charAt(i);// 當(dāng)前元素入棧
}
}
} else if ("+-".indexOf(str.charAt(i)) >= 0) {
if (top == -1) {
top++;
opStack[top] = str.charAt(i);
} else {
if ("*%/".indexOf(opStack[top]) >= 0) {
// 棧頂元素也為高優(yōu)先級(jí)運(yùn)算符
postQueue[j] = opStack[top] + "";// 棧頂元素出棧進(jìn)入后綴表達(dá)式
j++;
opStack[top] = str.charAt(i);// 當(dāng)前運(yùn)算符入棧
} else if ("(".indexOf(opStack[top]) >= 0) {// 棧頂元素為左括號(hào),當(dāng)前運(yùn)算符入棧
top++;
opStack[top] = str.charAt(i);
} else if ("+-".indexOf(str.charAt(i)) >= 0) {// 遇到低優(yōu)先級(jí)運(yùn)算符
postQueue[j] = opStack[top] + "";// 棧頂元素出棧進(jìn)入后最表達(dá)式
j++;
opStack[top] = str.charAt(i);// 當(dāng)前元素入棧
}
}
}
}
for (; top != -1;) {// 遍歷結(jié)束后將棧中剩余元素依次出棧進(jìn)入后綴表達(dá)式
postQueue[j] = opStack[top] + "";
j++;
top--;
}
return postQueue;
}
//開(kāi)方運(yùn)算方法
public String kfys(String str) {
String result = "";
double a = Double.parseDouble(str), b = 0;
b = Math.sqrt(a);
result = String.valueOf(b);//將運(yùn)算結(jié)果轉(zhuǎn)換為string類(lèi)型并賦給string類(lèi)型的變量result
return result;
}
//平方運(yùn)算方法
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;
}
// 計(jì)算后綴表達(dá)式,并返回最終結(jié)果
public String Result(String str[]) {
String Result[] = new String[100];// 順序存儲(chǔ)的棧,數(shù)據(jù)類(lèi)型為字符串
int Top = -1;// 靜態(tài)指針Top
for (int i = 0; str[i] != null; i++) {
if ("+-*%/".indexOf(str[i]) < 0) {
Top++;
Result[Top] = str[i];
}
if ("+-*%/".indexOf(str[i]) >= 0)// 遇到運(yùn)算符字符,將棧頂兩個(gè)元素出棧計(jì)算并將結(jié)果返回棧頂
{
double x, y, n;
x = Double.parseDouble(Result[Top]);// 順序出棧兩個(gè)數(shù)字字符串,并轉(zhuǎn)換為double類(lèi)型
Top--;
y = Double.parseDouble(Result[Top]);
Top--;
if ("-".indexOf(str[i]) >= 0) {
n = y - x;
Top++;
Result[Top] = String.valueOf(n);// 將運(yùn)算結(jié)果重新入棧
}
if ("+".indexOf(str[i]) >= 0) {
n = y + x;
Top++;
Result[Top] = String.valueOf(n);// 將運(yùn)算結(jié)果重新入棧
}
if ("*".indexOf(str[i]) >= 0) {
n = y * x;
Top++;
Result[Top] = String.valueOf(n);// 將運(yùn)算結(jié)果重新入棧
}
if ("/".indexOf(str[i]) >= 0)
{
if (x == 0)// 被除數(shù)不允許為0
{
String s = "error!";
return s;
} else {
n = y / x;
Top++;
Result[Top] = String.valueOf(n);// 將運(yùn)算結(jié)果重新入棧
}
}
if ("%".indexOf(str[i]) >= 0)
{
if (x == 0)// 被除數(shù)不允許為0
{
String s = "error!";
return s;
} else {
n = y % x;
Top++;
Result[Top] = String.valueOf(n);// 將運(yùn)算結(jié)果重新入棧
}
}
}
}
return Result[Top];// 返回最終結(jié)果
}
// 主函數(shù)
public static void main(String[] args) {
Calculator a = new Calculator();
}
}
到此這篇關(guān)于Java編寫(xiě)簡(jiǎn)單計(jì)算器的文章就介紹到這了,更多相關(guān)Java編寫(xiě)簡(jiǎn)單計(jì)算器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Java簡(jiǎn)易計(jì)算器程序設(shè)計(jì)
- java實(shí)現(xiàn)簡(jiǎn)易計(jì)算器功能
- Java實(shí)現(xiàn)計(jì)算器的代碼
- java 簡(jiǎn)單的計(jì)算器程序?qū)嵗a
- java實(shí)現(xiàn)簡(jiǎn)單的計(jì)算器類(lèi)實(shí)例
- java實(shí)現(xiàn)計(jì)算器功能
- 用Java實(shí)現(xiàn)簡(jiǎn)單計(jì)算器功能
- 200行Java代碼編寫(xiě)一個(gè)計(jì)算器程序
- Java編寫(xiě)計(jì)算器的常見(jiàn)方法實(shí)例總結(jié)
- 用Java打造簡(jiǎn)易計(jì)算器的實(shí)現(xiàn)步驟
相關(guān)文章
Mybatis-Plus 自動(dòng)填充失效問(wèn)題解決
在使用MyBatis-Plus時(shí),自動(dòng)填充功能可能會(huì)失效,這通常與版本和配置有關(guān),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-10-10
Java開(kāi)發(fā)druid數(shù)據(jù)連接池maven方式簡(jiǎn)易配置流程示例
本篇文章主要為大家介紹了java開(kāi)發(fā)中druid數(shù)據(jù)連接池maven方式的簡(jiǎn)易配置流程示例,文中附含詳細(xì)的代碼示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助2021-10-10
解決Java中的強(qiáng)制類(lèi)型轉(zhuǎn)換和二進(jìn)制表示問(wèn)題
這篇文章主要介紹了解決Java中的強(qiáng)制類(lèi)型轉(zhuǎn)換和二進(jìn)制表示問(wèn)題,需要的朋友可以參考下2019-05-05
Java深入數(shù)據(jù)結(jié)構(gòu)理解掌握抽象類(lèi)與接口
在類(lèi)中沒(méi)有包含足夠的信息來(lái)描繪一個(gè)具體的對(duì)象,這樣的類(lèi)稱(chēng)為抽象類(lèi),接口是Java中最重要的概念之一,它可以被理解為一種特殊的類(lèi),不同的是接口的成員沒(méi)有執(zhí)行體,是由全局常量和公共的抽象方法所組成,本文給大家介紹Java抽象類(lèi)和接口,感興趣的朋友一起看看吧2022-05-05
解決SpringBoot集成Eureka導(dǎo)致返回結(jié)果由json變?yōu)閤ml的問(wèn)題
這篇文章主要介紹了解決SpringBoot集成Eureka導(dǎo)致返回結(jié)果由json變?yōu)閤ml的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07
springboot jpa分庫(kù)分表項(xiàng)目實(shí)現(xiàn)過(guò)程詳解
這篇文章主要介紹了springboot jpa分庫(kù)分表項(xiàng)目實(shí)現(xiàn)過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-01-01
Java多線(xiàn)程模擬銀行系統(tǒng)存錢(qián)問(wèn)題詳解
本文將利用Java多線(xiàn)程模擬一個(gè)簡(jiǎn)單的銀行系統(tǒng),使用兩個(gè)不同的線(xiàn)程向同一個(gè)賬戶(hù)存錢(qián)。文中的示例代碼講解詳細(xì),感興趣的可以了解一下2022-09-09

