2

I had 9 hunks of form-identical code such as this:

btnExit.addActionListener(new ActionListener() {
  public void actionPerformed(ActionEvent evt) {
    btnExitActionPerformed(evt);
  }
});

...with 9 corresponding linked hunks of code like this:

private void btnExitActionPerformed(ActionEvent evt) {   
  // some code *********************
}                                          

... and a large number of similar repeated hunks of code for FocusListener and MouseListener.

I tried to cut down the number of lines of code by assigning the button's text to its action command and using this:

  public void actionPerformed(ActionEvent e) 
  {
    String c = e.getActionCommand();
    switch (c) {
      case "Clear output":        btnClearOutputActionPerformed(e); break;
      case "Search":              btnSearchActionPerformed(e);      break;
      case "Exit":                btnExitActionPerformed(e);        break;
  ...
    }
  }

It works, but that's not a lot better. Still repetitive. Looking for elegant.

I can't believe the following method even compiles, but it doesn't work because doClick() calls the method recursively. I was naively hoping doClick() would execute the method btnPatternMouseClickedActionPerformed().

  public void actionPerformed(ActionEvent e){
    Component[] c ;
    c = theFrame.getComponents();
    JButton b;
    for(Component x: c)
    {
      if(x instanceof JButton)
      {
        b = (JButton) x;
        if(b.getText().equals(e.getActionCommand()))
        {
          b.doClick(); // want it to execute code elsewhere
          return;
        }
      }
    }
  }

At first I thought the above method was close. Now I'm about to give up.

I have three questions:

(1) Is there a way to cut down on such repeated hunks of code as shown in the first two paragraphs?

(1a) Is the last method above close? Can it be easily fixed?

(2) Would a technique similar to the actionPerformed method above (the one that uses switch) to replace hunks of code for FocusListener and MouseListener be a waste of time to implement?

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
DSlomer64
  • 4,234
  • 4
  • 53
  • 88

2 Answers2

3

You could change this:

btnExit.addActionListener(new ActionListener() {
  public void actionPerformed(ActionEvent evt) {
    btnExitActionPerformed(evt);
  }
});

...with 9 corresponding linked hunks of code like this:

private void btnExitActionPerformed(ActionEvent evt) {   
  // some code *********************
} 

to this:

btnExit.addActionListener(new ActionListener() {
  public void actionPerformed(ActionEvent evt) {
    // same code that was in the btnExitActionPerformed method.
  }
});

But perhaps even better still would be to separate your "control" code, the code in the listeners, from your "view" code, your GUI, but how to do this will depend on your problem and current code base.


Edit
You ask:

I will blame Swing GUI builder for that (bad?) habit.

It's not so bad, and is certainly a lot better than having your GUI classes implement listener interfaces.

Why does Swing do that?? Why does Swing do a LOT of what it does!!

I'm not sure what specifically you meant here.

So about "even better": are you saying to separate the listeners into another class file? And are you suggesting that coconuts migr~~...

Yes, and yes. In fact the control -- the listener part could be composed of several classes, but they all might be used in a single master control class.

I mean, that I should abandon the last method in my question?

Yes.

Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • :I will blame Swing GUI builder for that (bad?) habit. (I'm sure at first I thought it was required structure!) I have done as you've suggested in a lot of places in other programs. Why this program is this way is that I inherited it from Swing and employed my own GridBagLayout. Should've just started over altogether. (Why does Swing do that??) (Why does Swing do a LOT of what it does!!) So about "even better": are you saying to separate the listeners into another class file? And are you suggesting that coconuts migr~~... I mean, that I should abandon the last method in my question? – DSlomer64 Feb 15 '15 at 23:26
  • 2
    @DSlomer64 it's not Swing, it's the form editor, those are two different things. The form editor actually allows you to assign the same "action method" to multiple components, but, I think skipping the form editor is a better solution – MadProgrammer Feb 15 '15 at 23:31
  • @MadProgrammer--I know so much about so little and half of it's wrong! But at least I've gotten past GUI builder and (apparently) form editor. `GridBagLayout` really isn't all that hard once you succeed a few times. I don't know about abstract action listeners. I may go there soon. Thanks. – DSlomer64 Feb 15 '15 at 23:40
1
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;

public class Example implements ActionListener{

 JButton buttons[] = new JButton[12];

 public Example(){


    for(int c=0; c<buttons.length; c++){
        buttons[c]=new JButton("I am button"+c);
        buttons[c].addActionListener(this);
    }   

  }


@Override
public void actionPerformed(ActionEvent e) {
    if(e.getSource() == buttons[0]){}
    if(e.getSource() == buttons[1]){}
    if(e.getSource() == buttons[2]){}
    if(e.getSource() == buttons[3]){}
    if(e.getSource() == buttons[4]){}
    if(e.getSource() == buttons[5]){}
    if(e.getSource() == buttons[6]){}
    if(e.getSource() == buttons[7]){}
    //....


}

}

This is not enough elegant for you code?

Something other: If for example you have buttons that are in the same Team, for example: It's a good idea to have one class(java Object) and then take objects and make buttons.

public class TVButton implements ActionListener{

   public TVButton(String name,String whatever){

  }


 @Override
   public void actionPerformed(ActionEvent e){


    //actionFor this button
  }


 }
crAlexander
  • 376
  • 1
  • 2
  • 12
  • 2
    IMHO - "blob" `ActionListener`s are a bad idea. They are difficult to maintain and introduce no end of issues, especially when you want to change the behaviour of one or more buttons. Personally, defining one or more "abstract" `ActionListener`s or `Action`s that don't physically rely on the button or rely only on limited information (and index or other value) is not only simpler but is a better OO approach. If this isn't possible, anonymous or inner classes are the next best thing. Isolate and contain. But that's just me (and I still have legacy code which use "blob" approach - and I hate) – MadProgrammer Feb 15 '15 at 23:19
  • @MadProgrammer give me an example of what you mean(a page or something to see) it will be usefull – crAlexander Feb 15 '15 at 23:52
  • You could start with [How to Use Actions](http://docs.oracle.com/javase/tutorial/uiswing/misc/action.html) and also see Hovercraft's answer – MadProgrammer Feb 16 '15 at 00:04
  • 1
    You could also have a look at [this example](http://stackoverflow.com/questions/22059165/having-two-objects-move-in-an-swingbot/22059424#22059424), it relates to key bindings, but the basic concept is the same. It's uses a single configurable `Action` to allow movement in 4 different directions. The beauty of this is that the `Action` could be associated with buttons as well. So what this does is provide a common, central `Action`, which can be configured to provide different results ;) – MadProgrammer Feb 16 '15 at 00:12
  • crAlex--I'm going to give a look at your edited example. So far I'm not sure what to do with the other answers since I'm not up on the concepts therein. – DSlomer64 Feb 17 '15 at 17:58