Search code examples
javaswingactionlistener

Action-listener implemented in Abstract Class does not get inherited by the classes who extend it


Happy holidays to everyone,

Here is a use case of the situation i am trying to understand.

public abstract class Animal extends JButton implements ActionListener {
    private boolean actionFlag = false;

    //some constructor
    //some functions

    @Override
    public void actionPerformed(ActionEvent actionEvent) {
        this.actionFlag = true;
        System.out.println(this.actionFlag);
    }

}

public class Tiger extends Animal {}

public class Bear extends Animal {}

When for example Tiger and Bear objects getting created and they are BTN's cause the abstract method extends the JButton class, These buttons when getting pressed their respective ActionPerformed() function will get called, since I haven't overidden the actionPerformed func to each of these classes separately they will inherit the actionPerformed() from their parent class which is Animal, I believe I'm correct so far, if not feel free to correct me.

Now since all these observations are correct, when I click the bear button for example I should see that the message in my output equals to "true".

That's the problem, nothing appears on my console and it looks like the actionListener of the base class is not triggered at all . (The buttons on the GUI are setEnabled(true) so the interaction is not a problem)

What are the possible causes of this? what am I missing here?

Same thing happens with the paintComponent() function, but I believe that if I understand the error on the actionListener then it's kind of straightforward)


Solution

  • Just giving a JButton-extending class an ActionListener doesn't add that listener to the created button. To do that, you have to actually add the listener using addActionListener(this); in the class's constructor.

    public abstract class Animal extends JButton implements ActionListener {
        private boolean actionFlag = false;
    
        public Animal() {
            addActionListener(this);
        }
    
        //some constructor
        //some functions
    
        @Override
        public void actionPerformed(ActionEvent actionEvent) {
            this.actionFlag = true;
            System.out.println(this.actionFlag);
        }
    }
    

    Having said that, I would never have Swing code like this, ever. Instead I would

    • Extend by composition if possible, unless I absolutely needed to override an existing JButton method (and this needs to be justified)
    • Separate my view class from my listener, even if this means using anonymous inner classes. It's rarely advisable to have a view class implement a listener interface as this breaks the "single responsibility principle" and increases the complexity and purpose of the class with no advantage

    Regarding:

    Same thing happens with the paintComponent()

    something different is likely happening here since you don't need to "add" paintComponent to the component, but rather if it is a proper method override, it is called automatically by the Swing graphics system.