使用JavaScript解析算术表达式(通过ScriptEngine)

使用JavaScript解析算术表达式(通过ScriptEngine),java,javascript,swing,parsing,jbutton,Java,Javascript,Swing,Parsing,Jbutton,以下是我的完整代码供参考,以防错误与所讨论的块无关: import java.awt.*; import java.awt.event.*; import javax.swing.*; import java.util.*; import javax.script.*; //Previously while debugging this, I was writing my own exception in case of an arithmetic //error. I'm trying t

以下是我的完整代码供参考,以防错误与所讨论的块无关:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import javax.script.*;

//Previously while debugging this, I was writing my own exception in case of an arithmetic
//error.  I'm trying to get it to work so my evaluation method has a catch block, which is
//necessary because the ScriptEngineManager requires it.
public class Calculator
{
    JButton button0;
    JButton button1;
    JButton button2;
    JButton button3;
    JButton button4;
    JButton button5;
    JButton button6;
    JButton button7;
    JButton button8;
    JButton button9;
    JButton buttonCE;
    JButton buttonC;

    JButton buttonPlus;
    JButton buttonMinus;
    JButton buttonTimes;
    JButton buttonDivide;

    JTextField expr;
    JButton buttonEquals;
    JTextField result;


    public Calculator()
    {
        ActionListener listener = new MyButtonListener();  //Use for ALL buttons.
        JFrame window = new JFrame("Calculator");
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        Container content;
        content = window.getContentPane();
        content.setLayout( new BorderLayout() );


        JPanel bottomPanel = new JPanel();
        JPanel topPanel = new JPanel();
        JPanel ops = new JPanel();
        ops.setLayout(new GridLayout(4,3));
        JPanel digits = new JPanel();
        digits.setLayout(new GridLayout(4,1));

        button0 = new JButton("0");  //Generate and add buttons and listeners for bottomPanel
        digits.add(button0);
        button0.addActionListener(listener);
        button1 = new JButton("1");
        digits.add(button1);
        button1.addActionListener(listener);
        button2 = new JButton("2");
        digits.add(button2);
        button2.addActionListener(listener);
        button3 = new JButton("3");
        digits.add(button3);
        button3.addActionListener(listener);
        button4 = new JButton("4");
        digits.add(button4);
        button4.addActionListener(listener);
        button5 = new JButton("5");
        digits.add(button5);
        button5.addActionListener(listener);
        button6 = new JButton("6");
        digits.add(button6);
        button6.addActionListener(listener);
        button7 = new JButton("7");
        digits.add(button7);
        button7.addActionListener(listener);
        button8 = new JButton("8");
        digits.add(button8);
        button8.addActionListener(listener);
        button9 = new JButton("9");
        digits.add(button9);
        button9.addActionListener(listener);
        buttonCE = new JButton("CE");
        digits.add(buttonCE);
        buttonCE.addActionListener(listener);
        buttonC = new JButton("C");
        digits.add(buttonC);
        buttonC.addActionListener(listener);

        buttonPlus = new JButton("+");  //Generate operations buttons and add them
        ops.add(buttonPlus);
        buttonPlus.addActionListener(listener);
        buttonMinus = new JButton("-");
        ops.add(buttonMinus);
        buttonMinus.addActionListener(listener);
        buttonTimes = new JButton("*");
        ops.add(buttonTimes);
        buttonTimes.addActionListener(listener);
        buttonDivide = new JButton("/");
        ops.add(buttonDivide);
        buttonDivide.addActionListener(listener);


        expr = new JTextField(10);  //These will go on topPanel
        topPanel.add(expr);
        buttonEquals = new JButton("=");
        topPanel.add(buttonEquals);
        result = new JTextField(6);
        topPanel.add(result);

        bottomPanel.add(digits);
        bottomPanel.add(ops);

        content.add(bottomPanel, BorderLayout.SOUTH);  //Is this why it won't put them in a frame?
        content.add(topPanel, BorderLayout.NORTH);
        window.pack();
        window.setVisible(true);
    }

