java - 如何拆分计算器类?

标签 java swing class oop hierarchy

我用 java 编程已经有大约 4 - 5 个月了,我没有什么可提示的。这很棒。虽然我仍处于学习阶段,但就我投入的时间而言,我已经取得了很大的进步。

好的,我已经创建了一个计算器类。通常,我会非常巧妙地使用多态性(OO)并尝试尽可能地创建相关的类。

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

即:我想做的是,制作一个 Calculator 类、一个 ButtonHandler 类和一个 ActionListener 类,为了不写那么多 Operaants,我还想要一个 ScriptEngineManager 类(js)。

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

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)

但我觉得这很奇怪,因为我使用了“implements ActionListener”并且还使用了“extends Calculator”

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

如果有人可以告诉我如何将此 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;
                }


                }

最佳答案

你对继承的理解都是错误的

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 因为 FooFooBoo code> 类Bar 类中的 FooBoo 相同。它们绝不是同一个引用。 Bar 实例中的 FooBoo 从未初始化过。

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

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

因此,您将 FooFooBoo 的引用传递给 Bar。那么它就是同一个引用的 FooBoo 对象。请注意,我没有使 Bar 扩展 Foo。这不是继承的正确用法。

关于java - 如何拆分计算器类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25688330/

相关文章:

java - 通过java运行批处理文件

java - 此正则表达式错误 : var worksheet = (. *)\\};

java - 限制JToggleButton的选中数量

c# - "Special Class"到底是什么?

java - 为什么mysql表中的所有记录都被删除了?

java - Netbeans 文件路径

java - JInternalFrame 不会出现在我的屏幕上

java - 如何在扩展 JPanel 的类中添加用于加载/保存文件的菜单栏?

Python;如何将方法导入类 'pluginstyle' ?

python : How to create a dynamic list of class values