Question

Je travaille actuellement sur un code Java qui a beaucoup de ActionListeners qui y sont définis (un pour chaque JButton) et il y a environ 60 boutons. Ceux-ci sont toutes définies comme les classes internes anonymes dans la méthode JButton.addActionListener. J'ai pensé à des façons de refactoriser cela pour rendre le code plus propre regard que ce fait, il avait l'air très encombré. Je pensais peut-être prendre les auditeurs dans une catégorie distincte qui a essentiellement une charge de méthodes statiques chaque retour d'un auditeur. Cela signifie que le code ressemblera à quelque chose comme addActionListener(GetActionListener.addActionListener()). Alors que cela rendra plus propre je pense que ce n'est pas vraiment une solution élégante. Je pensais aussi une carte finale de maintien statique paires de KV avec le nom de l'auditeur à l'auditeur lui-même. Encore une fois mais cela ne semble toujours pas comme une solution très élégante. Je me demandais si quelqu'un avait des idées? Je dois aussi dire que tous les ActionListeners sont assez différents.

Était-ce utile?

La solution

Je suggère de ne pas ajouter directement des actions en utilisant ActionListener. Si vous le faites de cette façon, il devient non réutilisable. envelopper vos actions au lieu en classe javax.swing.Action. Alors que vous pouvez réutiliser l'action où vous voulez. Pour vous pouvez par exemple utiliser la même action pour dire un raccourci de menu d'une action de copie et le bouton de copie dans la barre d'outils. Fondamentalement, l'idée est de ne pas coupler directement des actions avec des éléments exécutables GUI.

Venons-en maintenant à votre question. Je voudrais faire une repository of actions dans une classe appelée, par exemple, ActionRepsoitory avec une méthode publique Action getAction(String) publique. Chacune de vos actions seraient identifiées par une constante de chaîne que vous utilisez pour récupérer l'action du référentiel. En général cette chaîne serait le actionCommand pour l'élément. Comment vous gérez les actions dans le ActionRepository, via un HasMap ou autre, est complètement dépendant de vous.

Voici comment son doen dans la plupart du code proffesional, autant que je sache.

Autres conseils

pas une duplication de cette question (qui était pas double de la question, il a répondu ... wow) mais la réponse doit appliquer.

Si vos classes internes font plus que simplement appeler une méthode à l'intérieur de la classe externe, alors vous le faites « mal » (à ma définition de « droit »). Dans le code affiché les appels à incrément () et décrément () sont la « bonne » pour le faire. Refactorisation du code ont les auditeurs transférer l'appel de méthode à la classe externe est un bon endroit pour commencer à rendre le code plus facile à gérer.

Cela étant dit ... 60 boutons sur une interface utilisateur ?! Vraiment! Aie! Sont-ils tous sur un seul écran ou est-il fait avec des onglets ou quelque chose? (Si elle est quelque chose que je onglets ou ont plus à offrir dans la réponse).

Vous pouvez faire une sous-classe de ActionListener spécial qui utilise la réflexion pour appeler un nom de méthode donnée, vous pouvez mettre en œuvre toutes vos 60 actions que les méthodes normales.

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

}

et si vous une méthode call à votre classe

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

vous pouvez ajouter vos actions comme suit

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

si l'une de ces méthodes est manquante, le programme échouera lorsque l'interface est construite (puisque nous recherche la méthode lorsque l'auditeur d'action est créé). Ce qui est pas aussi bien au moment de la compilation, mais toujours mieux que tout retard lié lorsque l'action est déclenchée.

Je recommande quelque chose comme ce que vous suggérez - créer une seule classe d'écouteur qui vous êtes abonné à tous les événements. Vous voulez probablement utiliser une autre instance de la classe pour chaque événement si, en disant l'instance (dans le constructeur) en général quoi faire avec cet événement spécifique.

L'avantage de ceci est que vous pouvez alors commencer factorisation le code à l'intérieur des auditeurs ensemble en moins de méthodes, car il est généralement assez similaire. Parfois, vous pouvez l'obtenir en une seule méthode.

Un truc que je l'ai utilisé pour une situation « d'expédition pure » pour la création de menu était de spécifier le menu, la structure du menu et la méthode lien entre chaque élément de menu à des données. A besoin d'un peu de réflexion, mais cela fonctionne.

En fait -. Laissez-moi regarder

Oui, je gardais les classes dans un doc google :) Les données ont été spécifié comme ceci:

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

Il a juste analysé cela. Fichier devient un élément de niveau supérieur en raison du démarrage, sauf appellera votre méthode « Enregistrer », la charge appellera votre méthode « Load », Print est un sous-menu (d'où les parens), avec aperçu dessous et impression n'est pas lié à quoi que ce soit.

Cette chaîne peut créer et lier un menu entier avec un seul appel.

Voici mon code source si vous voulez jouer avec.

La classe « Testmenu » en haut est une classe d'essai montrant comment utiliser la méthode buildMenus.

Cela a été fait il y a quelques années, je pourrais le faire différemment maintenant, mais cela fonctionne. Je ne suis pas sûr que je l'aime générer effectivement le menu, et je pense que je ferais l'analyseur de chaîne utiliser une seule chaîne au lieu de le décomposer en chaînes pour chaque élément - devrait être facile à assurer que chaque élément est séparé des espaces. ..

Une meilleure API peut être une méthode de liaison comme ceci:

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

où en appuyant sur le bouton Enregistrer causerait la méthode d'enregistrement pour être appelé sur ce (ou tout autre objet que vous avez passé dans). Vous pouvez même faire le « sauver » paramètre optionnel et il suffit d'utiliser la JButton.getText () toLower (). Comme méthode pour appeler si aucun paramètre existe (je suppose que ce congrès avant la configuration)

Je ne le fais pas ainsi avec le menu parce que je voulais aussi faire abstraction sur la création de menu et les relations dans le menu mes données.

Notez que le codage de cette façon est un moyen génial pour obtenir votre séparation MVC en Java -. Tout le code du contrôleur peut être retiré de votre point de vue

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
}

}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top