公告
日历
| 日 | 一 | 二 | 三 | 四 | 五 | 六 |
---|
29 | 30 | 31 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
|
统计
- 随笔 - 36
- 文章 - 10
- 评论 - 94
- 引用 - 0
导航
常用链接
留言簿(5)
随笔分类(49)
随笔档案(36)
文章分类(11)
文章档案(10)
相册
dyerac
搜索
积分与排名
最新随笔
最新评论
阅读排行榜
评论排行榜
|
有感于windows自带计算器的不好使,最近心血来潮按自己需求开发了一个多功能计算器。其核心的一部分来自于网上的学习资料,因此我也不敢私藏代码,特拿出来和大家分享心得。 计算器功能如下: 1.支持运行时更换界面皮肤,水印和按钮形状等外观显示。 2.支持sin, cos, tan, cot, arcsin, arccos, arctan, arccot, !, log, ln, +, -, *, /, %, 乘方等基本运算,支持连续运算并自带PI,E的精确值。 3.支持表达式计算,支持设置变量,可以轻松的实现公式运算。 4.无限的结果保存,完全对用户透明,用户可以轻松的存储和读取先前的操作结果. 5.能够分析用户操作尤其是表达式中的语法错误,提醒用户而不是返回错误结果。
设计思路:
整个程序的
GUI
由两部分组成。结果存储由
JDialog
完成,
JDialog
内含一个
JList
存放结果。主界面由
JMenuBar
和
JTabbedPane
组成,
JTabbedPane
的两个子界面分别用作按键式计算器和表达式式计算器。
关于界面的构建工作全部由
CalculatorFace
类完成,同时按键式计算器的后台计算工作也有该类完成。
Parser
类则负责解析表达式返回计算结果。
CalculatorFace
调用
Parser
进行表达式计算工作。
在处理按键式计算时,各种计算操作符号显然可以分为两类:单操作数和双操作数。单操作数计算只需要取出显示框中内容,进行计算再将结果显示即可。双操作数计算则显得比较麻烦。因为需要实现连续计算,所以必须保存上次的操作符号和上次输入的结果。为此增加lastOperator字段和number1,number2字段分别存储前次操作符和对应的操作数。 运行机制如下: 当按下新键时,将number2->number1,显示框中内容取出作为number2,同时根据lastOperator中内容进行计算(number1 lastOperator number2),计算完成后,将这次按键内容保存到lastOperator中。要注意的是,当“=”按下时,将取消连续运算。因此添加boolean字段continued用来判断是否进行连续运算。 考虑到用户的误操作,即可能不小心按错了按钮,因此每次运算应以输入新数字前最后一个操作符号为准。因此,continued事实上也控制运算是否进行,每次双操作运算后,continued赋值为false,输入数字后才重新为真。当continued为false时,程序只是简单的把按键值赋予lastOperator而不进行运算工作。 而对于数字按键,唯一需要注意的是按下操作键后,再输入数据需要将显示框清空后从头输入;否则新数字将在显示框原有内容尾部添加。completed字段用于控制该情形。上述例外在于,第一次使用计算器时,即使没有按下操作键,也应该重新显示数字。First字段将处理这一情形。
表达式解析则通过Parser类完成。getToken方法负责将表达式中基本的单元取出。这些基本单元包括:变量,数字和操作符号。运行时,首先将表达式中变量替换成其值,对处理好的表达式从左至右取出单元进行计算。计算采用递归下降的流式处理,调用按计算优先级排列好的各种函数,每种函数处理同一优先级的运算。 优先级列表为: 括号,阶乘,正负号,三角函数/对数函数/反三角函数,乘方,乘/除/模运算,加减运算。 下面举例说明表达式的解析过程。表达式 10 + 5 * B 有两个项:10和5*B,第二项包括两个因数:5和B,分别是一个数字和一个变量 再看另外一个例子。表达式 14 * (7 – C) 有两个因数:14和(7-C),分别是一个数字和一个圆括号表达式。圆括号表达式包括两个项:一个数字和一个变量。 上述过程形成了递归下降解析器的基础。递归下降解析器是一组互相递归的方法,这些方法以一种链式方式实现生成规则。在每个适当的步骤上,解析器以代数学规定的正确顺序执行指定的操作。为了解释如何使用生成规则来解析表达式,采用下面的表达式来跟踪解析过程: 9/3 – (100 + 56) 整个解析过程如下: (1) 获得第一项9/3; (2) 获得第一项的两个因数并完成除法运算,得到结果3; (3) 获得第二项(100+56)。在这一步启动递归分析过程处理括号内的子表达式; (4) 获得其中的两项并完成加法运算,得到结果156; (5) 从第二项的递归计算过程中返回; (6) 3减去156,答案是-153。
Bugs: 经过同学的友情测试,现发现bug如下: (1)无法将――2形式识别为2 (2)乘方运算时,当数字和’!’中出现空格或者括号时无法处理 (3)类似sinlog10形式无法识别,只能识别sin(log10) 以上将在下一版本中修订。
Uncompleted features: (1)任意进制的计算和转换 (2)角度与弧度的转换 (3)扩大计算范围(即应该使用BigDemical而不是double) 以上同样会在下一版本中实现。
下面是程序的源代码:
package
cn.com.w4t.calculator;
import
java.awt.BorderLayout;
import
java.awt.Color;
import
java.awt.GridLayout;
import
java.awt.event.ActionEvent;
import
java.awt.event.ActionListener;
import
java.util.Vector;
import
javax.swing.JButton;
import
javax.swing.JDialog;
import
javax.swing.JFrame;
import
javax.swing.JLabel;
import
javax.swing.JList;
import
javax.swing.JMenu;
import
javax.swing.JMenuBar;
import
javax.swing.JMenuItem;
import
javax.swing.JPanel;
import
javax.swing.JScrollPane;
import
javax.swing.JTabbedPane;
import
javax.swing.JTextArea;
import
javax.swing.JTextField;
import
javax.swing.UIManager;
import
javax.swing.border.EtchedBorder;
import
javax.swing.border.LineBorder;
import
javax.swing.border.TitledBorder;
import
org.jvnet.substance.SubstanceLookAndFeel;
import
org.jvnet.substance.theme.SubstancePurpleTheme;
import
org.jvnet.substance.watermark.SubstanceBinaryWatermark;
/** */
/**
* Main Application Interface * *
@author
td *
*/
@SuppressWarnings(
"
serial
"
)
public
class
CalculatorFace
extends
JFrame
implements
ActionListener
{
/** */
/**
* 按键计算的结果
*/
private
double
result1;
/** */
/**
* 表达式计算的结果
*/
private
double
result2;
/** */
/**
* 二元计算是否完成,完成后下次输入数据时将从头开始而不是在原有数据后添加
*/
private
boolean
completed
=
false
;
/** */
/**
* 是否是第一次进行操作
*/
private
boolean
first
=
true
;
/** */
/**
* 是否进行连续计算,比如"="将取消连续运算
*/
private
boolean
continued
=
false
;
/** */
/**
* 被保存的先前计算结果集
*/
private
Vector
<
String
>
resultVector
=
new
Vector
<
String
>
();
/** */
/**
* 计算表达式
*/
private
String express;
/** */
/**
* 变量值
*/
private
String variables;
/** */
/**
* 表达式解析式
*/
private
Parser parser
=
new
Parser();
/** */
/**
* 操作按键
*/
private
JButton[] operatorBtns
=
new
JButton[
20
];
/** */
/**
* 操作符号
*/
private
String[] op
=
{
"
+
"
,
"
-
"
,
"
*
"
,
"
/
"
,
"
%
"
,
"
^
"
,
"
!
"
,
"
=
"
,
"
ln
"
,
"
log
"
,
"
sin
"
,
"
cos
"
,
"
tan
"
,
"
cot
"
,
"
arcsin
"
,
"
arccos
"
,
"
arctan
"
,
"
arccot
"
,
"
PI
"
,
"
E
"
}
;
/** */
/**
* 数字按键
*/
private
JButton[] numberBtns
=
new
JButton[
12
];
/** */
/**
* 保持结果的对话框
*/
private
JDialog resultHolder;
/** */
/**
* 保持结果的列表
*/
private
JList resultList;
/** */
/**
* 一些系统功能按键,显示、隐藏结果记录对话框,存储计算结果,清屏,退格
*/
private
JButton clearBtn, saveBtn, saveBtn2, backBtn, shBtn, shBtn2, submitBtn;
/** */
/**
* 主界面
*/
private
JTabbedPane mainTab;
/** */
/**
* 输入框
*/
private
JTextField resultField1, resultField2, inputField;
/** */
/**
* 错误标签
*/
private
JLabel errorLabel1, errorLabel2;
/** */
/**
* 监听器
*/
private
ActionListener numberListener
=
new
NumberListener(), oneOperatorListener
=
new
OneOperatorListener(), twoOperatorListener
=
new
TwoOperatorListener();
/** */
/**
* 菜单
*/
private
JMenu fileM, setM, helpM;
/** */
/**
* 菜单栏
*/
private
JMenuBar menu;
/** */
/**
* 变量输入框
*/
private
JTextArea variableArea;
/** */
/**
* 操作数
*/
private
String number1
=
"
0.0
"
, number2
=
"
0.0
"
;
/** */
/**
* 上一次操作符号
*/
private
String lastOperator;
//
private JMenuItem fileItem, settingsItem, helpItem;
public
CalculatorFace()
{
super
(); init(); }
/** */
/**
* 初始化属性 *
*/
private
void
initReference()
{
//
init all buttons
for
(
int
i
=
0
; i
<
10
; i
++
)
{ numberBtns[i]
=
new
JButton(Integer.toString(i)); numberBtns[i].addActionListener(numberListener); numberBtns[i].setBorder(
null
); }
numberBtns[
10
]
=
new
JButton(
"
.
"
); numberBtns[
10
].addActionListener(oneOperatorListener); numberBtns[
10
].setBorder(
null
); numberBtns[
11
]
=
new
JButton(
"
+/-
"
); numberBtns[
11
].setBorder(
null
); numberBtns[
11
].addActionListener(oneOperatorListener);
for
(
int
i
=
0
; i
<
op.length; i
++
)
{ operatorBtns[i]
=
new
JButton(op[i]);
if
(i
<
6
) operatorBtns[i].addActionListener(twoOperatorListener);
else
operatorBtns[i].addActionListener(oneOperatorListener); operatorBtns[i].setBorder(
null
); }
clearBtn
=
new
JButton(
"
Clear
"
); clearBtn.addActionListener(
this
); clearBtn.setBorder(
new
EtchedBorder(EtchedBorder.LOWERED)); saveBtn
=
new
JButton(
"
Save
"
); saveBtn.addActionListener(
this
); saveBtn.setBorder(
new
EtchedBorder(EtchedBorder.LOWERED)); saveBtn2
=
new
JButton(
"
Save
"
); saveBtn2.addActionListener(
this
); saveBtn2.setBorder(
new
EtchedBorder(EtchedBorder.LOWERED)); backBtn
=
new
JButton(
"
Back
"
); backBtn.addActionListener(
this
); backBtn.setBorder(
new
EtchedBorder(EtchedBorder.LOWERED)); shBtn
=
new
JButton(
"
S/H
"
); shBtn.addActionListener(
this
); shBtn.setBorder(
new
EtchedBorder(EtchedBorder.LOWERED)); shBtn2
=
new
JButton(
"
S/H
"
); shBtn2.addActionListener(
this
); shBtn2.setBorder(
new
EtchedBorder(EtchedBorder.LOWERED)); submitBtn
=
new
JButton(
"
Submit
"
); ParserListener p
=
new
ParserListener(); submitBtn.addActionListener(p); submitBtn.setBorder(
new
EtchedBorder(EtchedBorder.LOWERED));
//
init textfileds
resultField1
=
new
JTextField(
"
0.0
"
); resultField1.setEditable(
false
); resultField2
=
new
JTextField(
"
0.0
"
); resultField2.setEditable(
false
); inputField
=
new
JTextField(); inputField.addActionListener(p); inputField.setToolTipText(
"
输入表达式,可以含有变量,但是变量必须在下面定义
"
); variableArea
=
new
JTextArea(); variableArea.setToolTipText(
"
输入变量值,约定形式为a=1,b=2,请勿使用s,c,t等关键字作为变量名
"
);
//
init labels
errorLabel1
=
new
JLabel(); errorLabel1.setForeground(Color.red); errorLabel2
=
new
JLabel(); errorLabel2.setForeground(Color.red);
mainTab
=
new
JTabbedPane();
//
init menu
menu
=
new
JMenuBar(); fileM
=
new
JMenu(
"
File
"
); fileM.setMnemonic(
'
F
'
); setM
=
new
JMenu(
"
Settings
"
); setM.setMnemonic(
'
S
'
); helpM
=
new
JMenu(
"
Help
"
); helpM.setMnemonic(
'
H
'
); }
/** */
/**
* 初始化菜单 *
*/
private
void
initMenu()
{ menu.add(fileM); menu.add(setM); menu.add(helpM); fileM.add(
new
JMenuItem(
"
Exit
"
)); setM.add(
new
JMenuItem(
"
二进制
"
)); setM.add(
new
JMenuItem(
"
八进制
"
)); setM.add(
new
JMenuItem(
"
十进制
"
)); setM.add(
new
JMenuItem(
"
十六进制
"
)); helpM.add(
new
JMenuItem(
"
Manual
"
)); helpM.add(
new
JMenuItem(
"
About
"
)); }
/** */
/**
* 初始化主界面 *
*/
private
void
initTabbedPane()
{ JPanel p1
=
new
JPanel(); JPanel p10
=
new
JPanel(); JPanel p12
=
new
JPanel(); JPanel p11
=
new
JPanel(); JPanel pc1
=
new
JPanel(); JPanel p2
=
new
JPanel(); JPanel p20
=
new
JPanel(); JPanel p22
=
new
JPanel(); JPanel p21
=
new
JPanel();
p10.setLayout(
new
GridLayout(
2
,
1
)); p10.setBorder(
new
TitledBorder(
new
LineBorder(Color.DARK_GRAY,
1
),
"
Result:
"
)); p12.setLayout(
new
GridLayout(
6
,
8
)); p11.setLayout(
new
GridLayout(
2
,
8
)); p1.setLayout(
new
BorderLayout()); pc1.setLayout(
new
BorderLayout()); pc1.setBorder(
new
TitledBorder(
new
LineBorder(Color.DARK_GRAY,
1
),
"
Input Buttons:
"
));
p20.setLayout(
new
GridLayout(
3
,
1
)); p21.setLayout(
new
BorderLayout()); p22.setLayout(
new
GridLayout(
1
,
7
)); p2.setLayout(
new
BorderLayout());
p10.add(resultField1); p10.add(errorLabel1);
for
(
int
i
=
0
; i
<
4
; i
++
)
{ p12.add(operatorBtns[i]); }
for
(
int
i
=
0
; i
<
4
; i
++
)
{ p12.add(
new
JLabel()); }
for
(
int
i
=
0
; i
<
4
; i
++
)
{
for
(
int
j
=
i
*
4
; j
<
i
*
4
+
4
; j
++
) p12.add(operatorBtns[j
+
4
]); p12.add(
new
JLabel(
""
));
for
(
int
j
=
i
*
3
; j
<
i
*
3
+
3
; j
++
) p12.add(numberBtns[j]); }
for
(
int
i
=
0
; i
<
8
; i
++
)
{ p12.add(
new
JLabel()); }
p11.add(shBtn); p11.add(saveBtn); p11.add(backBtn); p11.add(clearBtn);
for
(
int
i
=
0
; i
<
12
; i
++
) p11.add(
new
JLabel());
p1.add(p10,
"
North
"
); pc1.add(p11,
"
Center
"
); pc1.add(p12,
"
South
"
); p1.add(pc1,
"
Center
"
);
JLabel tip
=
new
JLabel(
"
支持:sin,cos,tan,cot,arcsin,arccos,arctan,arccot,!,log,ln
"
); p20.add(tip); p20.add(resultField2); p20.add(errorLabel2); p20.setBorder(
new
TitledBorder(
new
LineBorder(Color.DARK_GRAY,
1
),
"
Result:
"
));
JPanel p210
=
new
JPanel(); p210.setLayout(
new
BorderLayout()); p210.add(
new
JLabel(
"
输入表达式
"
),
"
North
"
); p210.add(inputField,
"
Center
"
); p210.add(
new
JLabel(
"
输入变量值
"
),
"
South
"
); p21.add(p210,
"
North
"
); p21.add(variableArea,
"
Center
"
); p21.setBorder(
new
TitledBorder(
new
LineBorder(Color.DARK_GRAY,
1
),
"
Input Express and Variables:
"
));
p22.add(
new
JLabel()); p22.add(
new
JLabel()); p22.add(saveBtn2); p22.add(shBtn2); p22.add(submitBtn); p22.add(
new
JLabel()); p22.add(
new
JLabel());
p2.add(p20,
"
North
"
); p2.add(p21,
"
Center
"
); p2.add(p22,
"
South
"
);
mainTab.addTab(
"
按键式
"
, p1); mainTab.addTab(
"
表达式
"
, p2); }
/** */
/**
* init the result-holding dialog *
*/
private
void
initHolder()
{ resultHolder
=
new
JDialog(); resultHolder.setTitle(
"
计算结果记录
"
); resultHolder.setLocation(
this
.getLocation().x
+
this
.getWidth()
+
10
,
this
.getLocation().y); resultList
=
new
JList(); resultList.setSize(
150
,
200
); resultList.addMouseListener(
new
java.awt.event.MouseAdapter()
{
public
void
mouseClicked(java.awt.event.MouseEvent e)
{
if
(e.getClickCount()
==
2
)
{ String s
=
(String) resultList.getSelectedValue();
//
System.err.print(mainTab.getSelectedIndex());
if
(mainTab.getSelectedIndex()
==
0
)
{ resultField1.setText(s); completed
=
false
; }
else
resultField2.setText(s); }
}
}
); resultHolder.add(
new
JScrollPane(resultList)); resultHolder.setSize(
150
,
200
); }
/** */
/**
* the main init method, init the whole application *
*/
private
void
init()
{
this
.setTitle(
"
DollyCal Calculator
"
);
this
.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this
.setLayout(
new
BorderLayout()); initReference(); initMenu(); initTabbedPane(); initHolder(); add(menu,
"
North
"
); add(
new
JScrollPane(mainTab),
"
South
"
); pack(); setLocation(
200
,
100
); setVisible(
true
); }
/** */
/**
* 处理有关系统功能(显示、隐藏结果记录对话框,存储计算结果,清屏,退格)的按键触发事件
*/
public
void
actionPerformed(ActionEvent e)
{
//
TODO Auto-generated method stub
if
(e.getSource().equals(shBtn)
||
e.getSource().equals(shBtn2))
{
if
(resultHolder.isVisible()
==
false
)
{ resultHolder.setLocation(
this
.getLocation().x
+
this
.getWidth()
+
10
,
this
.getLocation().y); resultHolder.setVisible(
true
); }
else
resultHolder.setVisible(
false
); }
if
(e.getSource().equals(saveBtn))
{ resultHolder.setLocation(
this
.getLocation().x
+
this
.getWidth()
+
10
,
this
.getLocation().y);
if
(resultField1.getText()
!=
null
&&
resultField1.getText().length()
>
0
)
{ resultVector.add(
0
, resultField1.getText()); resultList.setListData(resultVector); resultList.repaint(); }
resultHolder.setVisible(
true
); }
if
(e.getSource().equals(saveBtn2)
||
e.getSource().equals(inputField))
{ resultHolder.setLocation(
this
.getLocation().x
+
this
.getWidth()
+
10
,
this
.getLocation().y);
if
(resultField2.getText()
!=
null
&&
resultField2.getText().length()
>
0
)
{ resultVector.add(
0
, resultField2.getText()); resultList.setListData(resultVector); resultList.repaint(); }
resultHolder.setVisible(
true
); }
if
(e.getSource().equals(clearBtn))
{ resultField1.setText(
"
0.0
"
); first
=
true
; continued
=
false
; completed
=
false
; }
if
(e.getSource().equals(backBtn))
{ String s
=
resultField1.getText();
if
(s.length()
>
0
)
{ String t
=
s.substring(
0
, s.length()
-
1
);
if
(t.length()
>
0
&&
t.charAt(t.length()
-
1
)
==
'
.
'
) t
=
t.substring(
0
, t.length()
-
1
); resultField1.setText(t); }
}
}
/** */
/**
* application entry point * *
@param
args
*/
public
static
void
main(String[] args)
{
//
TODO Auto-generated method stub
try
{ UIManager.setLookAndFeel(
new
SubstanceLookAndFeel()); UIManager.put(
"
swing.boldMetal
"
,
false
);
if
(System.getProperty(
"
substancelaf.useDecorations
"
)
==
null
)
{ JFrame.setDefaultLookAndFeelDecorated(
true
); JDialog.setDefaultLookAndFeelDecorated(
true
); }
//
System.setProperty("sun.awt.noerasebackground", "true");
SubstanceLookAndFeel.setCurrentTheme(
new
SubstancePurpleTheme()); SubstanceLookAndFeel .setCurrentWatermark(
new
SubstanceBinaryWatermark()); }
catch
(Exception e)
{ System.err.println(
"
Oops! Something went wrong!
"
); }
CalculatorFace c
=
new
CalculatorFace(); }
/** */
/**
* 处理数字按键的触发事件 * *
@author
td *
*/
private
class
NumberListener
implements
ActionListener
{
public
void
actionPerformed(ActionEvent e)
{
//
TODO Auto-generated method stub
if
(e.getSource()
instanceof
JButton)
{ String s
=
resultField1.getText(); JButton btn
=
(JButton) e.getSource(); String t
=
btn.getText();
if
(completed
||
first)
{ resultField1.setText(t); first
=
false
; }
else
{ resultField1.setText(s
+
t); }
completed
=
false
; continued
=
true
; }
}
}
/** */
/**
* 处理单操作数的运算按键触发事件(包含等号,PI,E) * *
@author
td *
*/
private
class
OneOperatorListener
implements
ActionListener
{
public
void
actionPerformed(ActionEvent e)
{
//
TODO Auto-generated method stub
errorLabel1.setText(
""
); JButton btn
=
(JButton) e.getSource(); String s
=
resultField1.getText(); String t
=
btn.getText();
if
(t.equals(
"
+/-
"
))
{
if
(completed
||
first)
{ completed
=
false
; resultField1.setText(
"
-
"
); }
}
if
(t.equals(
"
.
"
))
{
if
(completed
||
first)
{ completed
=
false
; resultField1.setText(
"
0.
"
); }
else
{
if
(s.indexOf(
"
.
"
)
==
-
1
) resultField1.setText(s
+
"
.
"
); }
}
if
(t.equals(
"
PI
"
))
{
if
(completed
||
first)
{ ; resultField1.setText(String.valueOf(Math.PI)); completed
=
false
; }
}
if
(t.equals(
"
E
"
))
{
if
(completed
||
first)
{ resultField1.setText(String.valueOf(Math.E)); completed
=
false
; }
}
if
(t.equals(
"
!
"
))
{
try
{
int
i
=
Integer.parseInt(s);
int
n
=
1
;
for
(
int
j
=
1
; j
<=
i; j
++
)
{ n
*=
j; }
resultField1.setText(String.valueOf(n)); completed
=
true
; }
catch
(NumberFormatException nfe)
{ errorLabel1.setText(
"
小数不能做阶乘运算
"
); completed
=
true
; }
}
if
(t.equals(
"
1/x
"
))
{
double
d
=
Double.parseDouble(s); resultField1.setText(String.valueOf(
1
/
d)); completed
=
true
; }
if
(t.equals(
"
ln
"
))
{
double
d
=
Double.parseDouble(s); resultField1.setText(String.valueOf(Math.log(d))); completed
=
true
; }
if
(t.equals(
"
log
"
))
{
double
d
=
Double.parseDouble(s); resultField1.setText(String.valueOf(Math.log10(d))); completed
=
true
; }
if
(t.equals(
"
sin
"
))
{
double
d
=
Double.parseDouble(s); resultField1.setText(String.valueOf(Math.sin(d))); completed
=
true
; }
if
(t.equals(
"
cos
"
))
{
double
d
=
Double.parseDouble(s); resultField1.setText(String.valueOf(Math.cos(d))); completed
=
true
; }
if
(t.equals(
"
tan
"
))
{
double
d
=
Double.parseDouble(s); resultField1.setText(String.valueOf(Math.tan(d))); completed
=
true
; }
if
(t.equals(
"
cot
"
))
{
double
d
=
Double.parseDouble(s); resultField1.setText(String.valueOf(
1
/
Math.tan(d))); completed
=
true
; }
if
(t.equals(
"
arcsin
"
))
{
double
d
=
Double.parseDouble(s); resultField1.setText(String.valueOf(Math.asin(d))); completed
=
true
; }
if
(t.equals(
"
arccos
"
))
{
double
d
=
Double.parseDouble(s); resultField1.setText(String.valueOf(Math.acos(d))); completed
=
true
; }
if
(t.equals(
"
arctan
"
))
{
double
d
=
Double.parseDouble(s); resultField1.setText(String.valueOf(Math.atan(d))); completed
=
true
; }
if
(t.equals(
"
arccot
"
))
{
double
d
=
Double.parseDouble(s); resultField1 .setText(String.valueOf(Math.PI
/
2
-
Math.atan(d))); completed
=
true
; }
if
(t.equals(
"
=
"
))
{ number1
=
number2; number2
=
resultField1.getText(); System.out.print(lastOperator);
if
(lastOperator
!=
null
) operator(lastOperator); completed
=
true
; lastOperator
=
""
; }
first
=
false
; }
}
/** */
/**
* 处理双操作数的运算按键触发事件 * *
@author
td *
*/
private
class
TwoOperatorListener
implements
ActionListener
{
public
void
actionPerformed(ActionEvent e)
{
//
TODO Auto-generated method stub
if
(continued
||
first)
{ number1
=
number2; errorLabel1.setText(
""
); JButton btn
=
(JButton) e.getSource(); String s
=
resultField1.getText(); System.err.println(s); number2
=
s; String t
=
btn.getText();
if
(lastOperator
!=
null
) operator(lastOperator); lastOperator
=
t; first
=
false
; completed
=
true
; continued
=
false
; }
else
{ JButton btn
=
(JButton) e.getSource(); String t
=
btn.getText(); lastOperator
=
t; }
}
}
/** */
/**
* 执行双操作数的运算 * *
@param
t
*/
private
void
operator(String t)
{
if
(t.equals(
"
+
"
))
{
double
a
=
Double.parseDouble(number1);
double
b
=
Double.parseDouble(number2); resultField1.setText(String.valueOf(a
+
b)); }
if
(t.equals(
"
-
"
))
{
double
a
=
Double.parseDouble(number1);
double
b
=
Double.parseDouble(number2); resultField1.setText(String.valueOf(a
-
b)); }
if
(t.equals(
"
*
"
))
{
double
a
=
Double.parseDouble(number1);
double
b
=
Double.parseDouble(number2); resultField1.setText(String.valueOf(a
*
b)); }
if
(t.equals(
"
/
"
))
{
double
a
=
Double.parseDouble(number1);
double
b
=
Double.parseDouble(number2); resultField1.setText(String.valueOf(a
/
b)); }
if
(t.equals(
"
%
"
))
{
double
a
=
Double.parseDouble(number1);
double
b
=
Double.parseDouble(number2); resultField1.setText(String.valueOf(a
%
b)); }
if
(t.equals(
"
^
"
))
{
double
a
=
Double.parseDouble(number1);
double
b
=
Double.parseDouble(number2); resultField1.setText(String.valueOf(Math.pow(a, b))); }
number2
=
resultField1.getText(); }
/** */
/**
* 处理表达式输入框回车以及确定键的触发事件,将调用Parser解析并计算表达式 *
@author
td *
*/
private
class
ParserListener
implements
ActionListener
{
public
void
actionPerformed(ActionEvent e)
{
//
TODO Auto-generated method stub
variables
=
variableArea.getText(); express
=
inputField.getText();
//
deal with variables
if
(variables
!=
null
&&
express
!=
null
)
{ String ss[]
=
variables.split(
"
,
"
);
for
(String s : ss)
{ String v[]
=
s.split(
"
=
"
);
if
(v.length
==
2
) express
=
parser.replaceExpress(express, v[
0
], getNumber(v[
1
])); }
}
try
{ result2
=
parser.entry(express); errorLabel2.setText(
""
); resultField2.setText(Double.toString(result2)); }
catch
(ParserException e1)
{
//
TODO Auto-generated catch block
errorLabel2.setText(e1.toString()); }
}
//
only get the digital part of the variables' values
public
String getNumber(String s)
{ StringBuffer sb
=
new
StringBuffer(s); StringBuffer tmp
=
new
StringBuffer();
for
(
int
i
=
0
; i
<
s.length(); i
++
)
{
if
(Character.isDigit(sb.charAt(i))
||
sb.charAt(i)
==
'
.
'
)
{ tmp.append(sb.charAt(i)); }
}
return
tmp.length()
>
0
?
tmp.toString() :
"
1
"
; }
}
}
package
cn.com.w4t.calculator;
import
java.util.ArrayList;
import
java.util.List;
/** */
/**
* Express Parser * *
@author
td *
*/
public
class
Parser
{
//
Define the end of expression
private
final
String EOE
=
"
\0
"
;
//
These are the types of tokens
private
final
int
NONE
=
0
;
private
final
int
DELIMITER
=
1
;
private
final
int
VARIABLE
=
2
;
private
final
int
NUMBER
=
3
;
//
These are the errors of SYNTAX
private
final
int
SYNTAX
=
0
;
private
final
int
UNBALPARENTH
=
1
;
private
final
int
NOEXP
=
2
;
private
final
int
DIVBYZERO
=
3
;
//
Array for variables
private
double
var[]
=
new
double
[
26
];
//
Define the variables
private
String exp;
//
Expression user entered
private
int
expIdx;
//
The index of the expression
private
int
tokType;
//
Type of the current token
private
String token;
//
The current token
private
static
List
<
String
>
operatorList;
static
{ operatorList
=
new
ArrayList
<
String
>
(); operatorList.add(
"
sin
"
); operatorList.add(
"
cos
"
); operatorList.add(
"
tan
"
); operatorList.add(
"
cot
"
); operatorList.add(
"
arcsin
"
); operatorList.add(
"
arccos
"
); operatorList.add(
"
arccot
"
); operatorList.add(
"
ln
"
); operatorList.add(
"
arctan
"
); operatorList.add(
"
log
"
); }
/** */
/**
* judge wether the token is Delimiter * *
@param
tok * the token *
@return
the judgement
*/
private
boolean
isDelim(
char
tok)
{
if
(
"
+-*/%^()
"
.indexOf(tok)
!=
-
1
)
return
true
;
return
false
; }
/** */
/**
* check the token wether a operator it is * *
@param
tok * the token *
@return
the judgement
*/
private
boolean
isOperator(String tok)
{
return
operatorList.contains(tok); }
//
The method getToken(),it can get next tokens
/** */
/**
* get the basic element of the express
*/
private
void
getToken()
{
//
System.out.println("gettoken");
token
=
""
; tokType
=
NONE;
if
(expIdx
==
exp.length())
{
//
If end of expression the token=EOE
token
=
EOE;
return
; }
while
(expIdx
<
exp.length()
&&
Character.isWhitespace(exp.charAt(expIdx)))
++
expIdx;
//
Removing the whitespace from the token
if
(expIdx
==
exp.length())
{
//
After removing,judge whether the end
//
of expression
token
=
EOE;
return
; }
if
(isDelim(exp.charAt(expIdx)))
{
//
is operator
token
=
token
+
exp.charAt(expIdx); tokType
=
DELIMITER; expIdx
++
; }
else
if
(Character.isLetter(exp.charAt(expIdx)))
{
//
is Letter
while
(
!
isDelim(exp.charAt(expIdx))
&&
Character.isLetter(exp.charAt(expIdx)))
{ token
=
token
+
exp.charAt(expIdx); expIdx
++
;
if
(expIdx
==
exp.length())
break
;
if
(isOperator(token))
break
; }
if
(isOperator(token)) tokType
=
DELIMITER;
else
{
while
(expIdx
<
exp.length()
&&
!
isDelim(exp.charAt(expIdx)))
{ token
=
token
+
exp.charAt(expIdx); expIdx
++
;
if
(expIdx
==
exp.length())
break
; }
tokType
=
VARIABLE; }
}
else
if
(Character.isDigit(exp.charAt(expIdx)))
{
//
is digital
while
(
!
isDelim(exp.charAt(expIdx)))
{ token
=
token
+
exp.charAt(expIdx); expIdx
++
;
if
(expIdx
==
exp.length())
break
; }
tokType
=
NUMBER; }
else
{ token
=
EOE;
//
end of expression
return
; }
}
private
void
handleErr(
int
error)
throws
ParserException
{ String[] err
=
{
"
表达式语法错误
"
,
"
表达式括号未平衡
"
,
"
表达式为空
"
,
"
除0错误
"
}
;
throw
new
ParserException(err[error]); }
/** */
/**
* handling errors * *
@param
error * the error *
@throws
ParserException
*/
private
void
handleErr(String error)
throws
ParserException
{
throw
new
ParserException(error); }
//
get the old token
//
private void getBack() {
//
if (token == EOE)
//
return;
//
for (int i = 0; i < token.length(); i++)
//
--expIdx;
//
}
//
The main course starts
//
The entry is the programme's entry,everything will be processed through
//
it
/** */
/**
* The entry is the programme's entry,everything will be processed through * it
*/
public
double
entry(String expstr)
throws
ParserException
{
double
result; exp
=
expstr; expIdx
=
0
; getToken();
if
(token.equals(EOE)) handleErr(NOEXP);
result
=
expCal1();
if
(
!
token.equals(EOE)) handleErr(SYNTAX);
return
result;
}
//
expCal1 process VARIABLE
private
double
expCal1()
throws
ParserException
{
return
expCal2(); }
/** */
/**
* process add and substract
*/
private
double
expCal2()
throws
ParserException
{
double
result;
char
op;
double
partialResult;
//
System.out.println("2");
result
=
expCal3();
while
((op
=
token.charAt(
0
))
==
'
+
'
||
op
==
'
-
'
)
{
//
System.out.println("2while");
getToken(); partialResult
=
expCal3();
switch
(op)
{
case
'
+
'
: result
=
result
+
partialResult;
break
;
case
'
-
'
: result
=
result
-
partialResult;
break
;
default
: handleErr(SYNTAX);
break
; }
}
return
result;
}
/** */
/**
* process multiply and divide
*/
private
double
expCal3()
throws
ParserException
{
char
op;
double
result;
double
partialResult;
//
System.out.println("3");
result
=
expCal4();
while
((op
=
token.charAt(
0
))
==
'
/
'
||
op
==
'
*
'
||
op
==
'
%
'
)
{
//
System.out.println("3while");
getToken(); partialResult
=
expCal4();
switch
(op)
{
case
'
/
'
:
if
(partialResult
==
0.0
) handleErr(DIVBYZERO); result
=
result
/
partialResult;
break
;
case
'
*
'
: result
=
result
*
partialResult;
break
;
case
'
%
'
:
if
(partialResult
==
0.0
) handleErr(DIVBYZERO); result
=
result
%
partialResult;
break
; }
}
return
result;
}
/** */
/**
* process ^ operater
*/
private
double
expCal4()
throws
ParserException
{
double
result;
double
partialResult;
double
tempRe;
//
System.out.println("4");
result
=
expCal5(); tempRe
=
result;
while
(token.charAt(
0
)
==
'
^
'
)
{ System.out.println(
"
4while
"
); getToken(); partialResult
=
expCal4();
if
(partialResult
==
0.0
) result
=
1.0
;
else
result
=
Math.pow(result, partialResult); }
return
result; }
/** */
/**
* process sin,cos,tan,cot,arcsin,arccos,arctan,arccot,log,ln
*/
private
double
expCal5()
throws
ParserException
{
double
result; String op
=
""
;
if
(tokType
==
DELIMITER
&&
(op
=
token).equals(
"
sin
"
)
||
op.equals(
"
cos
"
)
||
op.equals(
"
tan
"
)
||
op.equals(
"
cot
"
)
||
op.equals(
"
arctan
"
)
||
op.equals(
"
arccot
"
)
||
op.equals(
"
arcsin
"
)
||
op.equals(
"
arccos
"
)
||
op.equals(
"
ln
"
)
||
op.equals(
"
log
"
)) getToken(); result
=
expCal6();
if
(op.equals(
"
sin
"
)) result
=
Math.sin(result);
if
(op.equals(
"
cos
"
)) result
=
Math.cos(result);
if
(op.equals(
"
tan
"
)) result
=
Math.tan(result);
if
(op.equals(
"
cot
"
)) result
=
1
/
Math.tan(result);
if
(op.equals(
"
arcsin
"
)) result
=
Math.asin(result);
if
(op.equals(
"
arccos
"
)) result
=
Math.acos(result);
if
(op.equals(
"
arctan
"
)) result
=
Math.atan(result);
if
(op.equals(
"
arccot
"
)) result
=
Math.PI
/
2
-
Math.atan(result);
if
(op.equals(
"
ln
"
)) result
=
Math.log(result);
if
(op.equals(
"
log
"
)) result
=
Math.log10(result);
return
result; }
/** */
/**
* process unary +,-
*/
private
double
expCal6()
throws
ParserException
{
double
result; String op
=
""
;
if
(tokType
==
DELIMITER
&&
(op
=
token).equals(
"
+
"
)
||
op.equals(
"
-
"
)) getToken(); result
=
expCal7();
if
(op.equals(
"
-
"
)) result
=
-
result;
return
result; }
//
process parenthesized expression
/** */
/**
* process parenthesized expression
*/
private
double
expCal7()
throws
ParserException
{
double
result;
//
System.out.println("7");
if
(token.equals(
"
(
"
))
{
//
System.out.println("6if");
getToken(); result
=
expCal2();
if
(
!
token.equals(
"
)
"
)) handleErr(UNBALPARENTH); getToken(); }
else
if
((tokType
==
DELIMITER))
{ getToken(); result
=
expCal2(); }
else
result
=
expCal8();
//
System.err.println(result);
return
result; }
//
convert String to NUMBER
/** */
/**
* convert String to NUMBER
*/
private
double
expCal8()
throws
ParserException
{
double
result
=
0.0
;
//
System.out.println("8");
switch
(tokType)
{
case
VARIABLE: result
=
findVar(); getToken();
break
;
case
NUMBER:
try
{
char
c
=
token.charAt(token.length()
-
1
);
if
(c
==
'
!
'
)
{ String s
=
token.substring(
0
, token.length()
-
1
);
if
(s.indexOf(
"
.
"
)
!=
-
1
) handleErr(
"
只能对整数进行阶乘运算
"
);
else
{ result
=
Integer.parseInt(s);
double
n
=
1.0
;
for
(
int
i
=
1
; i
<=
result; i
++
)
{ n
=
n
*
i; }
result
=
n; }
}
else
result
=
Double.parseDouble(token); }
catch
(NumberFormatException exc)
{ handleErr(SYNTAX); }
getToken();
break
;
default
: handleErr(SYNTAX);
break
; }
return
result; }
private
double
findVar()
throws
ParserException
{
if
(
!
Character.isLetter(token.charAt(
0
)))
{ handleErr(SYNTAX);
return
0.0
; }
handleErr(token
+
"
未赋值
"
);
return
var[Character.toLowerCase(token.charAt(
0
))
-
'
a
'
];
}
/** */
/**
* replace the variable with its value * *
@param
express * the initial express *
@param
name * the variable's name *
@param
value * the variable's value *
@return
replaced express
*/
public
String replaceExpress(String express, String name, String value)
{ token
=
""
; expIdx
=
0
; exp
=
express; StringBuffer tmp
=
new
StringBuffer();
if
(express
==
null
||
express.length()
<
1
)
return
express;
while
(
!
token.equals(
"
\0
"
))
{
if
(token.length()
>
0
&&
token.charAt(token.length()
-
1
)
==
'
!
'
)
{ String s
=
token.substring(
0
, token.length()
-
1
);
if
(s.equals(name)) s
=
value; tmp.append(s); tmp.append(
"
!
"
); }
else
{
if
(token.equals(name)) token
=
value; tmp.append(token); }
getToken(); }
return
tmp.toString(); }
}
/** */
/**
* errors that occured in calculating * *
@author
td *
*/
class
ParserException
extends
Exception
{
static
final
long
serialVersionUID
=
314088734511860866L
;
private
String str;
public
ParserException(String str)
{
this
.str
=
str; }
public
String toString()
{
return
str; }
}
评论:
-
# re: 自己做的多功能计算器,嘿嘿
Posted @ 2006-11-24 19:04
顶一下先! 回复 更多评论
-
# re: 自己做的多功能计算器,嘿嘿
Posted @ 2006-11-25 12:39
界面很好看,写的不错 回复 更多评论
-
# re: 自己做的多功能计算器,嘿嘿
Posted @ 2006-11-26 21:53
恩 不错
支持一下,我以前也做过一个,不过那个和window的差不多 回复 更多评论
-
# re: 自己做的多功能计算器,嘿嘿
Posted @ 2006-11-27 17:32
还差一点就完美了:
应该写个运行该程序的 bat(windows) 和 sh(linux) 回复 更多评论
-
# re: 自己做的多功能计算器,嘿嘿
Posted @ 2006-11-27 18:48
@windows计算器坏了
写了
没提交上来,还有本地exe,呵呵 回复 更多评论
-
# re: 自己做的多功能计算器,嘿嘿
Posted @ 2007-01-24 20:07
你好,我想运行一下你的这个程序,可以提供一下下面那三个包吗
org.jvnet.substance.SubstanceLookAndFeel
org.jvnet.substance.theme.SubstancePurpleTheme
org.jvnet.substance.watermark.SubstanceBinaryWatermark 回复 更多评论
-
# re: 自己做的多功能计算器,嘿嘿
Posted @ 2007-09-10 08:41
不知道怎么运行啊 回复 更多评论
-
# re: 自己做的多功能计算器,嘿嘿
Posted @ 2007-12-27 09:01
我也在做这个,但没你那个好看,还是遇到问题了,是技术不佳,可以请教一下吗 回复 更多评论
-
# re: 自己做的多功能计算器,嘿嘿
Posted @ 2008-03-23 14:49
谢谢 回复 更多评论
-
# re: 自己做的多功能计算器,嘿嘿[未登录]
Posted @ 2008-07-06 12:14
你这程序有调试么? 回复 更多评论
|