Может ли добавление ActionListener быть коротким? Могу ли я добавить аргументы в actionPerformed? - PullRequest
3 голосов
/ 25 марта 2010

У меня есть большая таблица с кнопкой в ​​каждой ячейке. Эти кнопки очень похожи и делают почти то же самое. Если я добавлю слушатель действия для каждой кнопки следующим образом:

tmp.addActionListener(new ActionListener(){
   @Override
   public void actionPerformed(ActionEvent evt) {
      proposition = proposition + action;
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            updatePropositionPanel();
         }
      });
   }
});

На самом деле каждый слушатель действия отличается от всех других значением action. proposition и updatePropositionPanel - это поле и метод класса.

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

  2. Затем я решил добавить метод actionPerformed к текущему классу и сделать это: addActionListener(this). Но потом я понял, что не знаю, как аргументировать метод actionPerformed.

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

ДОБАВЛЕНО:

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

Ответы [ 8 ]

4 голосов
/ 25 марта 2010

Вы можете создать свой собственный класс и передать данные в конструктор.Например,

public class MyActionListener
{
    private int proposition;
    private MyOtherClass moc;

    public MyActionListener(int proposition, MyOtherClass moc) {
        this.proposition = proposition;
        this.moc = moc;
    }

    public void actionPerformed(ActionEvent evt) {
        proposition += moc.action;
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                moc.updatePropositionPanel();
            }
        });
    }
}

Затем вы можете добавить его как обычно, передавая конструктору любые аргументы, которые вам нравятся:

tmp.addActionListener( new MyActionListener(proposition, this) );
1 голос
/ 25 марта 2010

Поскольку единственное отличие заключается в значении action, вы можете поместить код в метод. (Также @Override не требуется, и += здесь полезно.)

public void setup(
    final AbstractButton button,
    final int action
) { 
    button.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent evt) {
            proposition += action;
            EventQueue.invokeLater(new Runnable() {
                public void run() {
                   updatePropositionPanel();
                }
           });
        }
    });
}

Возможно, что invokeLater бессмысленно, так как вы все равно будете в потоке рассылки событий AWT (EDT).

Если вы добавляете много действий общего назначения, то вы можете упростить их, используя интерфейс, с которым не связан бессмысленный объект события.

Если вы хотите быть хакером, вы можете добавить слушателя в конструктор подкласса.

    new ActionHandler(button) { public void action() {
        proposition += action;
        updatePropositionPanel();
    }});

Надеюсь, JDK7 сделает синтаксис Java для такого рода вещей менее подробным. Java, однако, всегда будет несколько многословным.

1 голос
/ 25 марта 2010

РЕДАКТИРОВАТЬ : Я изменил класс, чтобы показать конструкцию с MyOuterClass.

Вот набросок кода. Надеюсь, это получится на вашем 1, как я бы это реализовал.

public class MyOuterClass {
    // member variables for MyOuterClass

    public MyOuterClass() {
        // ...constructor stuff here
    }
    // ...outer class stuff here - methods, etc.

    // The code each place you want to add the listener, somewhere in MyOuterClass
    tmp.addActionListener(new MyActionListener(poposition, action));


    // below outer class stuff, although it can really be most places, I usually put
    // it here - personal style preference.  Swing's classes often put inner
    // classes first

    /**
     * An inner class.
     */
    private MyActionListener implements ActionListener {
        /**
      * Object used here as a filler, replace with appropriate
      * class types
      */
        private Object proposition;
        private Object action;

        private MyActionListener(Object proposition, Object action) {
            this.proposition = proposition;
            this.action = action;
        }
        public void actionPerformed(ActionEvent evt) {
          proposition = proposition + action;
          SwingUtilities.invokeLater(new Runnable() {
             public void run() {
                updatePropositionPanel();
             }
        }
        /**
         * Setters provided in case you need to change proposition and action.  If not,
         * feel free not to have them and to have final members
         */
        private void setProposition(Object proposition) {
            this.proposition = proposition;
        }
        private void setAction(Object action) {
            this.action = action;
        }
    }
}

РЕДАКТИРОВАТЬ : Чтобы создать другой класс, как вы просили при редактировании, сделайте, как указано выше, но создайте не приватный другой класс в другом файле .java и удалите код.

0 голосов
/ 25 марта 2010

Вы не сказали, сколько кнопок вы говорите.

Если это небольшое число, например, шахматная доска или меньше, подход @ juskt будет хорошим.

Однако, если вы смотрите на что-то большее, я бы использовал этот подход:

public class MyActionListener {
      public void actionPerformed(ActionEvent evt) {
          JComponent c = (JComponent)evt.getSoource();
          int prop = (Integer)c.getclientProperty("PROPOSITION");
          int act = (Integer)c.getclientProperty("ACTION");
          SomeClass obj = c.getclientProperty("UPDATE");
          prop += act;
          // If necessary, clientPut("PROPOSITION", prop);
          SwingUtilities.invokeLater(new    Runnable() {
              public void run() {
                  obj.updatePropositionPanel();
              }
          });
      }
}

Этот слушатель действия не имеет состояния. В результате один экземпляр может использоваться для всех кнопок. Для чего-то вроде доски Го (19x19) это работает на 1 объект вместо 361.

0 голосов
/ 25 марта 2010

Я предполагаю, что ваше предложение и переменные действия являются строками для примера. Определите интерфейс PropositionUpdater, интерфейс PropositionPanelUpdater и держатель предложения для соавтора:

public interface PropositionUpdater() {
    public void updateProposition(PropositionHolder holder, String action);
}

public interface PropositionHolder() {
    public String getProposition();

    public void setProposition(String proposition);
}

public interface PropositionPanelUpdater() {
    public void updatePropositionPanel();
}

Реализация по умолчанию средства обновления предложений выглядит следующим образом:

public class DefaultPropositionUpdater implements PropositionUpdater {
    public void updateProposition(final PropositionHolder holder, final String action) {
        holder.setProposition(holder.getProposition() + action);
    }
}

Я оставлю значения по умолчанию для PropositionHolder и PropositionPanelUpdater для вашего воображения;)

Теперь, вот ваш слушатель действия:

public class PropositionUpdaterActionListener implements ActionListener {
    private PropositionHolder holder;

    private PropositionUpdater updater;

    private PropositionPanelUpdater panelUpdater;

    public PropositionUpdaterActionListener(final PropositionHolder holder, final PropositionUpdater updater, final PropositionPanelUpdater panelUpdater) {
        super();
        this.holder = holder;
        this.updater = updater;
        this.panelUpdater = panelUpdater;
    }

    public void actionPerformed(final ActionEvent evt) {
        //Not sure how you *got* the action, but whatever...
        updater.updateProposition(holder, action);
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                panelUpdater.updatePropositionPanel();
            }
        });
    }
}
0 голосов
/ 25 марта 2010

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

Вызов для добавления слушателя будет выглядеть примерно так:

tmp.addActionListener(new MyActionListenerSubClass(proposition, action));
0 голосов
/ 25 марта 2010

Вы можете создать отдельный класс MyActionListener и передать предложение с двумя значениями и действие с конструктором. Обезвреживает исходный код.

0 голосов
/ 25 марта 2010

Опция 1 работает, если вы сделаете proposition изменяемым (например, StringBuilder вместо String). Вариант 2 работает, если вы объявите их final. Таким образом, они доступны / видимы во внутреннем классе.

...