Comment ajouter un écouteur d'action qui écoute plusieurs boutons
J'essaie de comprendre ce que je fais 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'action.
Ci-dessous est un programme simple que je tente d'obtenir un bouton de travail.
Qu'est-ce que je fais de 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)
}
}
L'écouteur d'action n'est jamais enregistré car avec le if(e.getSource() == button1)
Il ne peut pas voir button1
, les erreurs disant ne peuvent pas trouver le symbole.
9 réponses
Il n'y a pas de pointeur this
dans une méthode statique. (Je ne crois pas que ce code va même compiler.)
Vous ne devriez pas faire ces choses dans une méthode statique comme main()
; Configurez les choses dans un constructeur. Je n'ai pas compilé ou exécuté ceci pour voir si cela fonctionne réellement,mais essayez-le.
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)
}
}
Je suis étonné que personne n'ait mentionné l'utilisation d'une commande d'action. C'est une façon assez standard 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'use puisse appuyer sur la touche Entrée sur un champ de texte comme alternative à cliquer sur un bouton à côté)
- vous n'avez pas de référence au composant générant 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");
}
}
}
Voici une forme modifiée de la source basée sur mon commentaire. Notez que les interfaces graphiques devraient ê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);
}
}
Le problème est que button1 est une variable locale. Vous pouvez le faire en changeant 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.
On vous a dit comment trier 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 à jeter. Cela signifie des cas initiaux pour les noms de classe.
N'étendez pas les classes dont vous n'avez pas besoin.
JFrame
devrait rarement être étendu. En fait, vous ne créez pas une instance de votre classe dérivée!!!Ne pas regrouper un tas de choses dans une classe. En particulier, vous devriez généralement seulement sous-type au plus une classe principale ou une interface à la fois (des choses comme
Comparable
non inclus).Interagissez toujours, y compris les interfaces graphiques construct, Swing/AWT sur le Thread de répartition des événements AWT (EDT). C'est moche et verbeux, mais C'est Java pour vous.
Vérifier une source d'un événement est un peu de hack. Les auditeurs sont petits, donc vous ne pouvez même pas prétendre à l'excuse de performance boiteuse.
Donc:
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 avez besoin d'accéder à l'une des variables enfermant la méthode dans l'écouteur, faites-les final
.
Le premier problème est que button1
est une variable locale de la méthode main
, donc la méthode actionPerformed
n'y a pas accès.
Le deuxième problème est que la ActionListener
interface est implémentée par la classe calc
, mais aucune instance de cette classe est créée dans le main
méthode.
La façon habituelle de faire ce que vous voulez est de créer une instance de calc
et faire button1
un champ de la calc
classe.
Vous déclarez button1 dans la méthode principale 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)
}
Tout d'abord, exend JFrame correctement avec un super () et un constructeur ajoutez ensuite actionlisteners 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);
}
}
J'utilise " E. getActionCommand ().contains(CharSecuence s)", puisque Im provenant d'un contexte MVC, et le bouton est déclaré dans la classe View, mais l'appel actionPerformed se produit 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ôleur implémente ActionListener, et donc, en remplaçant 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 réponse est également utile.