1. 程式人生 > 程式設計 >Java編寫簡單計算器的完整實現過程

Java編寫簡單計算器的完整實現過程

前言

本文用Javaswing來實現一個簡單計算器,主要內容為圖形使用者介面GUI的實現以及運算表示式核心演算法的設計編寫。

程式執行環境為Windows10 ,編譯環境為MyEclipse 。

一、具體功能:

1、:輸入,輸出

輸入:允許輸入帶有括號的完整計算式(例 8*(4-95)+5÷2*e-pi)
輸出:輸出Double型別的結果
輸出:整個運算表示式並保存於歷史記錄中

2、:功能

基本的加,減,乘,除,四則運算
平方運算
開方運算
求餘運算

最終介面如下圖:

Java編寫簡單計算器的完整實現過程

除了常規的數字按鈕和運算子,還有兩個常數e,pi(π),清空鍵AC,括號運算子(),平方(x^x)和開方(sqrt)運算子,輸入顯示框以及歷史記錄文字框,文字框的垂直滾動條和水平滾動條。

二、主要思想:

1:中綴表示式轉為字尾表示式

準備:

①字尾表示式佇列:postQueue,用於儲存逆波蘭表示式(其實不用佇列排序直接輸出也行)
②操作符棧:opStack,對使用者輸入的操作符進行處理,用於儲存運算子

演算法思想:

從左向右依次讀取算術表示式的元素X,分以下情況進行不同的處理:
(1)如果X是運算元,直接入隊
(2)如果X是運算子,再分以下情況:
a)如果棧為空,直接入棧。
b)如果X==”(“,直接入棧。
c)如果X==”)“,則將棧裡的元素逐個出棧,併入隊到字尾表示式佇列中,直到第一個配對的”(”出棧。(注:“(”和“)”都不 入隊)
d)如果是其他操作符(+ - * /),則和棧頂元素進行比較優先順序。 如果棧頂元素的優先順序大於等於X,則出棧並把棧中彈出的元素入隊,直到棧頂元素的優先順序小於X或者棧為空。彈出完這些元素後,才將遇到的操作符壓入到棧中。

(3)最後將棧中剩餘的操作符全部入隊。

示意圖:

Java編寫簡單計算器的完整實現過程

2、計算字尾表示式

準備:

需要用到一個結果棧Res_Stack :用於存放計算的中間過程的值和最終結果

演算法思想:

1、從左開始向右遍歷字尾表示式的元素。
2、如果取到的元素是運算元,直接入棧Res_Stack,如果是運算子,從棧中彈出2個數進行運算,然後把運算結果入棧
3、當遍歷完字尾表示式時,計算結果就儲存在棧裡了。

示意圖:

Java編寫簡單計算器的完整實現過程

三、結果測試

Java編寫簡單計算器的完整實現過程

分析:

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,370);//設定面板視窗位置及大小
	jp2.setLayout(new GridLayout());
	jp1.setBounds(20,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,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();
  }
}

到此這篇關於Java編寫簡單計算器的文章就介紹到這了,更多相關Java編寫簡單計算器內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!