web-dev-qa-db-fra.com

Comment ajouter un écouteur d'action qui écoute plusieurs boutons

J'essaie de comprendre ce que je fais de mal avec les auditeurs d'action. Je suis plusieurs tutoriels et pourtant netbeans et Eclipse me donnent des erreurs lorsque je tente d'utiliser un écouteur d'actions. 

Vous trouverez ci-dessous un programme simple qui tente de faire fonctionner un bouton. 

Qu'est-ce que je fais mal?

import Java.awt.event.ActionEvent;
import Java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;


public class calc extends JFrame implements ActionListener {



    public static void main(String[] args) {

        JFrame calcFrame = new JFrame();

        calcFrame.setSize(100, 100);
        calcFrame.setVisible(true);

        JButton button1 = new JButton("1");
        button1.addActionListener(this);

        calcFrame.add(button1);
    }

    public void actionPerformed(ActionEvent e) {
        if(e.getSource() == button1)
    }  

}

le programme d'écoute d'action n'est jamais enregistré car, avec la fonction if(e.getSource() == button1), il ne peut pas voir le code button1, les erreurs indiquant le symbole introuvable 

26
user519670

Il n'y a pas de pointeur this dans une méthode statique. (Je ne crois pas que ce code sera même compilé.)

Vous ne devriez pas faire ces choses avec une méthode statique comme main(); mettre les choses en place dans un constructeur. Je n'ai pas compilé ou exécuté ceci pour voir si cela fonctionne réellement, mais essayez.

public class Calc extends JFrame implements ActionListener {

    private Button button1;

    public Calc()
    {
        super();
        this.setSize(100, 100);
        this.setVisible(true);

        this.button1 = new JButton("1");
        this.button1.addActionListener(this);
        this.add(button1);
    }


    public static void main(String[] args) {

        Calc calc = new Calc();
        calc.setVisible(true);
    }

    public void actionPerformed(ActionEvent e) {
        if(e.getSource() == button1)
    }  

}
35
duffymo

Je suis étonné que personne n'ait mentionné l'utilisation d'une commande d'action. C'est un moyen assez classique d'associer des sources et des auditeurs. C'est vraiment utile si;

  • vous avez plusieurs sources d'événements qui doivent faire la même chose (par exemple, si vous voulez que l'utilisateur puisse appuyer sur la touche Entrée d'un champ de texte plutôt que de cliquer sur un bouton à côté de celui-ci)
  • vous n'avez pas de référence au composant qui génère l'événement 

voir;

import Java.awt.FlowLayout;
import Java.awt.event.ActionEvent;    
import Java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;

public class DontExtendJFrame implements ActionListener {

  private enum Actions {
    HELLO,
    GOODBYE
  }

  public static void main(String[] args) {

    DontExtendJFrame instance = new DontExtendJFrame();

    JFrame frame = new JFrame("Test");
    frame.setLayout(new FlowLayout());
    frame.setSize(200, 100);

    JButton hello = new JButton("Hello");
    hello.setActionCommand(Actions.HELLO.name());
    hello.addActionListener(instance);
    frame.add(hello);

    JButton goodbye = new JButton("Goodbye");
    goodbye.setActionCommand(Actions.GOODBYE.name());
    goodbye.addActionListener(instance);
    frame.add(goodbye);

    frame.setVisible(true);
  }

  @Override
  public void actionPerformed(ActionEvent evt) {
    if (evt.getActionCommand() == Actions.HELLO.name()) {
      JOptionPane.showMessageDialog(null, "Hello");
    } else if (evt.getActionCommand() == Actions.GOODBYE.name()) {
      JOptionPane.showMessageDialog(null, "Goodbye");
    }
  }
}
19
Qwerky

Voici une forme modifiée de la source basée sur mon commentaire. Notez que les interfaces graphiques doivent être construites et mises à jour sur l'EDT, bien que je ne sois pas allé aussi loin.

import Java.awt.event.ActionEvent;
import Java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JFrame;

public class Calc {

    public static void main(String[] args) {

        JFrame calcFrame = new JFrame();

        // usually a good idea.
        calcFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        final JButton button1 = new JButton("1");
        button1.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                JOptionPane.showMessageDialog(
                    button1, "..is the loneliest number");
            }
        });

        calcFrame.add(button1);

        // don't do this..
        // calcFrame.setSize(100, 100);

        // important!
        calcFrame.pack();

        calcFrame.setVisible(true);
    }
}
9
Andrew Thompson

