开发者

Passing data between two separate .java files

I'm learning Java and I happened to come across an ActionListener example from Fred Swartz's leepoint.net webpage. DogYears2.java.

For the sake of learning, I experimented by seperating the ActionListener ConvertBtnListener from the DogYears2.java into a seperate top level class file called ConvertBtnListener.java.

The DogYears2.java file

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 Convert开发者_高级运维er");
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setLocationRelativeTo(null);          // Center window.
}

    //====================================================== method main
public static void main(String[] args) {
    DogYears2 window = new DogYears2();
    window.setVisible(true);
}

}

The ConvertBtnListener.java file

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

}

Now when I ran the DogYears.java file, the GUI pops out and when I typed in the No. of human years in the textfield, I got a NullPointerException instead.

For the sake of learning as a Java noob, I hope somebody can enlighten me on why this happens and how do I get round this if I INSIST that I maintain a seperate ActionListener class file?


The first step is to stop thinking of files. You should be talking about classes and objects.

In your example you have defined two classes (those definitions happen to be placed in two separate files, but that doesn't really matter).

Of the first class DogYears2 (note: no ending .java, that's only for the file) you create one instance (a.k.a one object) in your main method.

Of the second class ConvertBtnListener you create two instances (a.k.a two objects) in the constructor of DogYears2.

The fields _dogYearsTF and _humanYearsTF in the ConvertBtnListener class never get a value and therefore you'll get a NullPointerException once you try to do something with them.

You should be aware that _dogYearsTF in ConvertBtnListener is entirely unrelated to _dogYearsTF in DogYears2! Furthermore, the field _dogYearsTF in the first instance of ConvertBtnListener is entirely unrelated to the field _dogYearsTF n the second instance.

Now that I've told you why it doesn't work, I should probably tell you how to make it work:

One way would be to pass the necessary JTextField objects to the constructor of the ConvertBtnListener object. For this you'll need to create a constructor in that class that accepts the two JTextField references and assigns them to the appropriate fields.

The usual way is to make the listener an inner class of your UI class, in which case it would have direct access to the UI classes fields and would not need such a constructor (this is why it worked in the original example).


In your listener class please initialize textfield variables. Consider this:

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");
    ...
}

see also what are anonymous classes. This is another way to implement such operations.

--- edit instead of declaring

int DOG_YEARS_PER_HUMAN_YEAR = 7;

in ConvertBtnListener class - use just static field you've declared previously in DogYears.java. So this should be right way.

int humanYears = dogYears * DogYears2.DOG_YEARS_PER_HUMAN_YEAR;

---edit constructor parameters order


In ConvertBtnListener you get null pointer exceptions here:

String dyStr = _dogYearsTF.getText();

... and here:

 _humanYearsTF.setText("" + humanYears);

You never initialize _dogYearsTF and _humanYearsTF in ConvertBtnListener; these fields have nothing to do with the same name ones in DogYears2.


you can try using the getSource() function

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

This would get the source from which the action event was fired.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