在上篇文章《安卓应用开发学习》仿锤子计算器(上)只是写了个布局,那么在这篇文章中就去实现具体的计算功能。计算的实现主要是通过BigDecimal这个类来实现。
Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算。双精度浮点型变量double可以处理16位有效数。在实际应用中,需要对更大或者更小的数进行运算和处理。float和double只能用来做科学计算或者是工程计算,在商业计算中要用java.math.BigDecimal。BigDecimal所创建的是对象,我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。方法中的参数也必须是BigDecimal的对象。构造器是类的特殊方法,专门用来创建对象,特别是带有参数的对象。
BigDecimal一共有4个构造方法:
BigDecimal(int) 创建一个具有参数所指定整数值的对象。
BigDecimal(double) 创建一个具有参数所指定双精度值的对象。
BigDecimal(long) 创建一个具有参数所指定长整数值的对象。
BigDecimal(String) 创建一个具有参数所指定以字符串表示的数值的对象
在这里我们的计算器功能要实现四则运算的,所以使用StringBuffer类来生成计算的表达式,通过对表达式进行分析,得到正确的计算顺序,使用BigDecimal进行计算得出结果。在这里给出分析计算表达式的网址链接java字符串运算表达式的计算,感谢作者 缪斯的情人的分享。在这我直接给出代码,我稍微的修改了一下。
package com.xiangang.tools;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.Scanner;
import java.util.Stack;
/**
* 功能描述 . 只计算不带括号的加,减,乘,除
*
* @version 1.0
* @data:2012-11-01 下午06:53:39
* @author jeffig.guo
*/
public class StringCaculate {
private Stack<BigDecimal> numbers = new Stack<BigDecimal>();
private Stack<Character> chs = new Stack<Character>();
/**
* 比较当前操作符与栈顶元素操作符优先级,如果比栈顶元素优先级高,则返回true,否则返回false
*
* @param str
* 需要进行比较的字符
* @return 比较结果 true代表比栈顶元素优先级高,false代表比栈顶元素优先级低
*/
DecimalFormat df = new DecimalFormat("0.0");
private boolean compare(char str) {
if (chs.empty()) {
// 当为空时,显然 当前优先级最低,返回高
return true;
}
char last = (char) chs.lastElement();
switch (str) {
case '*': {
// '*/'优先级只比'+-'高
if (last == '+' || last == '-')
return true;
else
return false;
}
case '/': {
if (last == '+' || last == '-')
return true;
else
return false;
}
// '+-'为最低,一直返回false
case '+':
return false;
case '-':
return false;
}
return true;
}
public BigDecimal caculate(String st) {
StringBuffer sb = new StringBuffer(st);
StringBuffer num = new StringBuffer();
String tem = null;
char next;
while (sb.length() > 0) {
tem = sb.substring(0, 1);// 获取字符串的第一个字符
sb.delete(0, 1);
if (isNum(tem.trim()) || ".".equals(tem.trim())) {
num.append(tem);// 如果是数字,将其放入num当中
} else {
if (num.length() > 0 && !"".equals(num.toString().trim())) {// 当截取的字符不是数字时,则认为num中放置的时一个完整的数字,
// 如123+1,当获取到+时,前面的123可以认为是一个完整的数
BigDecimal bd = new BigDecimal(num.toString().trim());
numbers.push(bd);
num.delete(0, num.length());
}
// 如果chs为空,这认为这时第一个字符直接放入
if (!chs.isEmpty()) {
// 当当前的运算符优先级等于或者小于栈顶得预算符时,做运算.
// 例如,1+2+3,当截取到2,3之间的“+”与1,2之间的"+"优先级相等时,可以先计算1+2,使其变成3+3
// 同样,1*2+3,当截取到2,3之间的“+”与1,2之间的"*"优先级小,可以先计算1*2,使其变成2+3
while (!compare(tem.charAt(0))) {
caculate();
}
}
// 当数字栈也为空时,既运算式的第一个数字为负数时
if (numbers.isEmpty()) {
num.append(tem);
} else {
chs.push(new Character(tem.charAt(0)));
}
// 判断后一个字符是否为“-”号,为"-"号时,认为数字为负数
// 例如 1*2*(-5),因为此运算不计算(),因此将被改写为1*2*-5,如此情况,须将"-"认为是负数表达式而非减号
next = sb.charAt(0);
if (next == '-') {
num.append(next);
sb.delete(0, 1);
}
}
}
// 由于前面将数字放入栈时,是通过获取符号为时处理,导致最后一个数字没有放入栈中,因此将最后的数字放入栈中
BigDecimal bd = new BigDecimal(num.toString().trim());
numbers.push(bd);
// 此时符号栈上最多只有2个符号,并且栈顶得符号优先级高,做运算
while (!chs.isEmpty()) {
caculate();
}
return numbers.pop();
}
private void caculate() {
BigDecimal b = numbers.pop();// 第二个运算数
BigDecimal a = null;// 第一个运算数
a = numbers.pop();
char ope = chs.pop();
BigDecimal result = null;// 运算结果
switch (ope) {
// 如果是加号或者减号,则
case '+':
result = a.add(b);
// 将操作结果放入操作数栈
numbers.push(result);
break;
case '-':
// 将操作结果放入操作数栈
result = a.subtract(b);
numbers.push(result);
break;
case '*':
result = a.multiply(b);
// 将操作结果放入操作数栈
numbers.push(result);
break;
case '/':
String str = df.format(b.subtract(new BigDecimal("0.0")));
System.out.println("分母:" + str);
if (!str.equals("0.0")) {
System.out.println("分母不为零");
result = a.divide(b, 10, BigDecimal.ROUND_UP);
// 将操作结果放入操作数栈
numbers.push(result);
} else {
System.out.println("分母为零");
// 将操作结果放入操作数栈
numbers.push(new BigDecimal("0"));
}
break;
}
}
private boolean isNum(String num) {
return num.matches("[0-9]");
}
/**
*
* 功能描述。 解析,将带有括号的运算符变成没有带括号的字运算
*/
public BigDecimal parse(String st) {
int start = 0;
StringBuffer sts = new StringBuffer(st);
int end = -1;
while ((end = sts.indexOf(")")) > 0) {
String s = sts.substring(start, end + 1);
int first = s.lastIndexOf("(");
BigDecimal value = caculate(sts.substring(first + 1, end));
sts.replace(first, end + 1, value.toString());
}
return caculate(sts.toString());
}
}
在这里我给出另一种思路:Java表达式计算引擎:Expr4J 大家可以研究一下,更加的方便简单。
算法解决以后就是控制计算器的输入输出了,我这里用了比较笨的方法,就是每种情况都去考虑,代码直接贴出来,里面有比较详细的注释。
package com.xiangang.activity;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.GridView;
import android.widget.ImageButton;
import android.widget.Toast;
import com.xiangang.adapter.CalculatorTypeBoxItemAdapter;
import com.xiangang.livinghelper.R;
import com.xiangang.tools.Counts;
import com.xiangang.tools.StringCaculate;
public class CalculatorActivity extends Activity {
// 阿拉伯数字图片按钮的id数组
private int[] imgBtnNumId = { R.id.img_cal_d0, R.id.img_cal_d1,
R.id.img_cal_d2, R.id.img_cal_d3, R.id.img_cal_d4, R.id.img_cal_d5,
R.id.img_cal_d6, R.id.img_cal_d7, R.id.img_cal_d8, R.id.img_cal_d9 };
// 运算符号图片按钮的id数组
private int[] imgBtnSignId = { R.id.img_cal_mc, R.id.img_cal_madd,
R.id.img_cal_mminus, R.id.img_cal_addminus, R.id.img_cal_div,
R.id.img_cal_multiply, R.id.img_cal_minus, R.id.img_cal_add,
R.id.img_cal_amount };
private int[] imgBtnAcId = { R.id.img_cal_ac, R.id.img_cal_c,
R.id.img_cal_dot };
// 用于显示图片按钮的id数组
private int[] imgViewId = { R.drawable.pic0, R.drawable.pic1,
R.drawable.pic2, R.drawable.pic3, R.drawable.pic4, R.drawable.pic5,
R.drawable.pic6, R.drawable.pic7, R.drawable.pic8, R.drawable.pic9,
R.drawable.pic_add, R.drawable.pic_minus, R.drawable.pic_bg,
R.drawable.pic_e, R.drawable.pic_error, R.drawable.pic_multiply,
R.drawable.pic_div, R.drawable.pic_point };
// 阿拉伯数字图片按钮的控件数组
private ImageButton[] ImagButtonNum = new ImageButton[imgBtnNumId.length];
// 运算符图片按钮的控件数组
private ImageButton[] ImagButtonSign = new ImageButton[imgBtnSignId.length];
// 其它功能图片按钮的控件数组
private ImageButton[] ImagButtonAc = new ImageButton[imgBtnAcId.length];
// 用于显示输入的图片ID的list集合
private List<Integer> addViewList;
// 用于判断运算符号的
private Counts take = null;
// 用于计算的表达式
private StringBuffer expression;
// 用于判断小数点是否出现
private boolean isHasPoint = false;
// 用于判断是否开始计算
private boolean start = true;
// 用于显示的Adapter
private CalculatorTypeBoxItemAdapter mCalculatorTypeBoxItemAdapter;
// 用于显示的GridView
private GridView mGridView;
private Context mContext = this;
private DecimalFormat df = new DecimalFormat("0.0");
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.calculator_main);
initFindViewById();
initListener();
}
private void initFindViewById() {
for (int i = 0; i < imgBtnNumId.length; i++) {
ImagButtonNum[i] = (ImageButton) findViewById(imgBtnNumId[i]);
}
for (int j = 0; j < imgBtnSignId.length; j++) {
ImagButtonSign[j] = (ImageButton) findViewById(imgBtnSignId[j]);
}
for (int k = 0; k < imgBtnAcId.length; k++) {
ImagButtonAc[k] = (ImageButton) findViewById(imgBtnAcId[k]);
}
mGridView = (GridView) findViewById(R.id.gv_cal_typebox);
}
private void initListener() {
ImgBtnNumListener mImgBtnNumListener = new ImgBtnNumListener();
for (int i = 0; i < imgBtnNumId.length; i++) {
ImagButtonNum[i].setOnClickListener(mImgBtnNumListener);
}
ImgBtnSignListener mImgBtnSignListener = new ImgBtnSignListener();
for (int j = 0; j < imgBtnSignId.length; j++) {
ImagButtonSign[j].setOnClickListener(mImgBtnSignListener);
}
ImgBtnAcListener mImgBtnAcListener = new ImgBtnAcListener();
for (int k = 0; k < imgBtnAcId.length; k++) {
ImagButtonAc[k].setOnClickListener(mImgBtnAcListener);
}
}
// 数字按钮监听器
class ImgBtnNumListener implements OnClickListener {
@Override
public void onClick(View v) {
// 如果开始新的计算,则清除屏幕
if (start) {
// 刚开始计算时表达式初始化为零,输入数字则在表达式后面添加数组,对计算结果无影响
expression = new StringBuffer("0");
addViewList = new ArrayList<Integer>();
ShowResultInTypeBox();
start = false;
}
switch (v.getId()) {
case R.id.img_cal_d0:
// 添加0到Gridview的item用于显示
addViewList.add(imgViewId[0]);
// 添加0到表达式
expression.append("0");
break;
case R.id.img_cal_d1:
addViewList.add(imgViewId[1]);
expression.append("1");
break;
case R.id.img_cal_d2:
addViewList.add(imgViewId[2]);
expression.append("2");
break;
case R.id.img_cal_d3:
addViewList.add(imgViewId[3]);
expression.append("3");
break;
case R.id.img_cal_d4:
addViewList.add(imgViewId[4]);
expression.append("4");
break;
case R.id.img_cal_d5:
addViewList.add(imgViewId[5]);
expression.append("5");
break;
case R.id.img_cal_d6:
addViewList.add(imgViewId[6]);
expression.append("6");
break;
case R.id.img_cal_d7:
addViewList.add(imgViewId[7]);
expression.append("7");
break;
case R.id.img_cal_d8:
addViewList.add(imgViewId[8]);
expression.append("8");
break;
case R.id.img_cal_d9:
addViewList.add(imgViewId[9]);
expression.append("9");
break;
}
ShowResultInTypeBox();
}
}
// 加减乘除按钮监听器
class ImgBtnSignListener implements OnClickListener {
@Override
public void onClick(View v) {
if (take == Counts.DIVIDE && isZeroInDivide()) {
Toast.makeText(mContext, "分母不能为零啦", Toast.LENGTH_SHORT).show();
} else {
switch (v.getId()) {
case R.id.img_cal_add:
CheckExpressionTop('+');
take = Counts.ADD;
break;
case R.id.img_cal_minus:
CheckExpressionTop('-');
take = Counts.MINUS;
break;
case R.id.img_cal_multiply:
CheckExpressionTop('*');
take = Counts.MULTIPLY;
break;
case R.id.img_cal_div:
CheckExpressionTop('/');
take = Counts.DIVIDE;
break;
case R.id.img_cal_amount:
CheckExpressionTop('=');
StringCaculate caculate = new StringCaculate();
ShowResultView(String.valueOf(caculate.parse(expression
.toString())));
// 初始化表达式
expression = new StringBuffer("0");
// 本次计算结束
start = true;
break;
}
}
ShowResultInTypeBox();
}
}
// 清零,回撤监听器
class ImgBtnAcListener implements OnClickListener {
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.img_cal_dot:
CheckExpressionTop('.');
break;
case R.id.img_cal_c:
if (addViewList.size() - 1 >= 0) {
addViewList.remove(addViewList.size() - 1);
expression = new StringBuffer(expression.substring(0,
expression.length() - 1));
} else {
addViewList = new ArrayList<Integer>();
}
break;
case R.id.img_cal_ac:
// 这里用做清除记录
addViewList = new ArrayList<Integer>();
// 初始化表达式
expression = new StringBuffer("0");
// 本次计算结束
start = true;
break;
}
ShowResultInTypeBox();
}
}
private void ShowResultView(String result) {
// addViewList = new ArrayList<Integer>();
addViewList.add(R.drawable.pic_equal);
// 将计算结果分解成单个字符并转换成字符串
char[] s = result.toCharArray();
for (int i = 0; i < s.length; i++) {
String str = s[i] + "";
if ("0".equals(str)) {
addViewList.add(R.drawable.pic0);
} else if ("1".equals(str)) {
addViewList.add(R.drawable.pic1);
} else if ("2".equals(str)) {
addViewList.add(R.drawable.pic2);
} else if ("3".equals(str)) {
addViewList.add(R.drawable.pic3);
} else if ("4".equals(str)) {
addViewList.add(R.drawable.pic4);
} else if ("5".equals(str)) {
addViewList.add(R.drawable.pic5);
} else if ("6".equals(str)) {
addViewList.add(R.drawable.pic6);
} else if ("7".equals(str)) {
addViewList.add(R.drawable.pic7);
} else if ("8".equals(str)) {
addViewList.add(R.drawable.pic8);
} else if ("9".equals(str)) {
addViewList.add(R.drawable.pic9);
} else if ("E".equals(str)) {
addViewList.add(R.drawable.pic_e);
} else if ("-".equals(str)) {
addViewList.add(R.drawable.pic_minus);
} else if (".".equals(str)) {
addViewList.add(R.drawable.pic_point);
}
}
}
/**
* 用于判断分母是否为零
*
*/
private boolean isZeroInDivide() {
int divIndex = expression.indexOf("/");
String denominatorStr = "";
// 如果分母只有一个0
if (expression.length() - divIndex == 2) {
denominatorStr = expression.substring(divIndex + 1);
System.out.println("1:" + denominatorStr);
} else {
denominatorStr = expression.substring(divIndex + 1,
expression.length());
System.out.println("2:" + denominatorStr);
}
// 分母减去0.0结果若为零则认为分母的值为0
String str = df.format(new BigDecimal(denominatorStr)
.subtract(new BigDecimal("0.0")));
System.out.println("分母:" + str);
if (!str.equals("0.0")) {
System.out.println("分母不为零");
return false;
} else {
System.out.println("分母为零");
return true;
}
}
/**
* 用于屏幕显示
*
*/
private void ShowResultInTypeBox() {
mCalculatorTypeBoxItemAdapter = new CalculatorTypeBoxItemAdapter(
mContext, addViewList);
mGridView.setAdapter(mCalculatorTypeBoxItemAdapter);
}
/**
* 用于判断运算符号的逻辑性
*
*/
private void CheckExpressionTop(char ch) {
// 获取表达式最后一个字符
if (start) {
// 刚开始计算时表达式初始化为零,输入数字则在表达式后面添加数组,对计算结果无影响
expression = new StringBuffer("0");
addViewList = new ArrayList<Integer>();
addViewList.add(imgViewId[0]);
ShowResultInTypeBox();
start = false;
}
int lastIndex = expression.length() - 1;
char lastChar = expression.charAt(lastIndex);
switch (lastChar) {
case '+':
switch (ch) {
case '+':
// 不做任何事情
break;
case '-':
// 添加减号
addViewList.add(R.drawable.pic_minus);
expression.append("-");
break;
case '*':
// 表达式最后一个字符转换成乘号
addViewList
.set(addViewList.size() - 1, R.drawable.pic_multiply);
expression.setCharAt(lastIndex, '*');
break;
case '/':
// 表达式最后一个字符转换成除号
addViewList.set(addViewList.size() - 1, R.drawable.pic_div);
expression.setCharAt(lastIndex, '/');
break;
case '=':
// 添加0到表达式
addViewList.add(R.drawable.pic0);
expression.append("0");
break;
case '.':
// 添加0和.到表达式
addViewList.add(R.drawable.pic0);
expression.append("0");
addViewList.add(R.drawable.pic_point);
expression.append(".");
break;
}
break;
case '-':
switch (ch) {
case '+':
// 表达式最后一个字符转换成加号
addViewList.set(addViewList.size() - 1, R.drawable.pic_add);
expression.setCharAt(lastIndex, '+');
break;
case '-':
// 不做任何事情
break;
case '*':
// 表达式最后一个字符转换成乘号
addViewList
.set(addViewList.size() - 1, R.drawable.pic_multiply);
expression.setCharAt(lastIndex, '*');
break;
case '/':
// 表达式最后一个字符转换成除号
addViewList.set(addViewList.size() - 1, R.drawable.pic_div);
expression.setCharAt(lastIndex, '/');
break;
case '=':
// 添加0到表达式
addViewList.add(R.drawable.pic0);
expression.append("0");
break;
case '.':
// 添加0和.到表达式
addViewList.add(R.drawable.pic0);
expression.append("0");
addViewList.add(R.drawable.pic_point);
expression.append(".");
break;
}
break;
case '*':
switch (ch) {
case '+':
// 表达式最后一个字符转换成加号
addViewList.set(addViewList.size() - 1, R.drawable.pic_add);
expression.setCharAt(lastIndex, '+');
break;
case '-':
// 添加减号
addViewList.add(R.drawable.pic_minus);
expression.append("-");
break;
case '*':
// 不做任何事情
break;
case '/':
// 表达式最后一个字符转换成除号
addViewList.set(addViewList.size() - 1, R.drawable.pic_div);
expression.setCharAt(lastIndex, '/');
break;
case '=':
// 添加1到表达式
addViewList.add(R.drawable.pic1);
expression.append("1");
break;
case '.':
// 添加0和.到表达式
addViewList.add(R.drawable.pic0);
expression.append("0");
addViewList.add(R.drawable.pic_point);
expression.append(".");
break;
}
break;
case '/':
switch (ch) {
case '+':
// 表达式最后一个字符转换成加号
addViewList.set(addViewList.size() - 1, R.drawable.pic_add);
expression.setCharAt(lastIndex, '+');
break;
case '-':
// 添加减号
addViewList.add(R.drawable.pic_minus);
expression.append("-");
break;
case '*':
// 表达式最后一个字符转换成乘号
addViewList
.set(addViewList.size() - 1, R.drawable.pic_multiply);
expression.setCharAt(lastIndex, '*');
break;
case '/':
// 不做任何事情
break;
case '=':
// 添加1到表达式
addViewList.add(R.drawable.pic1);
expression.append("1");
break;
case '.':
// 添加0和.到表达式
addViewList.add(R.drawable.pic0);
expression.append("0");
addViewList.add(R.drawable.pic_point);
expression.append(".");
break;
}
break;
case '.':
Log.i("TAG", String.valueOf(isHasPoint));
switch (ch) {
case '+':
// 添加0和+到表达式
addViewList.add(R.drawable.pic0);
expression.append("0");
addViewList.add(R.drawable.pic_add);
expression.append("+");
break;
case '-':
// 添加0和-到表达式
addViewList.add(R.drawable.pic0);
expression.append("0");
addViewList.add(R.drawable.pic_minus);
expression.append("-");
break;
case '*':
// 添加0和*到表达式
addViewList.add(R.drawable.pic0);
expression.append("0");
addViewList.add(R.drawable.pic_multiply);
expression.append("*");
break;
case '/':
// 添加0和/到表达式
addViewList.add(R.drawable.pic0);
expression.append("0");
addViewList.add(R.drawable.pic_div);
expression.append("/");
break;
case '=':
// 添加0和=到表达式
addViewList.add(R.drawable.pic0);
expression.append("0");
break;
case '.':
// 不做处理
break;
}
break;
// 如果不是运算符号把当前的字符添加进去
default:
switch (ch) {
case '+':
// 表示允许输入小数点
isHasPoint = false;
// 添加加号
addViewList.add(R.drawable.pic_add);
expression.append("+");
break;
case '-':
// 表示允许输入小数点
isHasPoint = false;
// 添加减号
addViewList.add(R.drawable.pic_minus);
expression.append("-");
break;
case '*':
// 表示允许输入小数点
isHasPoint = false;
// 添加乘号
addViewList.add(R.drawable.pic_multiply);
expression.append("*");
break;
case '/':
// 表示允许输入小数点
isHasPoint = false;
// 添加除号
addViewList.add(R.drawable.pic_div);
expression.append("/");
break;
case '=':
// 表示允许输入小数点
isHasPoint = false;
break;
case '.':
// 若表达式最后一个字符不是运算符且小数点出现过则不允许再次输入小数点
if (!isHasPoint) {
addViewList.add(R.drawable.pic_point);
expression.append(".");
// 表示小数点出现过
isHasPoint = true;
}
break;
}
break;
}
}
}
代码写的不是很好,有的东西可能也考虑的不周全。因为计算的显示使用了图片来显示,之前想的方法是通过动态添加控件来实现,但没有一个好的管理,最终使用了Gridview去实现,效果差强人意吧。也请各位大神能够指点指点。最后给出演示的动态图。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/116900.html