Pregunta

Actualmente estoy trabajando en un código Java que tiene muchos ActionListeners definidos (uno para cada JButton) y hay alrededor de 60 botones.Todas ellas se definen como clases internas anónimas en el JButton.addActionListener método.He estado pensando en formas de refactorizar esto para que el código se vea más ordenado, ya que esto hace que parezca muy desordenado.Pensé en la posibilidad de llevar a los oyentes a una clase separada que esencialmente tenga una gran cantidad de métodos estáticos, cada uno de los cuales devuelve un oyente.Esto significará que el código se verá así addActionListener(GetActionListener.addActionListener()).Si bien esto lo hará más ordenado, creo que no es realmente una solución elegante.También pensé en un mapa final estático que contenga pares KV con el nombre del oyente para el propio oyente.Sin embargo, una vez más, esto todavía no parece una solución muy elegante.Me preguntaba si alguien tenía alguna idea.También debo decir que todos los actionListeners son bastante diferentes.

¿Fue útil?

Solución

Yo sugeriría no agregar directamente acciones usando ActionListener. Si lo hace de esta manera se convierte en no reutilizable. En lugar envolver sus acciones en la clase javax.swing.Action. Por lo que se puede reutilizar la acción donde quiera. Para por ejemplo, ahora puede usar la misma acción para por ejemplo un menú de acceso directo de una acción de copia y el botón de copia en la barra de herramientas. Básicamente, la idea es no acciones ejecutables directamente con par de elementos de interfaz gráfica de usuario.

Ahora que se acerca a su pregunta. Me gustaría hacer un repository of actions en una clase llamada, por ejemplo, con un ActionRepsoitory Action getAction(String) pública método público. Cada uno de su acción sería identificado por una constante de cadena que se utiliza para recuperar la acción desde el repositorio. Normalmente esa cadena sería el actionCommand para el elemento. La forma de administrar las acciones en el ActionRepository, a través de un HasMap o lo que sea, depende por completo de usted.

Esta es la forma de su doen en la mayoría de código profesional, que yo sepa.

Otros consejos

No es una duplicación de esta pregunta (que no era una duplicado de la pregunta que respondió ... WOW) pero la respuesta debe aplicarse.

Si sus clases internas están haciendo algo más que llamar a un método dentro de la clase externa, entonces lo está haciendo "mal" (a mi definición de "derecho"). En el código publicado las llamadas al incremento () y decremento () son la forma "correcta" de hacerlo. Refactorización del código tienen los oyentes desviar la llamada al método de la clase externa es un buen punto de partida para hacer el código más manejable.

Una vez dicho esto ... 60 botones de una interfaz de usuario ?! ¡De Verdad! ¡Ay! Están todos en una sola pantalla o se hace con pestañas o algo? (Si se trata de pestañas o algo tengo más que ofrecer en la respuesta).

Se podría hacer una subclase especial de ActionListener que utiliza la reflexión para llamar a un nombre de método dado, entonces se puede poner en práctica todas las 60 acciones como métodos 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);
        }
    }

}

y luego si un método call a su clase

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

a continuación, puede añadir sus acciones de la siguiente manera

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

Si uno de estos métodos no se encuentra, el programa fallará cuando la interfaz de usuario está construido (ya que las operaciones de búsqueda del método cuando se crea el oyente de action). Que no es tan agradable como en tiempo de compilación, pero aún mejor que tarde totalmente unida cuando se activa la acción.

Recomendaría algo como lo que sugirió: crear una clase de oyente única a la que se suscriba a todos los eventos.PROBABLEMENTE quieras usar una instancia diferente de la clase para cada evento, diciéndole a la instancia (en el constructor) en general qué hacer con este evento específico.

La ventaja de esto es que luego puedes comenzar a factorizar el código dentro de los oyentes en menos métodos porque generalmente es bastante similar.A veces puedes incluirlo en un solo método.

Un truco que he usado para una situación de "despacho puro" para la creación de menús fue especificar el menú, la estructura del menú y el método al que se vincula cada elemento del menú en los datos.Necesita un poco de reflexión pero funciona.

De hecho... déjame mirar.

Sí, guardé las clases en un documento de Google :) Los datos se especificaron así:

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

Simplemente analizó esto.El archivo se convierte en un elemento de nivel superior debido al inicio, guardar llamará a su método "Guardar", cargar llamará a su método "Cargar", Imprimir es un submenú (de ahí los pares), con vista previa debajo y la impresión no está vinculada a nada.

Esta cadena puede crear y vincular un menú completo con una sola llamada.

Aquí está mi código fuente si quieres jugar con él.

La clase "TestMenu" en la parte superior es una clase de prueba que demuestra cómo utilizar el método buildMenus.

Esto se hizo hace bastantes años, puede que ahora lo haga de manera diferente, pero funciona.No estoy seguro de que me guste que realmente genere el menú, y creo que haría que el analizador de cadenas use una sola cadena en lugar de dividirla en cadenas para cada elemento; debería ser fácil garantizar que cada elemento esté separado por espacios en blanco. ..

Una API mejor podría ser un método de vinculación como este:

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

donde presionar el botón Guardar haría que se llamara al método Guardar en este (o cualquier otro objeto que haya ingresado).Incluso podría hacer que el parámetro "guardar" sea opcional y simplemente usar JButton.getText().toLower() como método para llamar si no existe ningún parámetro (supongo que es una convención antes de la configuración)

No lo hice de esta manera con el menú porque también quería abstraer la creación del menú y las relaciones del menú en mis datos.

Tenga en cuenta que codificar de esta manera es una excelente manera de separar MVC en Java: todo el código de su controlador se puede eliminar de su vista.

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
}

}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top