Frage

Ich arbeite derzeit an einem Java-Code, in dem viele ActionListener definiert sind (einer für jeden). JButton) und es gibt etwa 60 Tasten.Diese sind alle als anonyme innere Klassen in definiert JButton.addActionListener Methode.Ich habe über Möglichkeiten nachgedacht, dies umzugestalten, damit der Code übersichtlicher aussieht, da er dadurch sehr unübersichtlich aussieht.Ich habe darüber nachgedacht, die Listener möglicherweise in eine separate Klasse aufzunehmen, die im Wesentlichen über eine Menge statischer Methoden verfügt, von denen jede einen Listener zurückgibt.Das bedeutet, dass der Code ungefähr so ​​aussieht addActionListener(GetActionListener.addActionListener()).Obwohl es dadurch übersichtlicher wird, bin ich der Meinung, dass es keine wirklich elegante Lösung ist.Ich dachte auch an eine statische endgültige Karte, die KV-Paare mit Listenernamen für den Listener selbst enthält.Auch dies scheint jedoch immer noch keine sehr elegante Lösung zu sein.Ich frage mich, ob jemand irgendwelche Ideen hat?Ich sollte auch sagen, dass alle actionListener ziemlich unterschiedlich sind.

War es hilfreich?

Lösung

Ich würde vorschlagen, Aktionen nicht direkt mit hinzuzufügen ActionListener.Wenn Sie auf diese Weise vorgehen, ist es nicht mehr wiederverwendbar.Packen Sie stattdessen Ihre Aktionen ein javax.swing.Action Klasse.Damit Sie die Aktion überall wiederverwenden können.Beispielsweise können Sie jetzt dieselbe Aktion beispielsweise als Menüverknüpfung einer Kopieraktion und für die Schaltfläche „Kopieren“ in der Symbolleiste verwenden.Grundsätzlich geht es nicht darum, ausführbare Aktionen direkt mit GUI-Elementen zu koppeln.

Kommen wir nun zu Ihrer Frage.Ich würde ein machen repository of actions in einer Klasse namens ActionRepsoitory mit einer öffentlichen Methode public Action getAction(String).Jede Ihrer Aktionen wird durch eine String-Konstante identifiziert, mit der Sie die Aktion aus dem Repository abrufen.Normalerweise wäre diese Zeichenfolge die actionCommand für das Element.Wie Sie die Aktionen im ActionRepository verwalten, über eine HasMap oder was auch immer, liegt vollständig bei Ihnen.

So wird es in den meisten professionellen Codes gemacht, AFAIK.

Andere Tipps

Keine Duplikat dieser Frage (was kein Duplikat der Frage war, die es beantwortete ...wow), aber die Antwort sollte zutreffen.

Wenn Ihre inneren Klassen mehr tun, als nur eine Methode innerhalb der äußeren Klasse aufzurufen, dann machen Sie es „falsch“ (nach meiner Definition von „richtig“).Im veröffentlichten Code sind die Aufrufe von increment() und decrement() der „richtige“ Weg, dies zu tun.Das Refactoring des Codes, bei dem die Listener den Methodenaufruf an die äußere Klasse weiterleiten, ist ein guter Anfang, um den Code besser verwaltbar zu machen.

Davon abgesehen...60 Schaltflächen auf einer Benutzeroberfläche?!Wirklich!Autsch!Befinden sie sich alle auf einem Bildschirm oder erfolgt dies über Tabs oder ähnliches?(Wenn es Tabs oder etwas anderes sind, habe ich in der Antwort mehr zu bieten).

Sie könnten daraus eine spezielle Unterklasse erstellen ActionListener Wenn Sie eine Methode verwenden, die Reflektion verwendet, um einen bestimmten Methodennamen aufzurufen, können Sie alle Ihre 60 Aktionen als normale Methoden implementieren.

