【问题标题】:Java - Separate Listener Class throws NullPointerExceptionJava - 单独的侦听器类抛出 NullPointerException
【发布时间】:2013-09-04 02:50:07
【问题描述】:

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

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

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 传递给我的侦听器类。

然后在 Keypad 类中,我说:

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
            }
        }
    }
}

此时我得到了 NullPointerException。我不知道为什么,但我猜这是因为监听器对象来自不同的类并使用不同的构造函数,因为我必须从每个需要相互通信的类中传递不同的对象。不过,我不是 100% 确定。有没有办法解决这个问题,还是我做错了什么?

【问题讨论】:

  • 您正在创建EventHandler 的两个不同实例,一个引用priceField 一个引用JButton[][],我假设在您的按钮actionPerformed ,您正在尝试引用priceField,即... null
  • @MadProgrammer 是的,谢谢!我重写了它,所以所有的传递变量方法都是静态的,现在它可以工作了。
  • 静态方法不是答案 ;)
  • 问题是,如果你现在创建另一个 UI 实例,它的引用是什么?
  • 要获得更好的答案,请尝试提供SSCCE。我没有写答案的原因是没有足够的上下文来为您提供可能的解决方案......

标签: java swing nullpointerexception actionlistener


【解决方案1】:

您应该让 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 本身处理所有用户输入是大多数情况下的最佳做法,主要是在处理多个面板时。

【讨论】:

    猜你喜欢
    • 2012-11-09
    • 1970-01-01
    • 2017-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-22
    • 2013-11-12
    • 1970-01-01
    相关资源
    最近更新 更多