Java - Separate Listener Class抛出NullPointerException

时间:2013-09-04 02:50:07

标签: java swing nullpointerexception actionlistener

为长篇文章道歉,但我希望尽可能详细,以便人们更好地理解我要传达的内容:

好的,所以这个问题的概述是我正在尝试制作一个模拟收银机的程序。 (这是一个“有趣”的项目)。我设置的方式是:

CashRegister:启动程序的主类,作为一切的主窗口。

public class CashRegister extends JFrame {
    ...
}

其他类:用作提供主CashRegister窗口的不同组件的JPanel。例如:

public class NorthPanel extends JPanel {
    ...
}

然后在CashRegister类中:

add(new NorthPanel(), BorderLayout.NORTH);

等。 基本上,我在NorthPanel类中有一个名为priceField的JTextField,它保存用户输入的价格值。我有一个单独的类(键盘),它也扩展了JPanel,并作为主窗口中心的数字键盘。在CashRegister中:

add(new NorthPanel(), BorderLayout.NORTH);
add(new Keypad()); // (default for BorderLayout is CENTER)

我遇到的一个问题是我创建了一个类EventHandler作为整个程序的监听器类,因为每个JPanel类(例如NorthPanel和Keypad)中都有需要通信的组件彼此;用户按下键盘按钮,NorthPanel中的价格字段需要知道按键盘上的键是什么。

我不知道问题是否来自这些组件来自不同类别的事实,因此被不同地引用,或者是什么。所有类都在同一个目录中,我使用的是NetBeans,它们都属于同一个包。

在我的EventHandler类中,我创建了几个不同的构造函数,以便能够传递需要从不同类中相互通信的所有组件。例如:

public class EventHandler implements ActionListener {
    private JTextField priceField;
    private JButton[][] keypad;

    public EventHandler(JTextField priceField) {
        this.priceField = priceField;
    }

    public EventHandler(JButton[][] keypad) {
        this.keypad = keypad;
    }
}

在我的NorthPanel类中,我首先实例化priceField,配置它(设置字体等)并说:

EventHandler e = new EventHandler(priceField);

我尝试将priceField传递给我的侦听器类。

然后在键盘课上,我说:

EventHandler e = new EventHandler(keypad);
for(int i = 0; i < 4; i++) {
    for(int j = 0; j < 3; j++) {
        keypad[i][j].addActionListener(e);
    }
}

然后在EventHandler类中,传递了这些变量:

public void actionPerformed(ActionEvent e) {
    for(int i = 0; i < 4; i++) {
        for(int j = 0; j < 3; j++) {
            if(keypad[i][j] == e.getSource()) {
                // call a custom method to append the numbers to the text field
            }
        }
    }
}

正是在这一点上,我得到了一个N​​ullPointerException。我不知道为什么,但我的猜测是因为监听器对象来自不同的类并使用不同的构造函数,因为我必须从每个需要相互通信的类传入不同的对象。我不是百分百肯定的。有办法解决这个问题,还是我做错了什么?

1 个答案:

答案 0 :(得分:0)

您应该让 CashRegister 处理所有用户输入,因为它是您应用程序的主框架(它扩展了 JFrame )。对于子面板,在您覆盖的keyPressed方法体内创建一个方法,例如 aKeyWasPressed(int keyCode),它将从您的帧中调用。

此外,将JFrame设置为可聚焦,最好使其他面板无法聚焦setFocusable(false);

以下是 CashRegister 的示例代码:

public class CashRegister extends JFrame implements KeyListener
{
    private NorthPanel northPanel;
    private Keypad keypad;

    public CashRegister ()
    {
        this.setFocusable(true);
        this.addKeyListener(this);
        northPanel = new NorthPanel();
        keypad = new Keypad();

        /* Your code ... */
    }

    @Override
    public void keyTyped(KeyEvent ke) 
    {
        /*Do nothing*/
    }

    @Override
    public void keyPressed(KeyEvent ke) 
    {
        northPanel.aKeyWasPressed( ke.getKeyCode() );
        keypad.aKeyWasPressed( ke.getKeyCode() );
    }

    @Override
    public void keyReleased(KeyEvent ke) 
    {
        /*Do nothing*/
    } 
}


注意:为了区分按键,在面板中的 aKeyWasPressed 方法中,你可以这样做:

private void aKeyWasPressed(int code)
{
    if(code == KeyEvent.VK_A)
    {
        /*If its letter 'A', do this...*/
    }
}

同样,有很多方法可以做到这一点,但在我看来,让Frame本身处理所有用户输入是大多数情况下的最佳实践,主要是在处理多个面板时。