NullPointerException for instantiated button in ac

2019-07-25 18:33发布

问题:

The following code is a snippet of a program I am getting a nullpointer exception from. When I press the "Add" button on the GUI, an error message pointing to this line:

  buttonPanel.addButton.setEnabled(false);

is displayed. I'm guessing that the addButton is null for some reason although I instantiated it in the constructor of buttonPanel:

 addButton = new JButton("Add");
 addButton.addActionListener(buttonListener);

Why is the null pointer error

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at AddButtonListener.actionPerformed(AddButtonListener.java:21)

appearing? When the listener is coded inside the buttonPanel class, the program runs fine with no errors. Thanks in advance for your help!

import java.awt.GridLayout;
import javax.swing.*;

public class ButtonPanel extends JPanel{
    public JButton addButton,
                   editButton,
                   deleteButton,
                   acceptButton,
                   cancelButton,
                   exitButton;

    public JPanel topPanel,
                   exitPanel;

    private ParentFrame parentFrame;

    public static String buttonStatus;

    public ButtonPanel(ParentFrame parent){
        parentFrame = parent;

        buttonStatus = "idle";
        //Create Buttons

        AddButtonListener buttonListener = new AddButtonListener(parent);
        addButton = new JButton("Add");
        addButton.addActionListener(buttonListener);
        editButton = new JButton("Edit");
        deleteButton = new JButton("Delete");
        acceptButton = new JButton("Accept");
        cancelButton = new JButton("Cancel");
        exitButton = new JButton("Exit");

        //Manipulate Buttons
        acceptButton.setEnabled(false);
        cancelButton.setEnabled(false);

        //Add to panels
        topPanel = new JPanel();
        topPanel.add(addButton);
        topPanel.add(editButton);
        topPanel.add(deleteButton);
        topPanel.add(acceptButton);
        topPanel.add(cancelButton);

        exitPanel = new JPanel();
        exitPanel.add(exitButton);

        this.setLayout(new GridLayout(2,1));
        this.add(topPanel);
        this.add(exitPanel);
    }
}

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class AddButtonListener implements ActionListener{

    private ParentFrame myFrame;

    private ButtonPanel buttonPanel;

    public AddButtonListener(ParentFrame parent){
        myFrame = parent;
        buttonPanel = parent.buttonPanel;
    }

    @Override
    public void actionPerformed(ActionEvent ae) {
        buttonPanel.buttonStatus = "add";

        buttonPanel.addButton.setEnabled(false);
        buttonPanel.editButton.setEnabled(false);
        buttonPanel.deleteButton.setEnabled(false);

        buttonPanel.acceptButton.setEnabled(true);
        buttonPanel.cancelButton.setEnabled(true);
    }

}

import java.awt.BorderLayout;
import javax.swing.JFrame;

public class ParentFrame extends JFrame{

    public ButtonPanel buttonPanel;

    public ParentFrame(){
        this.setResizable(false);

        buttonPanel = new ButtonPanel(this);

        this.add(buttonPanel, BorderLayout.SOUTH);
        this.pack();

        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setSize(400, 300);
    }

    public static void main(String[] args){
        ParentFrame frame = new ParentFrame();
        frame.setVisible(true);
    }
}

回答1:

Your buttonpanel requires a reference to ParentFrame to be constructed. ButtonPanel is being constructed in parent frame and creating a listener, which references the parent frame's button panel.

Unfortunately, the button panel hasn't been assigned at that point, and so your action listener has a null value assigned to its instance of button panel.

I think the problem is your button panel instance is null in your AddButtonListener.

You can fix this by passing a ButtonPanel instance into your AddButtonListener constructor. As AddButtonListener isn't using ParentFrame, don't bother passing it at all.

private ButtonPanel buttonPanel;
public AddButtonListener(ButtonPanel panel){
    myFrame = parent;
    buttonPanel = panel;
}

And then in your button panel constructor:

public ButtonPanel(ParentFrame parent){
    parentFrame = parent;

    buttonStatus = "idle";
    //Create Buttons

    AddButtonListener buttonListener = new AddButtonListener(this);
    //rest the code

Aside, you shouldn't be structuring things like this. What you're doing is tightly coupling your ButtonPanel with your ParentFrame. This means if your parent frame changes it could cause another change in ButtonPanel, which makes for less maintanable code.



回答2:

You are adding the new AddButtonListener(parent); before the ButtonPanel(ParentFrame parent) is fully initialized, so all it componets are null.



回答3:

Do the following In AddButtonListener

public void actionPerformed(ActionEvent ae) {
    // change all references to buttonPanel to myFrame.buttonPanel
    myFrame.buttonPanel.buttonStatus = "add";
    ...
}

This is because while you construct the ButtonPanel, the buttonPanel variable inside ParentFrame you pass around is null at that very moment.

see

public ParentFrame(){
    ...
    // when you initialize this, buttonPanel is null until constructing is complete
    buttonPanel = new ButtonPanel(this);
    ...
}

Therefore AddButtonListener.buttonPanel is null.



回答4:

you might have delete the initialization code which is:

public yourClass()
{
    initComponents();
    btn(false);
}