2009-05-21 12 views
5

Ich habe vor kurzem eine Programmieraufgabe gemacht, die es erforderte, dass wir in einem Programm ein Programm implementieren, das durch ein UML-Diagramm spezifiziert wurde. An einem Punkt gab das Diagramm an, dass ich eine anonyme JButton erstellen musste, die eine Zählung (beginnend bei 1) anzeigte und bei jedem Klicken dekrementierte. Der JButton und sein ActionListener mussten beide anonym sein.Java anonyme Klasse, die ActionListener implementiert?

kam ich auf die folgende Lösung:

public static void main(String[] args) { 
    JFrame f = new JFrame("frame"); 
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    f.setSize(400, 400); 

    f.getContentPane().add(new JButton() { 

    public int counter; 

    { 
     this.counter = 1; 
     this.setBackground(Color.ORANGE); 
     this.setText(this.counter + ""); 

     this.addActionListener(new ActionListener() { 
     public void actionPerformed(ActionEvent arg0) { 
      counter --; 
      setText(counter + ""); 
     } 
     }); 

    } 
    }); 

    f.setVisible(true); 

}

Diese anonyme JButton fügt hinzu, dann fügt eine weitere (innen) anonyme Action Ereignisse zu behandeln und der Schaltfläche Text falls erforderlich aktualisieren. Gibt es eine bessere Lösung? Ich bin mir ziemlich sicher, dass ich keinen anonymen JButton implements ActionListener() deklarieren kann, aber gibt es noch einen eleganteren Weg, um das gleiche Ergebnis zu erzielen?

+0

Schauen Sie, wo Sie jetzt sind @ Tim – Insane

Antwort

11

Ich gehe in der Regel etwas wie folgt aus:

JPanel panel = new JPanel(); 
panel.add(new JButton(new AbstractAction("name of button") { 
    public void actionPerformed(ActionEvent e) { 
     //do stuff here 
    } 
})); 

Abstract implements Action so sollte dies die Aufgabe erfüllen.

Es kann eine schlechte Übung sein, so viele Codezeilen zusammen zu quetschen, aber wenn Sie daran gewöhnt sind, es zu lesen, dann kann es ziemlich elegant sein.

+0

Dies nicht wirklich ermöglicht es Ihnen, ändere den Text der Buttons innerhalb des Action-Listeners ... Das ist eine ziemlich peinliche Anforderung und ich kann mir keinen Weg vorstellen, wie du das verbessern kannst dy haben. – Cogsy

+0

Also die öffentliche Deklaration von Zähler innerhalb der anonymen JButton und der unqualifizierte Zugriff darauf aus dem ActionListener sind OK? – Tim

+0

Yup, es ist die einzige Möglichkeit, einen "Griff" auf diese Felder zu bekommen. Denken Sie daran, dass die Felder in der inneren Klasse Felder desselben Namens ausblenden, die im äußeren Bereich deklariert sind. Hoffentlich warnt Sie Ihr Compiler/IDE ausdrücklich. – Cogsy

1

Ich würde so etwas in einem realen Programm nicht tun, aber angesichts der Anforderungen in Ihrem Auftrag, können Sie kaum besser machen.

1

Nun, es gibt einen viel eleganteren Weg, es zu tun.

Leider ist es kein Core Java/Swing Ansatz.

Sie können SwingBuilder in Groovy verwenden, um das gleiche Ergebnis zu erzielen, indem Sie eine etwas engere Syntax verwenden, z. Pseudo-Code:

button(text: '' + counter, 
     actionPerformed: {counter--; text = '' + counter + ''}, 
     constraints:BL.SOUTH) 