    public class MyButtonListener implements ActionListener
    {
        //Random bunch of if-else if statements for what happens when you
        //push each button.
        public void actionPerformed(ActionEvent e)
        {
            if (e.getSource() == button0)
            {
                expr.setText(expr.getText() + "0");
            }
            else if (e.getSource() == button1)
            {
                expr.setText(expr.getText() + "1");
            }
            else if (e.getSource() == button2)
            {
                expr.setText(expr.getText() + "2");
            }
            else if (e.getSource() == button3)
            {
                expr.setText(expr.getText() + "3");
            }
            else if (e.getSource() == button4)
            {
                expr.setText(expr.getText() + "4");
            }
            else if (e.getSource() == button5)
            {
                expr.setText(expr.getText() + "5");
            }
            else if (e.getSource() == button6)
            {
                expr.setText(expr.getText() + "6");
            }
            else if (e.getSource() == button7)
            {
                expr.setText(expr.getText() + "7");
            }
            else if (e.getSource() == button8)
            {
                expr.setText(expr.getText() + "8");
            }
            else if (e.getSource() == button9)
            {
                expr.setText(expr.getText() + "9");
            }
            else if (e.getSource() == buttonC)
            {
                expr.setText("");
                result.setText("");
            }
            else if (e.getSource() == buttonCE)
            {
                //clearLastEntry();
            }

            else if (e.getSource() == buttonPlus)
            {
                expr.setText(expr.getText() + "+");
            }
            else if (e.getSource() == buttonMinus)
            {
                expr.setText(expr.getText() + "-");
            }
            else if (e.getSource() == buttonTimes)
            {
                expr.setText(expr.getText() + "*");
            }
            else if (e.getSource() == buttonDivide)
            {
                expr.setText(expr.getText() + "/");
            }
            else if (e.getSource() == buttonEquals)
            {
                evaluate(expr, result);
            }

        }
    }
    /*private JTextField clearLastEntry(JTextField textbox)
    {
        textbox.setText(textbox.getText().substring(0, text.length()-1)); //Delete the last character.
        String text = textbox.getText();
        if (!(text.charAt(text.length()-1) == '+' || 
            text.charAt(text.length()-1) == '-' || 
            text.charAt(text.length()-1) == '*' ||
            text.charAt(text.length()-1) == '/')) return textbox;
        return clearLastEntry(textbox);
    }*/
    private void evaluate(JTextField expr, JTextField result)
    {
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName("JavaScript");
        /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
        //~~~Below is JavaScript code that will be run in Java.~~~~~
        //~~~It must be stored as a pure Object and manually ~~~~~~~
        //~~~converted to a String so it can be stored.  It ~~~~~~~~
        //~~~parses the arithmetic automatically, vastly ~~~~~~~~~~~
        //~~~simplifying the amount of code needed to be written. ~~
        /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

        try
        {
            Object textboxText = engine.eval(expr.getText());  //Store text as a pure object
            result.setText(textboxText.toString());
            expr.setText("");  //Blank out the text box.
        }
        catch (ScriptException e)
        {
            result.setText("Err");
            expr.setText("");
        }
    }

    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    //~The parsing method will throw the following~~//
    //~custom exception if the user does not input~~//
    //~~~~~~~~~~~valid calculator input.~~~~~~~~~~~~//

    /*private class TextNotArithmetic extends Exception
    {
        private TextNotArithmetic(JTextField textbox)  
        {
            char testChar;
            for (int i=0; i<textbox.getText().length()-1; i++)
            {
                testChar=textbox.getText().charAt(i);
                if (!(Character.isDigit(testChar) || testChar=='+' || testChar=='-' || 
                    testChar=='*' || testChar=='/'))  //if the character isn't valid
                {
                    throw new TextNotArithmetic();
                }
            }
        }
    }*/

