Java ActionListeners

I am going to develop a game in Java, and it will have many listeners (action, key, mouse, etc.).

My question is what is the preferred way to implement listeners.

Method 1:

this.addActionListener(new ActionListener() { // Overide methods go here }); 

Method 2:

create a new class (or several classes) that will implement the ActionListener and have methods for different game components (buttons, navigation, everything ActionListener needs)

For example. If I make a button, it's better to do

 JButton button = new JButton(); button.addActionListener(new ActionListener() { }); 

or

 JButton button = new JButton(); button.addActionListener(new MyActionListener()); // MyActionListener class MyActionListener implements ActionListener { @Override public void actionPerformed(ActionEvent e) { Object objectPressed = e.getSource(); if(objectPressed.equals(button) { System.out.println("Hello World"); } } } 

I see advantages in both directions: method 1 you can see what happens with this object directly, but method 2 you can see all the components.

So, when developing large-scale applications that are easier to maintain, having all the listeners in separate classes or using method 1?

+4
source share
5 answers

Personally, I would prefer that many listeners be with if checks. This would allow me to change them myself.

I would embed this code in the user interface. I would write them as separate classes and introduce them as dependencies using the constructor or DI factory.

Designer Injection:

 public class YourPanel extends JPanel { private JButton button; public YourPanel(ActionListener buttonListener) { this.button = new JButton("Do It"); this.button.addActionListener(buttonListener); } } 
+3
source

First of all, terms. In both cases, you define classes, but in the first, they are called anonymous inner classes . You will find a file like MyClass$1.java .

In this sense, MY rules (others may vary) will be

1) Use anonymous inner classes only for simpler actions that are not reused. For all others, use the "normal" classes.

2) Reuse components only when they make sense. If you have two buttons that have completely different meanings, do not try to reuse the same listener. Create some. For example, if you have two buttons (increment and decrement), you can reuse the same class, since the operation will be very similar. If you have multiple values ​​with these buttons, reuse the classes that pass the object you want to modify in the constructor. But do not mix the button to increase the value using the "start round" button.


UPDATE:

And by the way, when you say:

I see advantages in both directions: method 1 you can see what happens with this object directly, but method 2 you can see all the components.

This may look like an advantage of seeing all the components, but it makes encapsulating the logical path more difficult if all your classes can change all the rest. Encapsulation means some extra work, but in the end you get a product that is more manageable, and this is an important thing.

+2
source

To add another stick to this fire, I prefer to use AbstractActions as an anonymous inner class, or more often as a standalone stand-alone class:

 JButton myExitButton = new JButton(new MyExitAction()); 

As an example, the Control class, which is part of my MVC Swing project, has this as part of its code:

 public class Control { // these two types below are interfaces private Model model; private View view; public Control(Model model, View view) { this.model = model; this.view = view; addViewListeners(); } private void addViewListeners() { view.setGetPageAction(new GetPageAction(this, "Get Page", KeyEvent.VK_G)); view.setSetTnRendererBtnAction(new SetTnRendererBtnAction(this, "Show Images", KeyEvent.VK_S)); view.setClearThumbNailsAction(new ClearThumbNailsAction(this, "Clear ThumbNails", KeyEvent.VK_C)); view.setSetDestinationAction(new SetDestinationAction(this, "Set Destination", KeyEvent.VK_T)); view.setDownloadAction(new DownloadAction(this, "Download", KeyEvent.VK_D)); view.setExitAction(new ExitAction(this, "Exit", KeyEvent.VK_X)); model.addPropertyChangeListener(new ModelListener()); } public View getView() { return view; } public Model getModel() { return model; } // ..... } 

And the abstract class that underlies all my AbstractActions looks like this:

 public abstract class MyAbstractAction extends AbstractAction { protected Control control; protected Model model; protected View view; public MyAbstractAction(Control control, String txt, int mnemonic) { super(txt); putValue(MNEMONIC_KEY, mnemonic); this.control = control; this.model = control.getModel(); this.view = control.getView(); } } 

One caveat: note that I am not a professional programmer, but rather a hobby, therefore, although my ideas work for me, they cannot represent the absolute best in this area. All corrections and tips are welcome. The weakness of my design above is that I think that I "enter" my actions in an awkward way.

+2
source

I would honestly prefer the first one. you are right, the first approach you can easily see what happens with this component. But. there will be times when the button is likely to have the same behavior or the same ActionListener, which, as I said, I would prefer approach 2. so that you can easily reuse actionListeners.

0
source

You can also take a look at this swing environment called swingobjects that I was working on.

https://github.com/Sethuraman/swingobjects

If you create a Jframe using the FrameFactory class, swingobjects will register a GlobalListener for you for all the widgets that you specify in your frame. To do this, mark the method in your frame with the annotation as follows:

 @Action("<action name or button text>") public void performAction(ActionEvent evt){ .... } 

GlobalListener will call this method through reflection. This means that you do not have to write, if blocks, create anonymous inner classes. Everything is transparently processed for you. Take a look at the frames ...

0
source

Source: https://habr.com/ru/post/1483987/


All Articles