-1

So I started playing with javax.swing package classes in Java. I created a button and wanted to add functionality to it so I implemented ActionListener interface to listen to the event created by my button

Here is the code block.

public class SimpleGUI  implements ActionListener {     
    JButton button;

public void go() {
    JFrame frame = new JFrame();
    button = new JButton("Click me");

    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().add(button);
    frame.setSize(300, 300);
    frame.setVisible(true);

    button.addActionListener(this);
}

@Override
public void actionPerformed(ActionEvent event) {
    button.setText("I've been clicked");
}

When I looked up in the API about the method addActionListener, it stated that the argument passed should implement ActionListener interface but when I tweak the last line of my method go() code to

    button.addActionListener(new SimpleGUI());

I believe this should run just fine and also the compiler seems fine with it but when I run it, after all I am passing object which implements the ActionListener interface but I get plethora of runtime errors.

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at simplegui.SimpleGUI.actionPerformed(SimpleGUI.java:29)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2022)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2348)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252)
at java.awt.Component.processMouseEvent(Component.java:6533)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3324)
at java.awt.Component.processEvent(Component.java:6298)
at java.awt.Container.processEvent(Container.java:2236)
at java.awt.Component.dispatchEventImpl(Component.java:4889)
at java.awt.Container.dispatchEventImpl(Container.java:2294)
at java.awt.Component.dispatchEvent(Component.java:4711)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4888)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4525)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4466)
at java.awt.Container.dispatchEventImpl(Container.java:2280)
at java.awt.Window.dispatchEventImpl(Window.java:2746)
at java.awt.Component.dispatchEvent(Component.java:4711)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
at java.awt.EventQueue$4.run(EventQueue.java:731)
at java.awt.EventQueue$4.run(EventQueue.java:729)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:728)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)

Can someone explain the reason behind this?

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
Abdul Sami
  • 31
  • 5
  • 2
    Yes, it compiles - but I doubt that it does what you want it to. It's hard to tell exactly what's going to happen as you haven't shown your `ActionListener` implementation code, but basically all the methods would be called on the *new* instance of `SimpleGUI`, not the one that `go()` was called on. I doubt that that's what you want. – Jon Skeet Nov 22 '16 at 11:42
  • You need to post a valid [mcve] as well as your "plethora" of errors to tell you why this is happening, but it likely has much to do with the listener's assuming that it is the same object as the currently running GUI. Side note that most higher level Swing coders avoid having their view objects implement the listener interfaces. – Hovercraft Full Of Eels Nov 22 '16 at 11:42
  • I does nothing much, just prints a message, I have edited so you can see. – Abdul Sami Nov 22 '16 at 11:44
  • 1
    1) Tip: Add @HovercraftFullOfEels (or whoever, the `@` is important) to *notify* the person of a new comment. 2) *"I have edited so you can see."* I see no MCVE in the question, just a code snippet. Follow the link, **read** the document. There is more to MCVE than the 'M'. 3) See [What is a stack trace, and how can I use it to debug my application errors?](http://stackoverflow.com/q/3988788/418556) & [What is a Null Pointer Exception, and how do I fix it?](http://stackoverflow.com/q/218384/418556) – Andrew Thompson Nov 22 '16 at 12:28

2 Answers2

3

When you pass this into the .addActionListener() method, you're passing a reference to the current instance of your class. When you pass in new SimpleGUI(), your passing in a newly created instance. The newly created instance doesn't have assess to the instance of your button object , thus generating the errors you see when it tries to set it's text.

Also, as Hovercraft Full Of Eels was mentioning in the comments, it's much better practise to implement the ActionListener interface on another class, then pass that to .addActionListener().

You could also use an Anonymous Class , like this:

button.addActionListener(new ActionListener(){

        @Override
        public void actionPerformed(ActionEvent e) {

            button.setText("I've been clicked");
        }
    });

Doing this defines your your ActionListener "on the spot", and can make for cleaner code once you start to get into larger applications.

Gulllie
  • 523
  • 6
  • 21
1

The listener's button variable is null since the listener's SimpleGUI object is not the same the displayed object (as we mentioned above), the go() method of the listener object is never called, and so button is never assigned a valid object.

But assuming that you got rid of the go() method and did all the initialization within your SimpleGUI constructor, while your code would then not throw a NullPointerException, it would not behave correctly, since you'd be changing the text displayed (changing the state) of the listener's SimpleGUI object and not the displayed SimpleGUI object.

As noted by Gulllie, use an inner anonymous class, or a private inner class, or a separate listener class entirely.

Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373