Вопрос

В настоящее время я работаю над каким -то кодом Java, в котором определено много ActionListeners (по одному для каждого JButton) и есть около 60 кнопок. Все они определены как анонимные внутренние классы в JButton.addActionListener метод Я думал о том, чтобы рефактор, чтобы код выглядел аккуратно, так как он выглядит очень загроможденным. Я подумал о том, чтобы отвезти слушателей в отдельный класс, который, по сути, имеет множество статических методов, каждый из которых возвращает слушателя. Это будет означать, что код будет выглядеть как addActionListener(GetActionListener.addActionListener()). Анкет Хотя это сделает его более аккуратным, я чувствую, что это не элегантное решение. Я также подумал, что статическая финальная карта, держащая пары KV с именем слушателя для самого слушателя. Опять же, однако это все еще не кажется очень элегантным решением. Мне было интересно, есть ли у кого -нибудь идеи? Я также должен сказать, что все ActionListeners довольно разные.

Это было полезно?

Решение

Я бы предложил не напрямую добавлять действия, используя ActionListener. Анкет Если вы это сделаете, это становится невозвратным. Вместо этого заверните свои действия javax.swing.Action учебный класс. Чтобы вы могли повторно использовать действие, где бы вы ни захотите. Например, теперь вы можете использовать то же действие, скажем, сочетание меню действия копии и кнопки копирования на панели инструментов. По сути, идея не в том, чтобы напрямую пару, выполняемые действиями с элементами графического интерфейса.

Теперь прихожу к вашему вопросу. Я бы сделал repository of actions В классе, называемом, скажем, ActionReppsotytory с публичным методом Action getAction(String). Анкет Каждое из вашего действия будет идентифицировано константой строки, которую вы используете для извлечения действия из репозитория. Обычно эта строка будет actionCommand для элемента. То, как вы управляете действиями в ActionRepository, через HASMAP или что -то в этом роде, полностью зависит от вас.

Вот как он в большинстве профессоров, AFAIK.

Другие советы

Не дублирование этого вопроса (Что не было дубликатом вопроса, на который он ответил ... вау), но ответ должен применяться.

Если ваши внутренние классы делают больше, чем просто вызывают метод внутри внешнего класса, то вы делаете это «неправильно» (к моему определению «Право»). В опубликованном коде призывы к увеличению () и decrement () являются «правильным» способом сделать это. Рефакторирование кода Получите слушателей пересылать вызов метода во внешний класс - хорошее место, чтобы начать сделать код более управляемым.

При этом ... 60 кнопок на пользовательском интерфейсе?! Действительно! Уч! Они все на одном экране или это сделаны с вкладками или что -то в этом роде? (Если это вкладки или что -то, что мне есть больше в ответе).

Вы можете сделать специальный подкласс ActionListener Это использует отражение, чтобы вызвать заданное имя метода, тогда вы можете реализовать все свои 60 действий как обычные методы.

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

}

А потом, если вы метод call в ваш класс

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

тогда вы можете добавить свои действия следующим образом

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

Если один из этих методов отсутствует, программа потерпит неудачу при создании пользовательского интерфейса (поскольку мы ищем метод при создании слушателя действий). Что не так хорошо, как во время компиляции, но все же лучше, чем полностью позднее, когда действие запускается.

Я бы порекомендовал что-то вроде того, что вы предложили-создайте один класс слушателей, который вы подписываете на все события. Вы, вероятно, хотите использовать другой экземпляр класса для каждого события, хотя, сообщая экземпляр (в конструкторе) в целом, что делать с этим конкретным событием.

Преимущество этого заключается в том, что вы можете начать учитывать код внутри слушателей вместе в меньшее количество методов, потому что он обычно очень похож. Иногда вы можете получить его в один метод.

Одним из трюков, который я использовал для ситуации с «чистой диспетчерской» для создания меню, было указать меню, структуру меню и метод, с которым каждый пункт меню ссылается в данные. Нужно немного размышлять, но это работает.

На самом деле-дай мне взглянуть.

Да, я держал занятия в Google Doc :) Данные были указаны так:

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

Это просто проанализировало это. Файл становится элементом верхнего уровня из-за начала, сохранение будет вызвать ваш метод «Сохранить», загрузка будет вызвать ваш метод «загрузки», печать-это подменю (отсюда и парюр), с предварительным просмотром под ним, а печать не связана к чему -либо.

Эта строка может создавать и связывать целое меню с одним вызовом.

Вот Мой исходный код Если вы хотите играть с этим.

Класс «Testmenu» вверху - это класс тестирования, демонстрирующий, как использовать метод BuildMenus.

Это было сделано довольно много лет назад, теперь я мог бы сделать это по -другому, но это работает. Я не уверен, что мне нравится, что он на самом деле генерирует меню, и я думаю, что я бы заставил картеш-анализатор использовать одну строку вместо того, чтобы разбить его на строки для каждого элемента-должно быть легко гарантировать, что каждый элемент разделен пробел. ..

Лучшим API может быть методом привязки, подобного этому:

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

Там, где нажатие кнопки «Сохранить» приведет к тому, что метод сохранения будет вызван на это (или любой другой объект, в котором вы передали). Вы можете даже сделать параметр «Сохранить» необязательным и просто использовать jbutton.getText (). Tolower () в качестве метода для вызова, если параметр не существует (я думаю, это соглашение перед конфигурацией)

Я не делал этого с меню, потому что я также хотел абстрагировать создание меню и отношения меню в свои данные.

Обратите внимание, что кодирование таким образом-отличный способ получить отделение MVC на Java-все ваш код контроллера можно удалить с вашего представления.

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
}

}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top