[http://groovy.codehaus.org/Swing+Builder][1]

Ich würde dies allerdings nicht in Ihrer Zuordnung verwenden, ich habe Studenten gesehen wirklich weicht von der Norm und erhält für sich markiert nach unten, aber zumindest Sie kann es als einen möglichen Weg einschließen, um weiter zu untersuchen.

Ich denke, was Sie derzeit haben, ist absolut in Ordnung.

2

Die Implementierung mehrerer Typen ist im Allgemeinen eine schlechte Idee.

Es ist selten notwendig, JComponent Klassen zu erweitern, obwohl viele schlechte Software und Tutorials es tun. Ein Idiom/Hack, das in letzter Zeit an Boden gewinnt, ist Double Brace - eine Klasse ist nur Unterklassen, um ihr einen Instanzinitialisierer zu geben, der sich wie eine with Anweisung aus anderen Sprachen verhält.

In diesem Fall kann der entsprechende Code geschrieben werden als:

JButton button = new JButton(); 
button.addActionListener(new ActionListener() { 
    int counter = 1; 
    { 
     updateText(); 
    } 
    public void actionPerformed(ActionEvent arg0) { 
     --counter; 
     updateText(); 
    } 
    private void updateText() 
     setText(Integer.toString(counter)); 
    } 
}); 
f.getContentPane(button); 

Wenn es komplizierter wird, dann wollen Sie wahrscheinlich eine äußere Klasse (das nicht implementiert ActionListener oder erweitern JButton) machen um mit den Daten umzugehen.

Beachten Sie auch, dass Sie die EventQueue.invokeLater Boilerplate verwenden sollten, um sicherzustellen, dass Swing-Komponenten nur auf dem AWT EDT verwendet werden.

+2

updateText funktioniert nicht nur mit setText - ich denke, Sie brauchen button.setText, oder um den Listener in eine neue anonyme Unterklasse von JButton zu verschachteln. Auch f.getContentPane nimmt keine Argumente, ich denke du meinst f.getContentPane.add (button). –

+0

+1 für das Nicht-Erweitern von JButton für Konfigurationsgründe – kleopatra

4

Es ist ziemlich hässlich, aber man konnte die folgende Verwendung des Action Verfahren und eine anonyme Klasse tun:

f.getContentPane().add(new JButton(new AbstractAction("name of button") { 
     private int counter = 0; 

     public void actionPerformed(ActionEvent e) { 
      ((JButton) e.getSource()).setText(Integer.toString(counter--)); 
     } 
    }) { 
     { 
      setText("1"); 
     } 
    }); 

Um es einfacher, den Zähler zu öffnen würden wir Sie es aus auf der obersten Ebene der Klasse bewegen konnte und greifen Sie von beiden Stellen, an denen setText aufgerufen wird, darauf zu.

+0

+1. Es könnte "hässlich" (dein Wort, nicht meins) sein, aber ich finde es leichter zu verstehen als der Code in der Frage. Ich denke, die einzige Frage wäre, ob sie die Kriterien erfüllt, dass "The JButton und sein ActionListener beide anonym sein mussten". AbstractAction implementiert ActionListener, aber der Kursleiter könnte das Gefühl haben, dass die Kriterien nicht erfüllt wurden. –

0

Dies ist einer der schlecht-Praxis Aufgaben in Hausaufgaben ;-) nur Bad Dinge zu tun gezwungen:

  • Nutzung von Action statt Aktion, die
  • als Folge an sich schlecht ist, Scoping Probleme sprudeln
    • Zähler Anwendungsbereich breiter als notwendig
    • benötigen Zugriff auf Taste innerhalb des actionPerformed (via Typ-Guss- oder Zugriff umgebenden Objekts api)
  • unlesbar (aka: wartbaren Code)

Aber dann können .. wir nicht widerstehen, können wir hier eine Version mit Aktion ;-), die sauber ist (oder so glaube ich) in Bezug auf die ersten beiden Ausgabe, unleserlich wie alle anderen Beispiele (und ich betrogen, natürlich: zuerst die anonyme Klassen implementiert, dann lassen Sie die IDE tun die Inline-

f.add(new JButton(new AbstractAction() { 

     int counter = 1; 
     { // constructor block of action 
      updateName(); 
     } 

     @Override 
     public void actionPerformed(ActionEvent e) { 
      counter--; 
      updateName(); 
     } 

     private void updateName() { 
      putValue(Action.NAME, "" + counter); 
     } 

    }) { // subclass button 
      { // constructor block button 
      setBackground(Color.PINK); 
     }} 
    ); 
Verwandte Themen