1

Here's my complete code for reference, in case the error has nothing to do with the block in question:

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();
    }

And here's the block I'm asking about:

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("");
        }
    }

You can ignore most of my comments as some of them are outdated, but right now, my code compiles, but I don't get anything in my results box. Also, because I'm handing this in electronically and it'll be evaluated on a server, please do not make any suggestions to install additional packages. I figure Rhino should be enough, and as much as I hate eval, it seems to be the only way to do this, unless you guys have any other suggestions. Thank you!

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
Brandon Sherman
  • 673
  • 1
  • 8
  • 25
  • 1
    Use the [`ScriptEngine`](http://download.oracle.com/javase/7/docs/api/javax/script/ScriptEngine.html). E.G. [here](http://stackoverflow.com/questions/7441625/how-to-find-a-button-source-in-awt-calculator-homework/7441804#7441804). – Andrew Thompson Jul 05 '13 at 02:18
  • Thanks! The only thing is that seems to be exactly what I have, only he declares the ScriptEngine and ScriptEngineManager elsewhere. – Brandon Sherman Jul 05 '13 at 02:29
  • 'he' being 'me'.. As suggested by StephenC - Change code of the form `catch (Exception e) { ..` to `catch (Exception e) { e.printStackTrace(); // very informative! ..` – Andrew Thompson Jul 05 '13 at 02:31
  • Andrew, your code worked perfectly and I got a functional calculator app. It's just right now, my result field is blank. – Brandon Sherman Jul 05 '13 at 02:42
  • I changed the catch, but I'm still not getting any output. – Brandon Sherman Jul 05 '13 at 02:47

2 Answers2

3
    buttonEquals = new JButton("=");
    topPanel.add(buttonEquals);

Should be:

    buttonEquals = new JButton("=");
    buttonEquals.addActionListener(listener);  // add the listener!
    topPanel.add(buttonEquals);

Other tips

  • Change all instances of:
    else if (e.getSource() == button9)
    to
    else if (e.getSource().equals(button9)) // better compare using the method

  • See also this working example of using the ScriptEngine which uses some tricks to shrink around 260 LOC (e.g. the supplied code) to just 141 LOC. It does this by using loops to create the buttons, and (mostly) by using the button's action command directly (to add to the input).

Community
  • 1
  • 1
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
2

It is not immediately obvious to me what the problem is. But there is one thing you are definitely doing wrong that is going to make it harder to solve the problem ... unless you change it.

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

This is not helpful. If a scripting exception occurs, you are catching it, throwing away all the information about what went wrong. At the very least, you should print or log an exception stacktrace somewhere.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • Thanks! I just changed that catch block to: catch (ScriptException e) { e.printStackTrace(); //result.setText("Err"); //expr.setText(""); } But I'm still getting the same error. – Brandon Sherman Jul 05 '13 at 02:38
  • `//result.setText("Err");` There is no harm in doing those things *in addition* to calling `printStackTrace()` that (or logging) is simply a good addition to any existing user feed-back. Though you might experiment with `setText(e.getMessage())` for quick warning of things like divide by 0 error.. – Andrew Thompson Jul 05 '13 at 03:35