Pergunta

Atualmente, estou trabalhando em algumas código Java que tem um monte de ActionListeners nele definidas (uma para cada JButton) e há cerca de 60 botões.Estas são definidas como anónimo classes internas no JButton.addActionListener o método.Eu estive pensando em maneiras para refatorar isso para tornar o código olhar mais puro como isso está se tornando parecia muito confuso.Eu pensei sobre a possibilidade de tomar os ouvintes em uma classe separada que, essencialmente, tem uma carga de métodos estáticos cada um retornando um ouvinte.Isto significa que o código será algo parecido com addActionListener(GetActionListener.addActionListener()).Enquanto isso, o mais puro que eu sinto que realmente não é uma solução elegante.Eu pensei também um estática do mapa final de detenção KV pares com o nome de ouvinte para ouvinte em si.Novamente, no entanto, isso ainda não parece ser uma solução elegante.Eu estava me perguntando se alguém tinha alguma idéia?Gostaria também de dizer que todos os actionListeners são muito diferentes.

Foi útil?

Solução

Gostaria de sugerir para não adicionar diretamente ações usando ActionListener.Se você fizer desta forma, torna-se não-reutilizáveis.Em vez de moldar suas ações no javax.swing.Action de classe.De modo que você pode reutilizar a ação onde você quiser.Para e.g agora você pode usar a mesma ação para dizer um menu de atalho de uma Cópia de ação e o botão copiar na barra de ferramentas.Basicamente, a idéia não é diretamente casal runnable ações com elementos da GUI.

Vindo agora à sua pergunta.Eu gostaria de fazer um repository of actions em uma classe chamada, digamos, ActionRepsoitory com um método público público Action getAction(String).Cada um de sua ação seria identificado por uma constante de Seqüência de caracteres que você usa para recuperar a ação a partir do repositório.Normalmente, a seqüência seria o actionCommand para o elemento.Como gerenciar as ações na ActionRepository, através de um HasMap ou o que seja, é completamente dependente de você.

Esta é a forma como a sua doen em mais profissional código, AFAIK.

Outras dicas

Não é uma duplicação desta pergunta (que não foi uma duplicata da pergunta que ela respondeu ... uau), mas a resposta deve ser aplicada.

Se suas classes internas estiverem fazendo mais do que apenas chamar um método dentro da classe externa, você está fazendo isso "errado" (para minha definição de "certo"). No código publicado, as chamadas para increment () e decrement () são a maneira "certa" de fazê -lo. Refatorar o código Faça os ouvintes encaminhar a chamada do método para a classe externa é um bom lugar para começar a tornar o código mais gerenciável.

Sendo dito ... 60 botões em uma interface do usuário?! Sério! Ai! Eles estão todos em uma tela ou são feitos com guias ou algo assim? (Se são guias ou algo que tenho mais a oferecer na resposta).

Você poderia fazer uma subclasse especial de ActionListener Isso usa a reflexão para chamar um determinado nome do método e você pode implementar todas as suas 60 ações como métodos normais.

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

}

E então se você um método call para sua classe

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

Então você pode adicionar suas ações da seguinte maneira

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

Se um desses métodos estiver faltando, o programa falhará quando a interface do usuário for construída (já que procuramos o método quando o ouvinte de ação for criado). O que não é tão bom quanto em tempo de compilação, mas ainda melhor do que totalmente tarde quando a ação é acionada.

Eu recomendaria algo como o que você sugeriu-crie uma única classe de ouvinte que você assina em todos os eventos. Você provavelmente deseja usar uma instância diferente da classe para cada evento, dizendo à instância (no construtor) em geral o que fazer com este evento específico.

A vantagem disso é que você pode começar a fatorar o código dentro dos ouvintes juntos em menos métodos, porque geralmente é bem semelhante. Às vezes você pode colocá -lo em um único método.

Um truque que usei para uma situação de "despacho puro" para a criação de menus foi especificar o menu, a estrutura do menu e o método que cada item de menu vincula nos dados. Precisa de um pouco de reflexão, mas funciona.

Na verdade-me olhe.

Sim, eu mantive as aulas em um documento do Google :) Os dados foram especificados assim:

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

Apenas analisou isso. O arquivo se torna um item de nível superior devido ao início, o Salvar chama seu método "Salvar", o carregamento chamará seu método "Load", impressão é um submenu (daí o parens), com visualização abaixo e impressão não está ligada para qualquer coisa.

Essa string pode criar e vincular um menu inteiro com uma chamada.

Aqui está meu código -fonte Se você quiser brincar com isso.

A classe "testmenu" na parte superior é uma classe de teste que demonstra como usar o método Buildmenus.

Isso foi feito há alguns anos atrás, eu posso fazer de maneira diferente agora, mas funciona. Não tenho certeza se gosto que ele realmente gera o menu e acho que farei o analisador de cordas usar uma única string em vez de dividi-la em strings para cada item-deve ser fácil garantir que cada item seja o espaço em branco separado. ..

Uma API melhor pode ser um método de ligação como este:

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

Onde pressionar o botão Salvar faria que o método salvar fosse chamado sobre isso (ou qualquer outro objeto que você passou). Você pode até fazer o parâmetro "salvar" opcional e apenas usar o jbutton.getText (). Tolower () como o método a ser chamado se não existir parâmetro (acho que é a convenção antes da configuração)

Não fiz dessa maneira com o menu, porque também queria abstrair os relacionamentos de criação de menus e menu nos meus dados.

Observe que a codificação dessa maneira é uma maneira incrível de obter sua separação MVC em Java-todo o seu código do controlador pode ser removido da sua visualização.

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 em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top