Domanda

Mi è stato recentemente facendo un incarico di programmazione che ci ha richiesto di implementare nel codice di un programma specificato da un diagramma UML. A un certo punto, lo schema specificato che ho dovuto creare un JButton anonima che ha visualizzato un conteggio (a partire da uno) e decrementato ogni volta che è stato cliccato. Il JButton e la sua ActionListener entrambi dovevano essere anonimi.

Sono venuto con la seguente soluzione:

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);

}

Questo aggiunge un JButton anonima, poi aggiunge un altro (interno) ActionListener anonimo per gestire gli eventi e aggiornare il testo del pulsante, se necessario. C'è una soluzione migliore? Sono abbastanza sicuro che non posso dichiarare un JButton implements ActionListener () anonima, ma c'è un altro modo più elegante per ottenere lo stesso risultato?

È stato utile?

Soluzione

Di solito andare qualcosa come questo:

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

AbstractAction implementa ActionListener quindi questo dovrebbe soddisfare il compito.

Può essere cattiva pratica di schiacciare tante righe di codice insieme, ma se siete abituati a leggerlo allora può essere molto elegante.

Altri suggerimenti

E 'abbastanza brutto, ma si potrebbe fare quanto segue con il metodo ActionListener e una classe anonima:

  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");
      }
  });

Per rendere più facile l'accesso al bancone si poteva spostarlo verso il livello superiore della vostra classe e accedervi da entrambi i luoghi in cui è chiamato setText.

L'implementazione più tipi è generalmente una cattiva idea.

Raramente è necessario estendere le classi JComponent, anche se un sacco di software cattivo e tutorial farlo. Un idioma / hack che è stato guadagnando terreno recentemente è doppio Brace -. Una classe è solo sottoclassi, al fine di dare un esempio initialiser che si comporta come una dichiarazione with da altre lingue

In questo caso, il codice in questione può essere scritta come:

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);

Se diventa più complesso, quindi probabilmente si vorrà fare una classe esterna (che non implementa ActionListener o estendere JButton) per gestire i dati.

Si noti inoltre, si dovrebbe utilizzare il boilerplate EventQueue.invokeLater per garantire che siano sempre e solo utilizzati sul AWT EDT componenti Swing.

Non vorrei fare qualcosa di simile in un programma di mondo reale, ma dato i requisiti di cui il vostro compito, difficilmente si può fare meglio.

Beh c'è un modo molto più elegante per farlo.

Purtroppo, non è un / approccio core Java Swing.

È possibile utilizzare SwingBuilder in Groovy per ottenere lo stesso risultato, utilizzando la sintassi un po 'più concisa, per esempio Codice pseudo:

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

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

Non vorrei usare questo nel tuo incarico, però, ho visto gli studenti davvero deviare dalla norma e ottenere segnato per questo, ma almeno si può comprendere come una possibile via di indagare ulteriormente.

Credo che quello che hai in questo momento è assolutamente bene però.

Questo è uno dei compiti bad-pratica costretti a fare i compiti a casa le cose solo ;-) Bad:

  • Utilizzo di ActionListener invece di azione che è un male in sé
  • di conseguenza, scoping problemi bolla
    • portata del contatore più ampia del necessario
    • bisogno di accedere al pulsante all'interno del actionPerformed (tramite tipo pressofuso o l'accesso API dell'oggetto circostante)
  • illeggibile: Codice (aka impossibile da mantenere)

Ma, poi .. non possiamo resistere, possiamo ;-) Ecco una versione con azione che è pulito (o almeno così credo) per le prime due edizione, indecifrabile come tutti gli altri esempi (e ho barato, naturalmente : prima attuato le classi anonime, poi lasciare l'IDE fare la linea

    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);
        }}
    );
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top