On vous a dit comment régler votre problème immédiat, mais je pense qu'il y a des problèmes plus importants ici.

  • s'en tenir aux conventions. Même pour le code jetable. Cela signifie des cas initiaux pour les noms de classe. 

  • Ne prolongez pas les cours dont vous n'avez pas besoin. JFrame devrait rarement être prolongé. En fait, vous ne créez pas d'instance de votre classe dérivée !!!

  • Ne regroupez pas un tas de choses dans une classe. En particulier, vous ne devez généralement sous-taper qu’au plus une classe ou interface principale à la fois (des éléments tels que Comparable non inclus).

  • Interagissez toujours, y compris la construction, les interfaces graphiques Swing/AWT sur le thread EDT (AWT Event Dispatch Thread). C'est moche et prolixe, mais c'est Java pour vous.

  • Vérifier la source d'un événement est un peu de piratage. Les auditeurs sont de petite taille, vous ne pouvez donc même pas prétendre que l'excuse de performance boiteuse 

Alors:

import Java.awt.event.ActionEvent;
import Java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;


public class Calc {
    public static void main(String[] args) {
        Java.awt.EventQueue.invokeLater(new Runnable() { public void run() {
            runEDT();
        }});
    }
    private static void runEDT() {
        assert Java.awt.EventQueue.isDispatchThread();

        JFrame frame = new JFrame();

        frame.setSize(100, 100);

        JButton button1 = new JButton("1");
        button1.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                ...
            }
        });

        frame.add(button1);

        frame.setVisible(true);
    }
}

Si vous devez accéder à l'une des variables à partir de la méthode englobante dans l'écouteur, rendez-les final.

Le problème est que button1 est une variable locale. Vous pouvez le faire en modifiant simplement la façon dont vous ajoutez l'actionListener.

button.addActionListener(new ActionListener() {  
            public void actionPerformed(ActionEvent e)
            {
                //button is pressed
                System.out.println("You clicked the button");
            }});

Ou vous faites button1 une variable globale.

2
cb0

Le premier problème est que button1 est une variable locale de la méthode main; la méthode actionPerformed n'y a donc pas accès.

Le deuxième problème est que l'interface ActionListener est implémentée par la classe calc, mais aucune instance de cette classe n'est créée dans la méthode main.

La manière habituelle de faire ce que vous voulez est de créer une instance de calc et de transformer button1 en champ de la classe calc.

1
Laurent Pireyn

Vous déclarez button1 dans la méthode main afin que vous ne puissiez pas y accéder dans actionPerform. Vous devriez le rendre global en classe.

 JButton button1;
 public static void main(String[] args) {

    JFrame calcFrame = new JFrame();

    calcFrame.setSize(100, 100);
    calcFrame.setVisible(true);

    button1 = new JButton("1");
    button1.addActionListener(this);

    calcFrame.add(button1);
}

public void actionPerformed(ActionEvent e) {
    if(e.getSource() == button1)
}
0
Harry Joy

J'utilise "e.getActionCommand (). Contient (CharSecuence s)", car je viens d'un contexte MVC et le bouton est déclaré dans la classe View, mais l'appel à actionPerformed a lieu dans le contrôleur. 

public View() {
    ....
    buttonPlus = new Button("+");
    buttonMinus = new Button("-");
    ....
}

public void addController(ActionListener controller) {
    buttonPlus.addActionListener(controller);
    buttonMinus.addActionListener(controller);
}

Ma classe de contrôleurs implémente ActionListener, et donc, lors de la substitution de actionPerformed:

public void actionPerformed(ActionEvent e) {
    if(e.getActionCommand().contains("+")) {
        //do some action on the model
    } else if (e.getActionCommand().contains("-")) {
       //do some other action on the model
    }
}

J'espère que cette autre réponse est également utile.

0
Omar N

Tout d’abord, étendez correctement JFrame avec un super () et un constructeur, puis ajoutez des écouteurs d’action au cadre et ajoutez les boutons.

import Java.awt.event.ActionEvent;
import Java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;


public class Calc extends JFrame implements ActionListener {
    JButton button1 = new JButton("1");
    JButton button2 = new JButton("2");

    public Calc()
    {
         setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
         setSize(100, 100);
         button1.addActionListener(this);
         button2.addActionListener(this);
         calcFrame.add(button1);
         calcFrame.add(button2);
    }
    public void actionPerformed(ActionEvent e)
    {
        Object source = e.getSource();
        if(source == button1)
        {
            \\button1 code here
        } else if(source == button2)
        {
            \\button2 code here
        }
    } 
    public static void main(String[] args)
    {

        JFrame calcFrame = new JFrame();
        calcFrame.setVisible(true);
    }
}
0
Jon Takagi