dyerac  
dyerac In Java
公告

日历
<2006年11月>
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789
统计
  • 随笔 - 36
  • 文章 - 10
  • 评论 - 94
  • 引用 - 0

导航

常用链接

留言簿(5)

随笔分类(49)

随笔档案(36)

文章分类(11)

文章档案(10)

相册

dyerac

搜索

  •  

积分与排名

  • 积分 - 78759
  • 排名 - 706

最新随笔

最新评论

阅读排行榜

评论排行榜

 

   有感于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;
    }

}
posted on 2006-11-24 18:24 dyerac in java... 阅读(4586) 评论(10)  编辑  收藏 所属分类: 原创文章JavaSE
评论:
  • # re: 自己做的多功能计算器,嘿嘿  BeanSoft[匿名] Posted @ 2006-11-24 19:04
    顶一下先!  回复  更多评论   

  • # re: 自己做的多功能计算器,嘿嘿  dennis Posted @ 2006-11-25 12:39
    界面很好看,写的不错  回复  更多评论   

  • # re: 自己做的多功能计算器,嘿嘿  soddabao Posted @ 2006-11-26 21:53
    恩 不错
    支持一下,我以前也做过一个,不过那个和window的差不多  回复  更多评论   

  • # re: 自己做的多功能计算器,嘿嘿  windows计算器坏了 Posted @ 2006-11-27 17:32
    还差一点就完美了:
    应该写个运行该程序的 bat(windows) 和 sh(linux)  回复  更多评论   

  • # re: 自己做的多功能计算器,嘿嘿  dyerac in java... 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: 自己做的多功能计算器,嘿嘿  beichunbo Posted @ 2007-12-27 09:01
    我也在做这个,但没你那个好看,还是遇到问题了,是技术不佳,可以请教一下吗  回复  更多评论   

  • # re: 自己做的多功能计算器,嘿嘿  jurgis Posted @ 2008-03-23 14:49
    谢谢  回复  更多评论   

  • # re: 自己做的多功能计算器,嘿嘿[未登录]  毛毛 Posted @ 2008-07-06 12:14
    你这程序有调试么?  回复  更多评论   


只有注册用户登录后才能发表评论。


网站导航:
 
 
Copyright © dyerac in java... Powered by: 博客园 模板提供:沪江博客