Frage

Voller Haftungsausschluss:Ich bin ein CS-student, und diese Frage ist im Zusammenhang mit einem kürzlich zugewiesenen Java-Programm für die Objekt-Orientierte Programmierung.Obwohl wir haben getan einige Konsole Zeug, dies ist die erste Zeit, wir habe arbeitete mit einem GUI und Swing oder Awt.Wir erhielten einige code, der erstellt ein Fenster mit etwas text und eine Schaltfläche, gedreht durch die verschiedenen Farben für den text.Wir wurden dann gebeten, zu ändern das Programm zum erstellen von radio-buttons für die Farben statt—das war auch beabsichtigt, um uns die Praxis der Erforschung einer API.Ich habe schon abgegeben meiner Aufgabe und erhielt die Erlaubnis von meinem Lehrer, um poste meinen code hier.

Was ist der beste Weg, um zu implementieren, die Schaltfläche Aktionen in Java?Nach einigem hantieren, habe ich die buttons wie diese:

class HelloComponent3 extends JComponent
    implements MouseMotionListener, ActionListener
{
    int messageX = 75, messageY= 175;

    String theMessage;
    String redString = "red", blueString = "blue", greenString = "green";
    String magentaString = "magenta", blackString = "black", resetString = "reset";

    JButton resetButton;
    JRadioButton redButton, blueButton, greenButton, magentaButton, blackButton;
    ButtonGroup colorButtons;

    public HelloComponent3(String message) {

    theMessage = message;

    //intialize the reset button
    resetButton = new JButton("Reset");
    resetButton.setActionCommand(resetString);
    resetButton.addActionListener(this);

    //intialize our radio buttons with actions and labels
    redButton = new JRadioButton("Red");
    redButton.setActionCommand(redString);
    ...

Und action-Listener Hinzugefügt...

redButton.addActionListener(this);
blueButton.addActionListener(this);
...

Ein stub wurde bereits für die actionPerformed-Methode, um uns eine Idee auf, wie es zu benutzen, aber da gab es nur eine einzige Schaltfläche in der Vorlage, es war nicht klar, wie zu implementieren Sie mehrere buttons.Ich habe versucht, das Umschalten auf einen String, aber schnell gemerkt, dass da ein String ist kein primitiver Typ, ich konnte es nicht verwenden für eine switch-Anweisung.Hätte ich improvisierte mit einer if-else-Kette, aber das ist, was ich kam mit statt.Es scheint weit von elegant, und es muss einen besseren Weg.Wenn es ist, was es ist?Gibt es eine Möglichkeit, um Schalter auf einer Schnur?Oder wählen Sie eine Aktion in einem skalierbaren Mode?

public void actionPerformed(ActionEvent e){

    if (e.getActionCommand().equals(resetString)) {
        messageX = 75; messageY = 175;
        setForeground(Color.black);
        blackButton.setSelected(true);
        repaint();
        return;
    }

    if ( e.getActionCommand().equals(redString) ) {
        setForeground(Color.red);
        repaint();
        return;
    }

    if ( e.getActionCommand().equals(blueString) ) {
        setForeground(Color.blue);
        repaint();
        return;
    }

    if ( e.getActionCommand().equals(greenString) ) {
        setForeground(Color.green);
        repaint();
        return;
    }

    if ( e.getActionCommand().equals(magentaString) ) {
        setForeground(Color.magenta);
        repaint();
        return;
    }

    if ( e.getActionCommand().equals(blackString) ) {
        setForeground(Color.black);
        repaint();
        return;
    }
}
War es hilfreich?

Lösung

Statt diese schriftlich:

resetButton.addActionListener(this);

Sie können auch schreiben Sie diese:

resetButton.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent evt) {
        resetButtonActionPerformed(evt);
    }
});

Und statt zu schreiben eine große actionPerformed() für alle Aktionen, die Sie können (und dann) schreiben diese:

public void resetButtonActionPerformed(ActionEvent evt) {
    messageX = 75; messageY = 175;
    setForeground(Color.black);
    blackButton.setSelected(true);
    repaint();
}