    public static void main(String[] args)
    {
        new Calculator();
    }

你可以忽略我的大部分评论,因为其中一些已经过时了,但是现在,我的代码已经编译了,但是我的结果框中没有任何内容。另外,由于我以电子方式提交此文件,并且将在服务器上对其进行评估,因此请不要对安装其他软件包提出任何建议。我觉得Rhino应该足够了,尽管我讨厌eval,但这似乎是唯一的方法,除非你们有其他建议。谢谢大家!

我现在还不清楚问题出在哪里。但是有一件事你肯定做错了,那就是让问题更难解决。。。除非你改变它

catch (ScriptException e)
    {
        result.setText("Err");
        expr.setText("");
    }

这是没有帮助的。如果发生脚本异常,您将捕获它,并丢弃所有有关出错原因的信息。至少,您应该在某个地方打印或记录异常stacktrace。

我不清楚问题出在哪里。但是有一件事你肯定做错了,那就是让问题更难解决。。。除非你改变它

catch (ScriptException e)
    {
        result.setText("Err");
        expr.setText("");
    }
    buttonEquals = new JButton("=");
    topPanel.add(buttonEquals);
这是没有帮助的。如果发生脚本异常,您将捕获它,并丢弃所有有关出错原因的信息。至少,您应该在某处打印或记录异常stacktrace

    buttonEquals = new JButton("=");
    topPanel.add(buttonEquals);
应该是:

    buttonEquals = new JButton("=");
    buttonEquals.addActionListener(listener);  // add the listener!
    topPanel.add(buttonEquals);
其他提示 更改以下内容的所有实例: 如果e.getSource==按钮9,则为else 到 否则,如果e.getSource.equalsbutton9//最好使用该方法进行比较

另请参阅使用的工作,它使用一些技巧将260 LOC压缩到约260 LOC,例如,提供的代码仅为141 LOC。它通过使用循环来创建按钮来实现这一点,主要是通过直接使用按钮的动作命令来添加到输入中

应该是:

    buttonEquals = new JButton("=");
    buttonEquals.addActionListener(listener);  // add the listener!
    topPanel.add(buttonEquals);
其他提示 更改以下内容的所有实例: 如果e.getSource==按钮9,则为else 到 否则,如果e.getSource.equalsbutton9//最好使用该方法进行比较

另请参阅使用的工作,它使用一些技巧将260 LOC压缩到约260 LOC,例如,提供的代码仅为141 LOC。它通过使用循环来创建按钮来实现这一点,主要是通过直接使用按钮的动作命令来添加到输入中


使用。谢谢!唯一的问题是,这似乎正是我所拥有的,只是他在别处声明了ScriptEngine和ScriptEngineManager。。正如StephenC所建议的,将catch Exception e{..形式的代码更改为catch Exception e{e.printStackTrace;//非常有用!。安德鲁,你的代码运行得很好,我得到了一个函数计算器应用程序。现在,我的结果字段是空的。我更改了捕获,但仍然没有得到任何输出。使用。e.G..谢谢!唯一的问题是,这似乎正是我拥有的,只是他声明了脚本引擎和脚本“他”是“我”…正如StephenC所建议的那样-将形式为catch Exception e{..的代码更改为catch Exception e{e.printStackTrace;//非常有用!。Andrew,你的代码运行得很好,我得到了一个函数计算器应用程序。现在,我的结果字段为空。我更改了捕获,但仍然没有得到任何输出。谢谢!我刚刚将捕获块更改为:catch scripte{e.printStackTrace;//result.settexter;//expr.setText;}但是我还是遇到了同样的错误。//result.settexter;除了调用printStackTrace之外,做这些事情没有什么坏处,或者日志记录只是对任何现有用户反馈的一个很好的补充。尽管您可以尝试使用setTexte.getMessage来快速警告除法0错误……谢谢!我刚刚更改了catch块到:捕获脚本异常e{e.printStackTrace;//result.settexter;//expr.setText;}但是我还是遇到了同样的错误。//result.settexter;除了调用printStackTrace之外,执行这些操作并没有什么坏处,日志记录只是对任何现有用户反馈的一个很好的补充。尽管您可以尝试使用setTexte.getMessage来快速警告除数为0的错误……这就是问题所在。它总是看起来很明显是这样的。谢谢!它现在运行良好。另请参阅编辑。其中包括有关为什么您的代码(本质上与我的代码相同)可以从260->140位置缩减的提示。这就是问题所在。它似乎总是很明显。谢谢!它现在运行良好。另请参阅编辑。其中包括关于为什么的提示您的代码基本上与我的代码相同,可以从260->140位置缩小: