Может ли добавление ActionListener быть коротким?Могу ли я добавить аргументы к выполненному действию?
-
22-09-2019 - |
Вопрос
У меня есть большая таблица, содержащая кнопку в каждой ячейке.Эти кнопки очень похожи и выполняют почти то же самое.Если я добавлю прослушиватель действий к каждой кнопке таким образом:
tmp.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent evt) {
proposition = proposition + action;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
updatePropositionPanel();
}
});
}
});
На самом деле, каждый прослушиватель действий отличается от всех остальных значением action
. proposition
и updatePropositionPanel
являются полем и методом класса.
Сначала я подумал, что смогу сделать это короче, если не буду использовать внутренние классы.Итак, я решил запрограммировать новый класс ActionListener.Но потом я понял, что в этом случае "предложение" не будет видно экземплярам этого класса.
Затем я решил добавить метод actionPerformed в текущий класс и сделать это:
addActionListener(this)
.Но потом я понял, что я не знаю, как приводить аргументы к методу actionPerformed.
Итак, как это работает.Могу ли я добавить прослушиватель действий коротким и элегантным способом?
ДОБАВЛЕННЫЙ:
Мне понравилась идея запрограммировать внутренний класс с конструктором, который может принимать некоторые аргументы, и методом actioPerformed, который может использовать аргументы, указанные в конструкторе.Я начал это делать, а затем понял, что это создает конфликты с другими внутренними анонимными классами (используемыми, как в приведенном выше коде).Итак, я думаю, что создам еще один класс (не внутренний).
Решение
Вы можете создать свой собственный класс и передать данные в конструктор.Например
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) );
Другие советы
Редактировать:Я изменил класс, чтобы показать конструкцию с помощью 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 и удалите код.
Поскольку единственное отличие заключается в значении 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).
Если вы добавляете множество действий общего назначения, то вы могли бы упростить это, используя интерфейс, с которым не связан бессмысленный объект event.
Если бы вы хотели быть хакерским, вы могли бы добавить прослушиватель в конструктор подкласса.
new ActionHandler(button) { public void action() {
proposition += action;
updatePropositionPanel();
}});
Надеюсь, JDK7 сделает синтаксис Java для такого рода вещей менее подробным.Java, однако, всегда будет несколько многословной.
Вариант 1 работает, если вы сделаете proposition
изменяемый (например, StringBuilder
вместо того , чтобы String
).Вариант 2 работает, если вы объявляете их final
.Таким образом, они доступны / видны во внутреннем классе.
Вы могли бы создать отдельный класс MyActionListener и передать два значения proposition и action с помощью конструктора.Это уничтожает исходный код.
Вы могли бы создать свой собственный класс listener, который реализует ActionListener .Этот класс может содержать переменные-члены, соответствующие параметрам, о которых вы говорите;вы бы задали их с помощью конструктора.
Вызов для добавления слушателя тогда выглядел бы примерно так:
tmp.addActionListener(new MyActionListenerSubClass(proposition, action));
Ради этого примера я предположу, что ваши переменные proposition и action являются строками.Определите interface PropositionUpdater, interface PropositionPanelUpdater и владельца предложения collaborator:
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();
}
});
}
}
Вы не сказали, о каком количестве кнопок идет речь.
Если это небольшое число, как шахматная доска или меньше, подход @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.