Ich weiß nicht, ob dies ist die eleganteste Lösung, aber zumindest werden Sie nicht mehr die große if-Konstrukt.

Andere Tipps

Zwei alternative Ansätze:

  1. Erstellen Sie eine neue Klasse, die den Aktion-Schnittstelle implementiert und verfügt über ein Farbfeld und eine actionPerformed Methode, die die Farbe
  2. setzt
  3. eine HashMap von Befehlsnamen mantain Instanzen auf Farbe und die Befehlsnamen in der Karte nachschauen

Ein anständig genug Ansatz ist es, einen Enum, deren Elemente entsprechen Ihrer Strings zu erklären und Schalter auf valueOf (str) (das verknüpfte Beispiel zeigt, wie dies mit ziemlicher Sicherheit zu tun).

Der Grund anonyme innere Klassen zu vermeiden, ist wahrscheinlich, weil die Klasse, dass Konstrukt nicht gehabt hat (noch) nicht, auch wenn das vielleicht die beste Lösung sein.

Wie bereits angedeutet, können Sie anonyme innere Klassen verwenden, um die Action Schnittstelle zu implementieren. Als Alternative haben Sie keine anonyme innere Klassen zu verwenden, aber Sie können stattdessen eine einfache geschachtelte Klasse verwenden:

resetButton = new JButton(new ResetAction());
redButton = new JButton(new ColorAction("Red", Color.red));

und dann ...

private class ResetAction extends AbstractAction {
    public ResetAction() {
        super("Reset");
    }

    public void actionPerformed(ActionEvent e) {
        messageX = 75; messageY = 175;
        setForeground(Color.black);
        blackButton.setSelected(true);
        repaint();
    }
}

private class ResetAction extends AbstractAction {
    private Color color;

    public ColorAction(String title, Color color) {
        super(title);
        this.color = color;
    }

    public void actionPerformed(ActionEvent e) {
        setForeground(color);
        repaint();
    }
}

, warum dieser Ansatz - oder jeder Ansatz, die inneren Klassen - ist besser als Action in der äußeren Klasse Umsetzung „Design Patterns“ finden Sie unter:

„Favor‚Objekt-Komposition‘über‚Klassenvererbung‘.“ (Gang of Four 1995: 20)

zwischen anonymen inneren Klassen auswählen und diesen genannten inneren Klassen ist eine weitgehend eine Frage des Stils, aber ich denke, diese Version einfacher zu verstehen ist, und klarer, wenn es viele Aktionen.

Ergh. Sie nicht Massen von nicht verwandten Schnittstellen in einer Mega-Klasse implementieren. Verwenden Sie stattdessen anoymous innere Klassen. Sie sind ein wenig ausführlich, aber sind das, was Sie wollen. Verwenden Sie eine für jedes Ereignis, dann brauchen Sie nicht groß if-else-Kette. Ich schlage vor, halte genug Code innerhalb der inneren Klasse, um die Veranstaltung und Call-Methoden zu entschlüsseln, den Sinn zu den Zielobjekten machen. Darüber hinaus können Sie Ihre inneren Klassen parametrisieren. Sie werden Sie wahrscheinlich nicht finden, um Verweise auf die tatsächlichen Widgets halten müssen.

In Ihrem Beispiel scheinen Sie eine JComponent als JPanel mit werden. Es gibt nicht viel Unterschied, aber verwendet JPanel für einen Block von Widgets zu sammeln. Weiterhin gibt wahrscheinlich keine Notwendigkeit, es zu Unterklasse, also nicht.

So zum Beispiel:

   addColorButton("Green" , Color.GREEN );
   addColorButton("Red"   , Color.RED   );
   addColorButton("Yellow", Color.YELLOW);
   addColorButton("Blue"  , Color.BLUE  );
   ...

private void addColorButton(String label, Color color) {
    JRadioButton button = new JRadioButton(label);
    button.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent event) {
            target.setForeground(color);
            target.repaint();
        } 
    });
    colorGroup.add(button);
    panel.add(button);
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top