我正在学习Java,我碰巧遇到了来自Fred Swartz的leepoint.net网页的ActionListener
示例。 DogYears2.java。
为了学习,我通过将ConvertBtnListener
中的ActionListener DogYears2.java
分隔为名为ConvertBtnListener.java
的单独顶级类文件进行了实验。
DogYears2.java文件
import java.awt.*;
import javax.swing.*;
import java.awt.event.*; // Needed for ActionListener
//////////////////////////////////////////////////////// class DogYears2
class DogYears2 extends JFrame {
//======================================================== constants
final static int DOG_YEARS_PER_HUMAN_YEAR = 7;
//=============================================== instance variables
private JTextField _humanYearsTF = new JTextField(3);
private JTextField _dogYearsTF = new JTextField(3);
//====================================================== constructor
public DogYears2() {
// 1... Create/initialize components
JButton convertBtn = new JButton("Convert");
convertBtn.addActionListener(new ConvertBtnListener());
_dogYearsTF.addActionListener(new ConvertBtnListener());
_humanYearsTF.setEditable(false);
// 2... Create content panel, set layout
JPanel content = new JPanel();
content.setLayout(new FlowLayout());
// 3... Add the components to the content panel.
content.add(new JLabel("Dog Years"));
content.add(_dogYearsTF); // Add input field
content.add(convertBtn); // Add button
content.add(new JLabel("Human Years"));
content.add(_humanYearsTF); // Add output field
// 4... Set this window's attributes, and pack it.
setContentPane(content);
pack(); // Layout components.
setTitle("Dog Year Converter");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null); // Center window.
}
//====================================================== method main
public static void main(String[] args) {
DogYears2 window = new DogYears2();
window.setVisible(true);
}
}
ConvertBtnListener.java文件
import java.awt.*;
import javax.swing.*;
import java.awt.event.*; // Needed for ActionListener
class ConvertBtnListener implements ActionListener {
JTextField _dogYearsTF;
JTextField _humanYearsTF;
int DOG_YEARS_PER_HUMAN_YEAR = 7;
public void actionPerformed(ActionEvent e) {
//... Get the value from the dog years textfield.
String dyStr = _dogYearsTF.getText();
int dogYears = Integer.parseInt(dyStr);
//... Convert it - each dog year is worth 7 human years.
int humanYears = dogYears * DOG_YEARS_PER_HUMAN_YEAR;
//... Convert to string and set human yrs textfield
_humanYearsTF.setText("" + humanYears);
}
}
现在,当我运行DogYears.java
文件时,GUI弹出,当我输入文本字段中的人年数时,我得到了NullPointerException
。
为了学习Java菜鸟,我希望有人可以告诉我为什么会这样,如果我INSIST我保持一个单独的ActionListener类文件,我该如何解决这个问题?
答案 0 :(得分:4)
第一步是停止思考文件。你应该谈论类和对象。
在您的示例中,您已经定义了两个类(那些定义发生将被放置在两个单独的文件中,但这并不重要。)
在第一个班级DogYears2
(注意:没有结尾.java
,那个仅文件)中,您在{{1}中创建了一个实例(也称为一个对象)方法。
在第二个类main
中,您在ConvertBtnListener
的构造函数中创建了两个实例(a.k.a两个对象)。
DogYears2
类中的字段_dogYearsTF
和_humanYearsTF
永远不会获得值,因此一旦您尝试,您将获得ConvertBtnListener
与他们做点什么。
您应该知道NullPointerException
中_dogYearsTF
ConvertBtnListener
完全不相关 _dogYearsTF
中的DogYears2
!此外,_dogYearsTF
的第一个实例中的字段ConvertBtnListener
完全不相关到秒的字段_dogYearsTF
实例
现在我告诉你为什么它不起作用,我应该告诉你如何使它工作:
一种方法是将必要的JTextField
对象传递给ConvertBtnListener
对象的构造函数。为此,您需要在该类中创建一个构造函数,该构造函数接受两个JTextField
引用并将它们分配给相应的字段。
通常的方式是使侦听器成为UI类的内部类,在这种情况下,它可以直接访问UI类字段,并且不需要这样的构造函数(这就是为什么它在最初的例子中起作用。)
答案 1 :(得分:2)
在您的监听器类中,请初始化文本字段变量。考虑一下:
class ConvertBtnListener implements ActionListener {
....
ConvertBtnListener(JTextField humanYearsTF, JTextField dogYearsTF) {
_dogYearsTF = dogYearsTF;
_humanYearsTF = humanYearsTF;
}
....
}
public DogYears2() {
ActionListener listener = new ConvertBtnListener(_humanYearsTF, _dogYearsTF);
JButton convertBtn = new JButton("Convert");
...
}
另请参阅什么是匿名类。这是实现此类操作的另一种方式。
---编辑 而不是声明
int DOG_YEARS_PER_HUMAN_YEAR = 7;
ConvertBtnListener类中的- 只使用之前在DogYears.java中声明的静态字段。所以这应该是正确的方式。
int humanYears = dogYears * DogYears2.DOG_YEARS_PER_HUMAN_YEAR;
---编辑 构造函数参数命令
答案 2 :(得分:0)
在ConvertBtnListener
中,您会在此处获得空指针异常:
String dyStr = _dogYearsTF.getText();
......在这里:
_humanYearsTF.setText("" + humanYears);
您永远不会在_dogYearsTF
中初始化_humanYearsTF
和ConvertBtnListener;
这些字段与DogYears2
中的相同名称无关。
答案 3 :(得分:0)
您可以尝试使用getSource()函数
public void actionPerformed(ActionEvent e) {
//... Get the value from the dog years textfield.
String dyStr = _dogYearsTF.getText();
int dogYears = Integer.parseInt(dyStr);
JTextField _humanYearsTF = (JTextField)e.getSource(); // new line.
//... Convert it - each dog year is worth 7 human years.
int humanYears = dogYears * DOG_YEARS_PER_HUMAN_YEAR;
//... Convert to string and set human yrs textfield
_humanYearsTF.setText("" + humanYears);
}
这将获取触发动作事件的源。