A adição de um ActionListener pode ser curta?Posso adicionar argumentos ao actionPerformed?
-
22-09-2019 - |
Pergunta
Tenho uma tabela grande contendo um botão em cada célula.Esses botões são muito semelhantes e fazem quase a mesma coisa.Se eu adicionar um ouvinte de ação a cada botão desta forma:
tmp.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent evt) {
proposition = proposition + action;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
updatePropositionPanel();
}
});
}
});
Na verdade, cada ouvinte de ação difere de todos os outros pelo valor do action
. proposition
e updatePropositionPanel
são um campo e um método da classe.
Primeiro pensei que poderia torná-lo mais curto se não usasse classes internas.Então, decidi programar uma nova classe ActionListener.Mas então percebi que neste caso a "proposição" não será visível para as instâncias desta classe.
Então decidi adicionar o método actionPerformed à classe atual e fazer isso:
addActionListener(this)
.Mas então percebi que não sei como dar argumentos ao método actionPerformed.
Então, como isso funciona.Posso adicionar um ouvinte de ação de forma curta e elegante?
ADICIONADO:
Gostei da ideia de programar uma classe interna com um construtor que pode receber alguns argumentos e um método actioPerformed, que pode usar argumentos dados no construtor.Comecei a fazer isso e percebi que isso cria conflitos com outras classes anônimas internas (usadas como no código fornecido acima).Então, acho que vou criar outra classe (não a interna).
Solução
Você pode criar sua própria classe e passar os dados para o construtor. Por exemplo
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();
}
});
}
}
Em seguida, você pode adicioná -lo normalmente, passando quaisquer argumentos que desejar ao construtor:
tmp.addActionListener( new MyActionListener(proposition, this) );
Outras dicas
EDITAR: Eu alterei a classe para mostrar a construção com o MyouterClass.
Aqui estão algum código esboçado. Espero que isso chegue ao seu 1, e é assim que eu o implementaria.
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;
}
}
}
EDITAR: Para criar outra classe como você solicitou em sua edição, faça o que acima, mas crie uma outra classe não privada em outro arquivo .java e codifique.
Como o único diferente está no valor de action
Você pode colocar o código dentro de um método. (Também o @Override é desnecessário e +=
é útil aqui.)
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();
}
});
}
});
}
o invokeLater
Provavelmente é inútil, pois você estará no thread de envio de eventos AWT (EDT) de qualquer maneira.
Se você estiver adicionando muitas ações de uso geral, poderá simplificá -lo usando uma interface que não possui um objeto de evento inútil associado a ele.
Se você quisesse ser hackish, poderia adicionar o ouvinte em um construtor de subclasse.
new ActionHandler(button) { public void action() {
proposition += action;
updatePropositionPanel();
}});
Felizmente, o JDK7 tornará a sintaxe Java para esse tipo de coisa menos detalhada. Java, no entanto, sempre será um pouco detalhado.
A opção 1 funciona se você fizer proposition
mutável (por exemplo StringBuilder
ao invés de String
). A opção 2 funciona se você os declarar final
. Dessa forma, eles são acessíveis/visíveis na classe interna.
Você pode criar uma classe MyActionListener separada e passar a proposição e ação dos dois valores com o construtor. Ele declara o código -fonte.
Você poderia criar sua própria classe de ouvinte que implemente ActionListener.Esta classe pode conter variáveis de membro correspondentes aos parâmetros dos quais você está falando;você os configuraria usando o construtor.
A chamada para adicionar o ouvinte seria mais ou menos assim:
tmp.addActionListener(new MyActionListenerSubClass(proposition, action));
Assumirei que suas variáveis de proposição e ação são Strings para fins deste exemplo.Defina uma interface PropositionUpdater, uma interface PropositionPanelUpdater e um detentor de proposta de colaborador:
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();
}
A implementação padrão de um atualizador de proposição é simplesmente esta:
public class DefaultPropositionUpdater implements PropositionUpdater {
public void updateProposition(final PropositionHolder holder, final String action) {
holder.setProposition(holder.getProposition() + action);
}
}
Vou deixar o padrão de PropositionHolder e PropositionPanelUpdater para sua imaginação;)
Agora, aqui está seu ouvinte de ação:
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();
}
});
}
}
Você não disse de quantos botões está falando.
Se é um pequeno número como uma tábua de xadrez ou menos, a abordagem de @juskt é boa.
No entanto, se você olhando para algo maior, eu usaria esta abordagem:
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();
}
});
}
}
Este ouvinte de ação não possui estado. Como resultado, uma única instância pode ser usada para todos os botões. Para algo como uma placa GO (19x19), isso funciona em 1 objeto em vez de 361.