package com.example;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class MethodAsActionListener implements ActionListener {

    private Object receiver;
    private Method method;

    public MethodAsActionListener(Object receiver, String name) {
        this.receiver = receiver;
        try {
            this.method = receiver.getClass().getDeclaredMethod(name);
        } catch (SecurityException e) {
           throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void actionPerformed(ActionEvent event) {
        try {
            method.invoke(receiver);
        } catch (IllegalArgumentException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }

}

und dann, wenn Sie eine Methode call zu deiner Klasse

private call(String name) {
    return new MethodAsActionListener(this, name);
}

Anschließend können Sie Ihre Aktionen wie folgt hinzufügen

button1.addActionListener(call("methodName1"));
button2.addActionListener(call("methodName2"));
button3.addActionListener(call("methodName3"));
button4.addActionListener(call("methodName4"));
button5.addActionListener(call("methodName5"));

Wenn eine dieser Methoden fehlt, schlägt das Programm beim Erstellen der Benutzeroberfläche fehl (da wir die Methode beim Erstellen des Aktions-Listeners nachschlagen).Das ist nicht so schön wie zur Kompilierzeit, aber immer noch besser als eine völlig späte Bindung, wenn die Aktion ausgelöst wird.

Ich würde etwas wie Ihren Vorschlag empfehlen: Erstellen Sie eine einzelne Listener-Klasse, die Sie für alle Ereignisse abonnieren.Wahrscheinlich möchten Sie jedoch für jedes Ereignis eine andere Instanz der Klasse verwenden und der Instanz (im Konstruktor) im Allgemeinen mitteilen, was mit diesem bestimmten Ereignis geschehen soll.

Dies hat den Vorteil, dass Sie dann damit beginnen können, den Code in den Listenern in weniger Methoden zu zerlegen, da er normalerweise ziemlich ähnlich ist.Manchmal kann man es in einer einzigen Methode zusammenfassen.

Ein Trick, den ich für eine „Pure Dispatch“-Situation zur Menüerstellung verwendet habe, bestand darin, das Menü, die Struktur des Menüs und die Methode anzugeben, mit der jeder Menüpunkt in Daten verknüpft ist.Braucht ein wenig Überlegung, aber es funktioniert.

In der Tat – lassen Sie mich nachsehen.

Ja, ich habe die Klassen in einem Google-Dokument gespeichert :) Die Daten wurden wie folgt angegeben:

final static String[] menus = { "File:*", "Save:save", "Load:load", "(", "Print:-", "Preview:preview", ")", "Quit:quit" };

Es hat das gerade analysiert.Durch den Start wird die Datei zu einem Element der obersten Ebene. Speichern ruft Ihre Methode „Speichern“ auf, Laden ruft Ihre Methode „Laden“ auf. Drucken ist ein Untermenü (daher die Klammern) mit einer Vorschau darunter und Drucken ist nicht gebunden zu irgendetwas.

Dieser String kann mit einem Aufruf ein ganzes Menü erstellen und binden.

Hier ist mein Quellcode wenn du damit spielen willst.

Die Klasse „TestMenu“ oben ist eine Testklasse, die die Verwendung der buildMenus-Methode demonstriert.

Das wurde schon vor einigen Jahren gemacht, vielleicht mache ich es jetzt anders, aber es funktioniert.Ich bin mir nicht sicher, ob mir die Generierung des Menüs tatsächlich gefällt, und ich denke, ich würde dafür sorgen, dass der String-Parser einen einzelnen String verwendet, anstatt ihn für jedes Element in Strings aufzuteilen – es sollte einfach sein, sicherzustellen, dass jedes Element durch Leerzeichen getrennt ist. ..

Eine bessere API könnte eine Bind-Methode wie diese sein:

bind(this, new JButton("Save"), "save", this);

Dabei würde das Drücken der Schaltfläche „Speichern“ dazu führen, dass die Speichermethode für dieses (oder ein anderes von Ihnen übergebenes Objekt) aufgerufen wird.Sie könnten den Parameter „save“ sogar optional machen und einfach JButton.getText().toLower() als aufzurufende Methode verwenden, wenn kein Parameter vorhanden ist (ich denke, das ist eine Konvention vor der Konfiguration).

Ich habe es beim Menü nicht so gemacht, weil ich auch die Menüerstellung und Menübeziehungen in meine Daten abstrahieren wollte.

Beachten Sie, dass das Codieren auf diese Weise eine großartige Möglichkeit ist, Ihre MVC-Trennung in Java zu erreichen – Ihr gesamter Controller-Code kann aus Ihrer Ansicht entfernt werden.

package hEvil;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.border.EmptyBorder;

public class JDial extends JDialog {

private static final long serialVersionUID = -26565050431585019L;
private final JPanel contentPanel = new JPanel();

public static void main(String[] args) {
    try {

        JDial dialog = new JDial();
        dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
        dialog.setVisible(true);
        dialog.setTitle("Heavy Evil");
        dialog.setBackground(Color.WHITE);

    } catch (final Exception e) {
        e.printStackTrace();
    }
}

public JDial() {
    setBounds(0, 0, 1300, 800);
    getContentPane().setLayout(new BorderLayout());
    contentPanel.setLayout(new FlowLayout());
    contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
    getContentPane().add(contentPanel, BorderLayout.CENTER);

    JPanel windowPane = new JPanel();
    windowPane.setLayout(new FlowLayout(FlowLayout.RIGHT));
    getContentPane().add(windowPane, BorderLayout.SOUTH);

    {
        JButton cancelButton = new JButton("Exit");
        cancelButton.setActionCommand("Exit");
        windowPane.add(cancelButton);
        cancelButton.setBounds(0, 0, 1200, 700);

    }

    {
        JPanel textPane = new JPanel();
        textPane.setLayout(new FlowLayout(FlowLayout.LEFT));
        getContentPane().add(textPane, BorderLayout.NORTH);
        textPane.setVisible(true);

        {
            JTextArea textArea = new JTextArea("Username", 2, 15);
            textPane.add(textArea);
            textArea.setWrapStyleWord(true);
            textArea.setEditable(true);
            textArea.setFont(Font.getFont(Font.SANS_SERIF));
            textArea.setVisible(true);
            textArea.enableInputMethods(isEnabled());
            textArea.computeVisibleRect(getBounds());
            textArea.setBackground(Color.GRAY);

            JTextArea textArea2 = new JTextArea("Password", 2, 15);
            textPane.add(textArea2);
            textArea2.setWrapStyleWord(true);
            textArea2.setEditable(true);
            textArea2.setFont(Font.getFont(Font.SANS_SERIF));
            textArea2.setVisible(true);
            textArea2.enableInputMethods(isEnabled());
            textArea2.computeVisibleRect(getBounds());
            textArea2.setBackground(Color.GRAY);

        }
        {

            JButton registerButton = new JButton("Register");
            textPane.add(registerButton);

        }
        {
            JButton newButton = new JButton("Submit");
            textPane.add(newButton);
            newButton.setEnabled(true);
            getRootPane().setDefaultButton(newButton);
            newButton.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent evt) {

                    JFrame newFrame = new JFrame("Welcome");
                    newFrame.setVisible(true);
                    newFrame.setBackground(Color.BLACK);
                    newFrame.setBounds(0, 0, 580, 200);

                    JPanel newPanel = new JPanel();
                    newFrame.add(newPanel);
                    dispose();

                    JButton nuButton = new JButton("Mario");
                    newPanel.add(nuButton);

                    JButton nuButton2 = new JButton("Kirby");
                    newPanel.add(nuButton2);

                    JButton nuButton3 = new JButton("Mew Two");
                    newPanel.add(nuButton3);

                    JButton nuButton4 = new JButton("Vegeta");
                    newPanel.add(nuButton4);

                    JButton nuButton5 = new JButton("Tidus");
                    newPanel.add(nuButton5);

                    JButton nuButton6 = new JButton("Link");
                    newPanel.add(nuButton6);

                    JButton nuButton7 = new JButton("Master Chief");
                    newPanel.add(nuButton7);

                    JButton nuButton8 = new JButton("Snake");
                    newPanel.add(nuButton8);

                    JButton nuButton9 = new JButton("Cash");
                    newPanel.add(nuButton9);

                    JButton nuButton10 = new JButton("Lara");
                    newPanel.add(nuButton10);

                    JButton nuButton11 = new JButton("Max");
                    newPanel.add(nuButton11);

                    JButton nuButton12 = new JButton("Spyro");
                    newPanel.add(nuButton12);

                    JButton nuButton13 = new JButton("Sephiroth");
                    newPanel.add(nuButton13);

                    JButton nuButton14 = new JButton("Scorpion");
                    newPanel.add(nuButton14);

                }
            });

        }

    }

}

}
//AND I WANT TO BE ABLE TO IMPLEMENT EACH BUTTON FROM ANOTHER CLASS
//FROM ACTIONEVENT WITH SOMETHINGS SIMILAR TO nuButtonX.actionImplemented...
//CALLING THE SAME ACTIONLISTENER IF I CAN AND THEN CREATING A CLASS FOR
//MODIFICATIONS AT EACH INSTANCE. 
enter code here
package hEvil;

import java.awt.event.ActionEvent;

import javax.swing.JFrame;

public class ActoEve extends ActionEvent {

/**
 * 
 */
private static final long serialVersionUID = -2354901917888497068L;
public ActoEve(Object arg0, int arg1, String arg2) {
    super(ActionEvent.ACTION_PERFORMED, arg1, "flame_001.jpg");
    // TODO Auto-generated constructor stub
}
public void actionImplemented(ActionEvent evt1) {


    JFrame nuFrame = new JFrame();
    nuFrame.setVisible(true);
    nuFrame.setBounds(0, 0, 300, 200);



    // TODO Auto-generated constructor stub
}

}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top