Search code examples
javaswingjbuttonextendjcomponent

Java - Reusable button action handler concepts question


First off - sorry for the wall of code but it's not too horrendous, just a framework for what I'm trying to explain. It runs without errors.

The goal

I'm making a reuseable button class for my GUI and each button object needs to have a different handler when it's clicked. I want to to assign a ClickHandler object to each new button. Then, the button would call init() on the handler, and be on its way. Unfortunately, there's a typing problem, since each handler class would have a different name.

Current progress

Right now, the handler is typed as HandlerA, but I'd like to have it handle any name, like "SettingsHandler" or "GoToTheWahWah" etc.

I've tried messing about with generic types, but since I'm new to this, and from a webdev background, there seems to be a conceptual hurdle I keep knocking over. Is this the right way to approach the problem?

The code

ReuseableButton.java is a reuseable class, the only thing that changes is the action when it's clicked:

package gui;

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

public class ReuseableButton extends JButton implements ActionListener {
  private static final long serialVersionUID = 1L;

  // I want a generic type here, not just HandlerA!
  private HandlerA ClickHandler;

  // Assemble generic button
  public ReuseableButton(Container c, String s) {
    super(s);
    addActionListener(this);
    c.add(this);
  }

  // Once again, generic type, not just HandlerA!
  public void SetClickHandler(HandlerA ch) {
    ClickHandler = ch;
  }

  // Call init() from whatever class has been defined as click handler.
  public void actionPerformed(ActionEvent e) {
    ClickHandler.init();
  }
}

Controller.java fires the frame and assembles buttons as needed (right now, only one button).

package gui;
import javax.swing.*;
import java.awt.*;

public class Controller extends JFrame {
  private static final long serialVersionUID = 1L;


  public Controller() {
    JFrame frame = new JFrame("Handler Test GUI");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);        

    Container pane = frame.getContentPane();   
    pane.setLayout(new FlowLayout());

    ReuseableButton b = new ReuseableButton(pane,"Reuseable Button A");
    // THE QUESTION IS HERE: Pass a generic object?
    b.SetClickHandler(new HandlerA());

    frame.pack();
    frame.setSize(200,200);    
    frame.setVisible(true);        
  }

  public static void main(String args[]) {
    new Controller();
  }
}

HandlerA.java is a sample of a random handler for the button click. Later, there could be HandlerB, HandlerC, etc.

package gui;

// A random handler
public class HandlerA {
  public void init() {
    System.out.println("Button clicked.");
  }
}

Thanks very much in advance!


Solution

  • I recommend to work with inheritence in this case:

    public abstract class AbstractHandler {
    
        public abstract void init();
    }
    

    Then:

    public class ConcreteHandlerA extends AbstractHandler {
    
        @Override
        public void init() {
            // do stuff...
        }
    
    }
    

    Controller

    public class ReuseableButton extends JButton implements ActionListener {
        // I want a generic type here, not just HandlerA!
        private AbstractHandler ClickHandler;
    
        public Controller() {
            //...
    
            ReuseableButton b = new ReuseableButton(pane,"Reuseable Button A");
            AbstractHandler handlerA = new ConcreteHandlerA();
            b.SetClickHandler(handlerA);
    
            // ...
        }
    }
    

    Not sure if this is what you're looking for...

    BTW: You can define the AbstractHandler as an interface as well, but you may want to implement some common logic here as well - shared across handlers.