Enabling Button Actions / Button Implementations

Full caveat: I'm a CS student, and this question is related to the recently assigned Java program for object oriented programming. Although we did some things in the console, this is the first time we have worked with a GUI and Swing or Awt. We were given some code that created a window with some text and a button that rotated in different colors for the text. Then we were asked to change the program to create color switchers instead - this was also meant to give us the opportunity to explore the API. I have already transferred my assignment and received permission from my instructor to post my code here.

What is the best way to implement button actions in Java? After some attempts, I created these buttons:

class HelloComponent3 extends JComponent implements MouseMotionListener, ActionListener { int messageX = 75, messageY= 175; String theMessage; String redString = "red", blueString = "blue", greenString = "green"; String magentaString = "magenta", blackString = "black", resetString = "reset"; JButton resetButton; JRadioButton redButton, blueButton, greenButton, magentaButton, blackButton; ButtonGroup colorButtons; public HelloComponent3(String message) { theMessage = message; //intialize the reset button resetButton = new JButton("Reset"); resetButton.setActionCommand(resetString); resetButton.addActionListener(this); //intialize our radio buttons with actions and labels redButton = new JRadioButton("Red"); redButton.setActionCommand(redString); ... 

And added action listeners ...

 redButton.addActionListener(this); blueButton.addActionListener(this); ... 

A stub was created for the actionPerformed method to give us an idea of ​​how to use it, but since there was only one button in the template, it was not clear how to implement several buttons. I tried to include String, but quickly realized that since String is not a primitive type, I could not use it for the switch statement. I could improvise with an if-else chain, but instead I came to this. It seems far from elegance, and there must be a better way. If there is, what is it? Is there a way to include a string? Or choose an action in a more scalable way?

 public void actionPerformed(ActionEvent e){ if (e.getActionCommand().equals(resetString)) { messageX = 75; messageY = 175; setForeground(Color.black); blackButton.setSelected(true); repaint(); return; } if ( e.getActionCommand().equals(redString) ) { setForeground(Color.red); repaint(); return; } if ( e.getActionCommand().equals(blueString) ) { setForeground(Color.blue); repaint(); return; } if ( e.getActionCommand().equals(greenString) ) { setForeground(Color.green); repaint(); return; } if ( e.getActionCommand().equals(magentaString) ) { setForeground(Color.magenta); repaint(); return; } if ( e.getActionCommand().equals(blackString) ) { setForeground(Color.black); repaint(); return; } } 
+1
java swing awt
source share
5 answers

Instead of writing this:

 resetButton.addActionListener(this); 

You can also write this:

 resetButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { resetButtonActionPerformed(evt); } }); 

And instead of writing one big actionPerformed () for all actions, you can (and then should) write this:

 public void resetButtonActionPerformed(ActionEvent evt) { messageX = 75; messageY = 175; setForeground(Color.black); blackButton.setSelected(true); repaint(); } 

I don't know if this is the most elegant solution, but at least you no longer have such a big if construct.

+1
source share

Two alternative approaches:

  • Create a new class that implements the Action interface and has a Color field and an actionPerformed method that sets the color
  • Mantain a HashMap from team names to Color instances and find the team name on the map
0
source share

One reasonably suitable approach is to declare enum whose elements match your strings and include valueOf (str) (the linked example shows how to do this with a sufficient degree of security).

The reason to avoid anonymous inner classes is probably because the class does not have such a construct (though), although this might be a better solution.

0
source share

As already suggested, you can use anonymous inner classes to implement the ActionListener interface. Alternatively, you do not need to use anonymous inner classes, but instead you can use a simple nested class:

 resetButton = new JButton(new ResetAction()); redButton = new JButton(new ColorAction("Red", Color.red)); 

and then...

 private class ResetAction extends AbstractAction { public ResetAction() { super("Reset"); } public void actionPerformed(ActionEvent e) { messageX = 75; messageY = 175; setForeground(Color.black); blackButton.setSelected(true); repaint(); } } private class ResetAction extends AbstractAction { private Color color; public ColorAction(String title, Color color) { super(title); this.color = color; } public void actionPerformed(ActionEvent e) { setForeground(color); repaint(); } } 

Why is this approach or any approach involving inner classes better than implementing an ActionListener in an outer class, see "Design Patterns":

The "favorable" composition of an object "over" class inheritance. "(Gang of Four 1995: 20)

The choice between anonymous inner classes and these named inner classes depends heavily on style, but I think this version is easier to understand and understand when there are a lot of actions.

0
source share

Ergh. Do not implement a mass of unrelated interfaces in one mega-class. Use implicit inner classes instead. They are a little detailed, but that is what you want. Use one for each event, then you will not need a large if-else chain. I suggest storing enough code inside an inner class to decode events and call methods that make sense for targets. In addition, you can parameterize your inner classes. You will probably find that you do not need to maintain links to actual widgets.

In your example, you seem to be using JComponent as a JPanel. There are not many differences, but use JPanel to collect the widget block. In addition, it is unlikely that you need to subclass it, so no.

So for example:

  addColorButton("Green" , Color.GREEN ); addColorButton("Red" , Color.RED ); addColorButton("Yellow", Color.YELLOW); addColorButton("Blue" , Color.BLUE ); ... private void addColorButton(String label, Color color) { JRadioButton button = new JRadioButton(label); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { target.setForeground(color); target.repaint(); } }); colorGroup.add(button); panel.add(button); } 
-one
source share

All Articles