Parent JPanel - How to listen to the events genera

2019-05-23 09:26发布

问题:

This question already has an answer here:

  • Adding ActionListener to a Panel - Panel implements ActionListener vs Panel HAS A ActionListener 2 answers

I made a JPanel Child which contains a couple of radio buttons in it. Whenever a radio button is clicked i want an ActionEvent to be generated from the Child also. This action event should "contain" a reference to the button which actually generated an event.

This Child will be used as a component inside another JPanel Parent which will listen to the events from the Child, instead of listening to the individual radio buttons.

How can I do this ?

Code so far -

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

public class RadioListener extends JPanel implements ActionListener{

public static final String id = "id";

public RadioListener(){

    for(int i = 1; i < 5; i++){
        JRadioButton jrb = new JRadioButton(i + "", false);
        jrb.putClientProperty(id, i);
        this.add(jrb);
        jrb.addActionListener(this);

    }

}


public void actionPerformed(ActionEvent e){

    JRadioButton jrb = (JRadioButton) e.getSource(); 
    Integer id = (Integer) jrb.getClientProperty(RadioListener.id);
    System.out.println("id " + id);

}


public static void main(String[]args){

    JFrame frame = new JFrame("Radio buttons");
    frame.getContentPane().setLayout(new FlowLayout());
    frame.setSize(400, 100);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().add(new RadioListener());
    frame.setVisible(true);


}

}

回答1:

I'd recommend providing the ability for the component to act as a proxy for other interested parties to register interest.

This means you don't need to expose methods/components that other components shouldn't be calling or have access to.

You should also make use of inner classes for listeners, as they will prevent the exposure of other methods that others shouldn't have access to

public class ProxyActionListener extends JPanel {

    public static final String id = "id";
    private List<JRadioButton> buttons;

    public ProxyActionListener() {

        buttons = new ArrayList<>(25);
        ActionHandler actionHandler = new ActionHandler();

        for (int i = 1; i < 5; i++) {
            JRadioButton jrb = new JRadioButton(i + "", false);
            jrb.putClientProperty(id, i);
            this.add(jrb);
            jrb.addActionListener(actionHandler);
            buttons.add(jrb);

        }

    }

    public void addActionListener(ActionListener listener) {
        for (JRadioButton btn : buttons) {
            btn.addActionListener(listener);
        }
    }

    public void removeActionListener(ActionListener listener) {
        for (JRadioButton btn : buttons) {
            btn.removeActionListener(listener);
        }
    }

    public static void main(String[] args) {

        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                ProxyActionListener pal = new ProxyActionListener();
                pal.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        JRadioButton jrb = (JRadioButton) e.getSource();
                        Integer id = (Integer) jrb.getClientProperty(ProxyActionListener.id);
                        System.out.println("Proxy- id " + id);
                    }
                });

                JFrame frame = new JFrame("Radio buttons");
                frame.getContentPane().setLayout(new FlowLayout());
                frame.setSize(400, 100);
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.getContentPane().add(pal);
                frame.setVisible(true);
            }
        });
    }

    protected class ActionHandler implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {

            JRadioButton jrb = (JRadioButton) e.getSource();
            Integer id = (Integer) jrb.getClientProperty(ProxyActionListener.id);
            System.out.println("id " + id);

        }
    }
}


回答2:

To go MadProgrammer's recommendations (1+) one step further, you could use Swing Components intrinsic PropertyChangeSupport for this purpose:

import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.*;

@SuppressWarnings("serial")
public class RadioListenerTesterHFOE extends JPanel {
   private RadioListenerHFOE radioListenerHfoe = new RadioListenerHFOE();

   public RadioListenerTesterHFOE() {
      add(radioListenerHfoe);
      radioListenerHfoe.addPropertyChangeListener(new PropertyChangeListener() {

         @Override
         public void propertyChange(PropertyChangeEvent pcEvt) {
            if (pcEvt.getPropertyName().equals(RadioListenerHFOE.RADIO)) {
               System.out.println("Radio Selected: " + pcEvt.getNewValue());
            }
         }
      });
   }

   private static void createAndShowGui() {
      RadioListenerTesterHFOE mainPanel = new RadioListenerTesterHFOE();

      JFrame frame = new JFrame("RadioListenerTesterHFOE");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

class RadioListenerHFOE extends JPanel {
   private static final String[] LABELS = {"1", "2", "3", "4"};
   private static final int GAP = 5;
   public static final String RADIO = "radio";
   private ButtonGroup buttonGroup = new ButtonGroup();
   private RadioListenerHandler handler = new RadioListenerHandler();

   public RadioListenerHFOE() {
      setLayout(new GridLayout(1, 0, GAP, 0));
      for (String label : LABELS) {
         JRadioButton radioButton = new JRadioButton(label);
         radioButton.setActionCommand(label);
         radioButton.addActionListener(handler);
         buttonGroup.add(radioButton);
         add(radioButton);
      }      
   }

   private class RadioListenerHandler implements ActionListener {
      private String actionCommand = null;

      @Override
      public void actionPerformed(ActionEvent evt) {
         setActionCommand(evt.getActionCommand());
      }

      private void setActionCommand(String actionCommand) {
         String oldValue = this.actionCommand;
         String newValue = actionCommand;
         this.actionCommand = newValue;
         firePropertyChange(RADIO, oldValue, newValue);
      }
   }

}


回答3:

Is this solution good enough ?

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class RadioListener extends JPanel{

public static final String id = "id";
private ActionListener privateActionListener;
JRadioButton[] btns = new JRadioButton[5];

public RadioListener(){

    for(int i = 0; i < btns.length; i++){
        JRadioButton jrb = new JRadioButton(i + "", false);
        jrb.putClientProperty(id, i);
        btns[i] = jrb;
        this.add(jrb);      
    }

}


public static void main(String[]args){

    JFrame frame = new JFrame("Radio buttons");
    frame.getContentPane().setLayout(new FlowLayout());
    frame.setSize(400, 100);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    AnActionListener an = new AnActionListener();
    RadioListener rl = new RadioListener();
    rl.setActionListener(an);
    frame.getContentPane().add(rl);
    frame.setVisible(true);


}


public ActionListener getActionListener() {
    return privateActionListener;
}


public void setActionListener(ActionListener privateActionListener) {

    this.privateActionListener = privateActionListener;
    for(int i = 0; i < btns.length; i ++){

        btns[i].addActionListener(privateActionListener);

    }

}



}


class AnActionListener implements ActionListener{

public void actionPerformed(ActionEvent e){

    JRadioButton jrb = (JRadioButton) e.getSource(); 
    Integer id = (Integer) jrb.getClientProperty(RadioListener.id);
    System.out.println("id " + id);

}

}