如何拆分计算器类?

时间:2014-09-05 14:35:20

标签: java swing class oop hierarchy

我已经用java编程了大约4-5个月了,我没有什么可抱怨的。这很棒。虽然我还在学习阶段,但是我已经走了很长一段时间,我投入了很多时间。

好的,我做了一个计算器课程。通常,我使用多态(OO)非常巧妙地工作,并尝试尽可能地制作相关的课程。

只有这一次,当我将Calculator类分成不同的类时,我遇到了Calculator计算器按钮的问题。

即。 :我想要做的是,创建一个Calculator类,一个ButtonHandler类和一个ActionListener类,并且不要编写太多的Opera,我也想要一个ScriptEngineManager类(js)。

但是当我将Calculator java类分成这些类时,按钮不会反应,我得到:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    at calc_758D6.NumButtonActionListener.actionPerformed(NumButtonActionListener.java:29)
    at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2022)
    at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2346)
    at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)
    at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
    at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252)
    at java.awt.Component.processMouseEvent(Component.java:6527)
    at javax.swing.JComponent.processMouseEvent(JComponent.java:3321)
    at java.awt.Component.processEvent(Component.java:6292)
    at java.awt.Container.processEvent(Container.java:2234)
    at java.awt.Component.dispatchEventImpl(Component.java:4883)
    at java.awt.Container.dispatchEventImpl(Container.java:2292)
    at java.awt.Component.dispatchEvent(Component.java:4705)
    at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4898)
    at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4533)
    at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4462)
    at java.awt.Container.dispatchEventImpl(Container.java:2278)
    at java.awt.Window.dispatchEventImpl(Window.java:2739)
    at java.awt.Component.dispatchEvent(Component.java:4705)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:746)
    at java.awt.EventQueue.access$400(EventQueue.java:97)
    at java.awt.EventQueue$3.run(EventQueue.java:697)
    at java.awt.EventQueue$3.run(EventQueue.java:691)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:75)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:86)
    at java.awt.EventQueue$4.run(EventQueue.java:719)
    at java.awt.EventQueue$4.run(EventQueue.java:717)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:75)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:716)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)

但是我发现这很奇怪,因为我使用了'实现ActionListener'而且我也使用了'扩展计算器'

所以对象应该正确链接,才能正常工作,对吧?

如果有人可以告诉我如何将这个Calculator类分成不同的类,那就太棒了。

这是我的代码:

            package calculator;

            import java.awt.BorderLayout;
            import java.awt.Container;
            import java.awt.ComponentOrientation;
            import java.awt.Dimension;
            import java.awt.FlowLayout;
            import java.awt.GridLayout;
            import java.awt.Insets;
            import java.awt.event.ActionEvent;
            import java.awt.event.ActionListener;
            import javax.script.ScriptEngine;
            import javax.script.ScriptEngineManager;
            import javax.script.ScriptException;
            import javax.swing.BorderFactory;
            import javax.swing.JApplet;
            import javax.swing.JButton;
            import javax.swing.JComponent;
            import javax.swing.JFrame;
            import javax.swing.JTextField;
            import javax.swing.JLabel;
            import javax.swing.JOptionPane;
            import javax.swing.JPanel;
            import javax.swing.border.EmptyBorder;


            public class Calculator extends JApplet {


                // ;which is used during deserialization to verify that the sender and receiver of a serialized object have loaded classes for that object that are compatible with respect to serialization.
                public static final long serialVersionUID = 1;
                // boolean  A flag whether the text in the antwoordCalculatieEntryfield is the result of a calculation
                private boolean antwoordCalculatieEntryfield;
                //Container  The container of our app
                private Container con;
                //JPanel  The 'root' panel
                private JPanel panel;
                //JTextField  The field in which the calculations are created
                private JTextField entryField;
                //double  Memory
                private double defaultMemory = 0;
                //new
                private  Menu editDropDownMenu;
                private Menu viewDropDownMenu;
                private Menu helpDropDownMenu;
                private MenuBar menuBalk;
                private MenuItem optie1, optie2, optie3;
                private MenuItem viewOptie1, viewOptie2;
                private MenuItem helpOptie;

                /**
                 * This method is called when the app is an applet
                 * This will prepare for the app being used as an in-browser applet
                 */
                public void init() {
                    this.con = getContentPane();

                    createGUI();
                }

                /**
                 * This method is called when the app is started from the jar file
                 * This will prepare the app for being used as a standalone application
                 */
                public void go() {
                    // Create a frame and set the container
                    JFrame frame = new JFrame();
                    menuBalk = new MenuBar();
                    editDropDownMenu = new Menu ("Edit");
                    viewDropDownMenu = new Menu ("View");
                    helpDropDownMenu = new Menu ("Help");


                    this.con = frame.getContentPane();

                    // Build the GUI
                    createGUI();

                    frame.setLocation(400,400);
                    frame.setResizable(false);
                    frame.setMenuBar(menuBalk);
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setSize(300, 250);
                    frame.setVisible(true);

                }

                /**
                 * Create the GUI
                 */
                private void createGUI() {
                    panel = new JPanel(new BorderLayout());

                    entryField = new JTextField("0.");
                    panel.add(entryField, BorderLayout.NORTH);

                    JPanel buttonPanel = new JPanel(new BorderLayout(10,0));

                    // Build the different panels
                    buttonPanel.add(buildNorthPanel(), BorderLayout.NORTH);
                    buttonPanel.add(buildWestPanel(),  BorderLayout.WEST);
                    buttonPanel.add(buildNumPanel(),   BorderLayout.CENTER);

                    panel.add(buttonPanel, BorderLayout.CENTER);
                    con.add(panel);

                    /**
                     * De menubalk componenten realiseren en benoemen.
                     */
                    optie1 = new MenuItem(" Copy ");
                    optie2 = new MenuItem(" Paste ");
                    optie3 = new MenuItem(" Quit  ");
                    viewOptie1 = new MenuItem("Default");
                    viewOptie2 = new MenuItem("Scientific");
                    helpOptie = new MenuItem("Info");

                    /**
                     * Toevoegen van edit/view/help componenten aan de menus.
                     */
                    editDropDownMenu.add(optie1);
                    editDropDownMenu.add(optie2);
                    editDropDownMenu.addSeparator();
                    editDropDownMenu.add(optie3);
                    viewDropDownMenu.add(viewOptie1);
                    viewDropDownMenu.add(viewOptie2);
                    helpDropDownMenu.add(helpOptie);

                    /**
                     * aan het menubalkje de edit/view/help dropdown opties toevoegen.
                     */
                    menuBalk.add(editDropDownMenu);
                    menuBalk.add(viewDropDownMenu);
                    menuBalk.add(helpDropDownMenu);


                /**
                 * Build the northPanel
                 *
                 * @return  JPanel  The created panel
                 */
                private JPanel buildNorthPanel() {
                    JPanel p = new JPanel(new FlowLayout(FlowLayout.RIGHT));

                    // We have a placeholder on the top right
                    JPanel placeHolder = new JPanel();
                    placeHolder.setPreferredSize(new Dimension(BUTTON_HEIGHT, BUTTON_HEIGHT));
                    placeHolder.setBorder(BorderFactory.createLoweredBevelBorder());
                    p.add(placeHolder);

                    createNorthButton("Backspace", p).addActionListener(new BackspaceActionListener());
                    createNorthButton("CE", p).addActionListener(new CEActionListener());
                    createNorthButton("C", p).addActionListener(new CActionListener());

                    return p;
                }

                /**
                 * Build the westPanel
                 *
                 * @return  JPanel  The created panel
                 */
                private JPanel buildWestPanel() {
                    JPanel p = new JPanel(new GridLayout(4, 1, 5, 5));
                    p.setBorder(new EmptyBorder(0, 3, 3, 0));

                    createWestButton("MC", p);
                    createWestButton("MR", p);
                    createWestButton("MS", p);
                    createWestButton("M+", p);

                    return p;
                }

                /**
                 * Build the numPanel
                 *
                 * @return  JPanel  The created panel
                 */
                private JPanel buildNumPanel() {
                    JPanel p = new JPanel(new GridLayout(4, 5, 5, 5));
                    p.setBorder(new EmptyBorder(0, 0, 4, 4));

                    createNumButton("7", p);
                    createNumButton("8", p);
                    createNumButton("9", p);
                    createNumButton("/", p);
                    createNumButton("sqrt", p);

                    createNumButton("4", p);
                    createNumButton("5", p);
                    createNumButton("6", p);
                    createNumButton("*", p);
                    createNumButton("%", p);

                    createNumButton("1", p);
                    createNumButton("2", p);
                    createNumButton("3", p);
                    createNumButton("-", p);
                    createNumButton("1/x", p);

                    createNumButton("0", p);
                    createNumButton("+/-", p);
                    createNumButton(",", p);
                    createNumButton("+", p);
                    createNumButton("=", p);

                    return p;
                }

                /**
                 * Calculate the result from a string containing a calculation
                 */
                public double calcResult(String text) {
                    // We use the build-in JavaScript engine to calculate the result
                    // this saves us a lot of weird conversions and complex calculations
                    ScriptEngineManager sem = new ScriptEngineManager();
                    ScriptEngine engine = sem.getEngineByName("JavaScript");

                    // Do some pre processing to allow javascript to do something with it
                    text = text.replace("sqrt(", "Math.sqrt(");

                    try {
                        return (double) engine.eval(text);
                    } catch (ScriptException e) {
                        JOptionPane.showMessageDialog(null, "Er was een probleem met het evalueren van uw input", "foutmelding", JOptionPane.ERROR_MESSAGE);
                    }

                    return 0.0;
                }

                /**
                 * This will run when the application is run from the jar file
                 *
                 * @param  args  Arguments
                 */
                public static void main(String[] args) {
                    Calculator app = new Calculator();
                    app.go();
                }

                /**
                 * Create a button
                 *
                 * @param   String   Contents
                 * @param   JPanel   The panel to add
                 * @return  JButton  The created button
                 */
                private JButton createButton(String contents, JPanel p) {
                    JButton b = new JButton(contents);
                    b.setMargin(new Insets(0,0,0,0));
                    p.add(b);

                    return b;
                }

                /**
                 * Create a button for the NumPanel
                 *
                 * @param   String   Contents
                 * @param   JPanel   The panel to add
                 * @return  JButton  The created button
                 */
                private JButton createNumButton(String contents, JPanel p) {
                    JButton b = createButton(contents, p);
                    b.setPreferredSize(new Dimension(BUTTON_HEIGHT, BUTTON_HEIGHT));
                    b.addActionListener(new NumButtonActionListener());

                    return b;
                }

                /**
                 * Create a button for the WestPanel
                 *
                 * @param   String   Contents
                 * @param   JPanel   The panel to add
                 * @return  JButton  The created button
                 */
                private JButton createWestButton(String contents, JPanel p) {
                    JButton b = createButton(contents, p);
                    b.setPreferredSize(new Dimension(BUTTON_HEIGHT, BUTTON_HEIGHT));
                    b.addActionListener(new MemoryActionListener());

                    return b;
                }

                /**
                 * Create a button for the NorthPanel
                 *
                 * @param   String   Contents
                 * @param   JPanel   The panel to add
                 * @return  JButton  The created button
                 */
                private JButton createNorthButton(String contents, JPanel p) {
                    JButton b = createButton(contents, p);
                    b.setPreferredSize(new Dimension(100, BUTTON_HEIGHT));

                    return b;
                }

                /**
                 * Check if string b is a number
                 *
                 * @param   String   The string to check
                 * @return  boolean  String is a number or not
                 */
                public boolean isNumber(String b) {
                    try {
                        Double.parseDouble(b);
                    } catch(NumberFormatException ex) {
                        return false;
                    }

                    return true;
                }

                /**
                 * This class handles the buttons in the 'numPanel'
                 */
                class NumButtonActionListener implements ActionListener {
                    /**
                     * Responds to a click on the button
                     *
                     * @param  ActionEvent  The event object
                     */
                    public void actionPerformed(ActionEvent ev) {
                        JButton source    = (JButton) ev.getSource();
                        String sourceText = source.getText();
                        String origText   = calcField.getText();

                        String textToAdd = "";

                        // If the text equals the default text, clear it
                        if(origText.equals(DEFAULT_TEXT)) {
                            calcField.setText("");
                        }

                        // If you just calculated something and wish to use the result
                        // we don't want to clear the text for you, the text should only
                        // be cleared when you enter a new number
                        if (fieldIsResult && isNumber(sourceText)) {
                            calcField.setText("");
                            fieldIsResult = false;
                        } else {
                            fieldIsResult = false;
                        }

                        // Some buttons have special uses
                        if(sourceText.equals("=")) { // Calculate the result
                            calcField.setText(""+calcResult(calcField.getText()));
                            fieldIsResult = true;
                        } else if(sourceText.equals("sqrt")) { // Square root needs a '('
                            textToAdd = "sqrt(";
                        } else if(sourceText.equals("+/-") && origText.length() > 0) { // Toggle negative/non-negative number
                            char firstChar = origText.charAt(0);
                            if(firstChar == '-') {
                                calcField.setText(origText.substring(1, origText.length()));
                            } else {
                                calcField.setText("-"+origText);
                            }
                        } else { // Just append the button text
                            textToAdd = sourceText;
                        }

                        if( ! textToAdd.equals("")) { // If there is something that needs to be appended
                            calcField.setText(calcField.getText() + textToAdd);
                        }
                    }
                }

                /**
                 * This class handles the backspace button
                 */
                class BackspaceActionListener implements ActionListener {
                    /**
                     * Responds to a click on the button
                     *
                     * @param  ActionEvent  The event object
                     */
                    public void actionPerformed(ActionEvent ev) {
                        String newText = calcField.getText();

                        // If there are characters
                        if(newText.length() > 0) {
                            // Remove the last one
                            newText = newText.substring(0, newText.length() - 1);
                        }

                        calcField.setText(newText);
                    }
                }

                /**
                 * This class handles the C button
                 */
                class CActionListener implements ActionListener {
                    /**
                     * Responds to a click on the button
                     *
                     * @param  ActionEvent  The event object
                     */
                    public void actionPerformed(ActionEvent ev) {
                        // C will simply clear the field
                        calcField.setText("");
                    }
                }

                /**
                 * This class handles the CE button
                 */
                class CEActionListener implements ActionListener {
                    /**
                     * Responds to a click on the button
                     *
                     * @param  ActionEvent  The event object
                     */
                    public void actionPerformed(ActionEvent ev) {
                        // C will simply clear the field
                        String newText = calcField.getText().replaceAll("[0-9]+$", "");
                        calcField.setText(newText);
                    }
                }

                /**
                 * This class handles all the memory actions
                 */
                class MemoryActionListener implements ActionListener {
                    /**
                     * Respons to a click on the button
                     *
                     * @param  ActionEvent  The event object
                     */
                    public void actionPerformed(ActionEvent ev) {
                        JButton source    = (JButton) ev.getSource();
                        String sourceText = source.getText();

                        if(sourceText.equals("MC")) {
                            memory = 0.0; // Clear memory
                        } else if (sourceText.equals("MR")) {
                            calcField.setText(""+memory);
                            fieldIsResult = true;
                        } else if (sourceText.equals("MS") && fieldIsResult) {
                            memory = Double.parseDouble(calcField.getText());
                        } else if (sourceText.equals("M+") && fieldIsResult) {
                            memory = calcResult(memory+"+"+calcField.getText());
                        }
                    }
                }
            }

当我将它分开时,这就是类'NumButtonActionListener'的样子。

public class NumButtonActionListener extends Calculator implements ActionListener {

                // boolean  A flag whether the text in the antwoordCalculatieEntryfield is the result of a calculation
                private boolean antwoordCalculatieEntryfield;
                 //JTextField  The field in which the calculations are created
                private JTextField entryField;


                /**
                 * Responds to a click on the button
                 *
                 * @param  ActionEvent  The event object
                 */

//line 25
                public void actionPerformed(ActionEvent ev) {
                    JButton source    = (JButton) ev.getSource();
                    String sourceText = source.getText();
//line 29
                    String origText   = entryField.getText();

                    String textToAdd = "";

                    // If the text equals the default text, clear it
                    if(origText.equals("0.")) {
                        entryField.setText("");
                    }

                    // If you just calculated something and wish to use the result
                    // we don't want to clear the text for you, the text should only
                    // be cleared when you enter a new number
                    if (antwoordCalculatieEntryfield && isNumber(sourceText)) {
                        entryField.setText("");
                        antwoordCalculatieEntryfield = false;
                    } else {
                        antwoordCalculatieEntryfield = false;
                    }

                    // Some buttons have special uses
                    if(sourceText.equals("=")) { // Calculate the result
                        entryField.setText(""+calcResult(entryField.getText()));
                        antwoordCalculatieEntryfield = true;
                    } else if(sourceText.equals("sqrt")) { // Square root needs a '('
                        textToAdd = "sqrt(";
                    } else if(sourceText.equals("+/-") && origText.length() > 0) { // Toggle negative/non-negative number
                        char firstChar = origText.charAt(0);
                        if(firstChar == '-') {
                            entryField.setText(origText.substring(1, origText.length()));
                        } else {
                            entryField.setText("-"+origText);
                        }
                    } else { // Just append the button text
                        textToAdd = sourceText;
                    }

                    if( ! textToAdd.equals("")) { // If there is something that needs to be appended
                        entryField.setText(entryField.getText() + textToAdd);
                    }

                }

                /**
                 * Check if string b is a number
                 *
                 * @param   b   The string to check
                 * @return  boolean  String is a number or not
                 */
                public boolean isNumber(String b) {
                    try {
                        Double.parseDouble(b);
                    } catch(NumberFormatException ex) {
                        return false;
                    }

                    return true;
                }

                /**
                 * Calculate the result from a string containing a calculation
                 */
                public double calcResult(String text) {
                    // We use the build-in JavaScript engine to calculate the result
                    // this saves us a lot of weird conversions and complex calculations
                    ScriptEngineManager sem = new ScriptEngineManager();
                    ScriptEngine engine = sem.getEngineByName("JavaScript");

                    // Do some pre processing to allow javascript to do something with it
                    text = text.replace("sqrt(", "Math.sqrt(");

                    try {
                        return (double) engine.eval(text);
                    } catch (ScriptException e) {
                        JOptionPane.showMessageDialog(null, "Er was een probleem met het evalueren van uw input", "foutmelding", JOptionPane.ERROR_MESSAGE);
                    }

                    return 0.0;
                }


                }

1 个答案:

答案 0 :(得分:1)

您对继承的理解是错误的

NumButtonActionListener extends Calculator

考虑以下示例:

public class Foo {
    FooBoo foofoo;

    public Foo() {
        foofoo = new FooBoo();
        Bar bar = new Bar();
    }
}

public class Bar extends Foo {
    public Bar() {
        someMethod();
    }
    void someMethod() {
        foofoo.method();
    }
}

当您创建实例new Bar()时,这将导致NullPointerException,因为FooBoo类的Foo 相同{ {1}}中的{1}}。它们绝不是相同的参考。 FooBoo实例中的Bar从未初始化。

您需要完成太多代码,因此我不会尝试修复您的代码。但我会告诉你如何解决这个问题。为了让FooBoo使用相同的 Bar对象作为Bar中的对象,它需要对它进行引用。一种方法是简单地将它传递给它的构造函数。像

这样的东西
FooBoo

因此,您将Foo的{​​{1}}引用传递给public class Foo { FooBoo foofoo; public Foo() { foofoo = new FooBoo(); Bar bar = new Bar(foofoo); } } public class Bar { FooBoo foo; public Bar(FooBoo foo) { this.foo = foo; someMethod(); } void someMethod() { foo.method(); } } 。然后它是相同的引用Foo对象。请注意我没有FooBoo扩展Bar。这不是对继承的正确使用。