Estou com um problema quanto à utilização de Listeners em um componentes Swing.
Meu componente (uma tabela) já possui um ActionListener, que ás vezes faz alguns carregamentos nas linhas (buscas a banco , formatações e outras coisinhas…).
Eu precisei adicionar outro ActionListener, porque estou em outra classe e não a enxergo, então não pude colocar meu processo no meio dos métodos executados pelo outro Listener. Só que eu preciso que os processos que serão executados no novo Listener sejam executados DEPOIS daqueles que são executados pelo primeiro. Existe algum modo de eu garantir a ordem da execução?
Não sei se dá para garantir a ordem de execução à partir da ordem de inserção dos listeners.
Uma sugestão para garantir a ordem de execução é que os listeners que precisam ser executados depois sejam adicionados como listeners dos que precisam ser executados antes.
Ou seja, você adiciona seus listeners na sua tabela e os listeners que precisam ser executados depois você adiciona como listeners destes primeiros.
thegoergen
Eu posso fazer isso?
Tipo… Eu tenho um ActionListener na tabela, e ele tem o método propertyChange, que é executado quando tem uma alteração na tabela (praticamente tudo, mudança de selção, exclusão… várias coisas). E eu quero esse mesmo evento para o meu segundo Listener, eu tenho como implementar isso?
Se der, eu posso fazer isso tranquilo…
davidtiagoconceicao
Sim, é perfeitamente possível, mas dependendo da sua implementação até o momento, pode exigir algumas alterações.
Você criou duas classes que implementam os determinados listeners, certo? Para facilitar, vou chamar de classe A e classe B.
Supondo que a classe A precisa ser avisada antes da classe B, o que precisa ser feito é:
Dentro da classe A:
- criar um atributo para armazenar um ou um conjunto de listeners que esta classe irá avisar (ArrayList, por exemplo).
- criar métodos que adicionem e removam listeners na variável anterior (add e remove).
- no determinado momento que você gostaria que estes listeners fossem acionados, você chama os métodos do listener. Por exemplo, se são listeners de ActionPerformed, você percorre a estrutura de listeners adicionados e invoda o método actionPerformed.
Dentro da classe B:
- Implementa a interface dos listeners que serão adicionados em A.
Em algum outro ponto do seu sistema você adiciona instância(s) de B como listeners de A chamando os métodos que você criou.
Espero ter sido claro.
Qualquer dúvida poste aí!
thegoergen
Cara…
Foi mal, mas não consegui entender direito. Eu particularmente não entendo muito de eventos, nem sei o que é padrão do Java e o que tem de implementações do próprio código aqui da empresa… mas eu vou colocar as partes do códigos que eu estou usando.
// Essa implementação aqui é feita no diálogo em que minha tabela é criadaMinhaTabela.addPropertyChangeListener(newjava.beans.PropertyChangeListener(){publicvoidpropertyChange(java.beans.PropertyChangeEventevt){MinhaTabelaPropertyChange(evt);}});
// Adiciono aqui meu segundo listener (já é em outra classe)MinhaTabela.addPropertyChangeListener(newjava.beans.PropertyChangeListener(){publicvoidpropertyChange(java.beans.PropertyChangeEventevt){meuMetodo(evt);}});
É só isso que eu faço ( o primeiro código foi até o NetBeans que fez, como dá para perceber ).
O que eu quero é garantir que o meuMetodo seja executado depois do MinaTabelaPropertyChange…
Tipo… eu não criei classes diferentes pros meus Listeners… achei que não precisaria…
davidtiagoconceicao
Tudo bem cara, está indo pelo caminho certo…
Listeners são baseados no padrão Observer. E funcionam mais ou menos assim: um objeto que permite ser observado cria métodos
para adicionar e remover listeners e têm como parâmetros objetos que implementam determinada interface. Ou seja, para observar
outro objeto, um objeto deve implementar uma determinada interface. Conforme necessário, o objeto observado percorre a estrutura
em que os listeners foram adicionados invocando um determinado método da interface.
Falando do seu caso.
// Essa implementação aqui é feita no diálogo em que minha tabela é criada MinhaTabela.addPropertyChangeListener(newjava.beans.PropertyChangeListener(){publicvoidpropertyChange(java.beans.PropertyChangeEventevt){MinhaTabelaPropertyChange(evt);}});
Neste trecho de código o que o NB fez foi gerar um código no qual um objeto é instanciado através de uma chamada classe anônima: é instanciado um objeto que implementa a determinada interface, porém sem ser à partir de classe alguma. Para tratar o evento, o método MinhaTabelaPropertyChange é invocado.
Assim, o que você precisa fazer é criar uma classe que implementa java.beans.PropertyChangeListener, instanciar um objeto desta classe e adicionar esta instância como listener da tabela através do método addPropertyChangeListener. Isto pode ser feito no construtor da classe, por exemplo.
Dentro desta classe, crie métodos para adicionar e remover listeners conforme uma interface que você definir. Depois, dentro dos métodos percorra a lista de listeners invocando os métodos conforme necessário.
E essa classe MeuListener também precisa ter o método addPropertyChangeListener??
davidtiagoconceicao
Ela precisa ter um método addInterface.
Se você utilizar a interface PropertyChangeListener, então deverá ser um método addPropertyChangeListener.
thegoergen
Mas e como eu faço pra disparar o evento?
Tipo… o evento que o MeuListener vai pegar executará algo, e depois, como faço para que o Listener que eu tiver adicionado a ele chame o meu segundo método? Não deve ser automático… :roll:
davidtiagoconceicao
Supondo que você tenha escolhido como interface a PropertyChangeListener, no ponto em que você deseja acionar os listeners, você faria algo mais ou menos assim:
for(PropertyChangeListenerlistener:listeners){
listener.propertyChange(evt); //evt é o objeto de evento, pode ser o mesmo recebido como parâmetro ou um novo que teria como source this
}
thegoergen
Não entendi direito de onde veio essa List listeners...
Eu tenho meu listener agora:
publicclassMeuListenerimplementsPropertyChangeListener{publicvoidaddPropertyChangeListener(PropertyChangeListenernewListener){// O que eu faço aqui? Preciso criar um ArrayList com o listeners?// Mas e com o listener adicionado, como faço para que ele dispare o evento??}@OverridepublicvoidpropertyChange(PropertyChangeEventevt){MinhaTabelaPropertyChange(evt);}}
aqui eu adicionei ele na minha tabela:
// Essa implementação aqui é feita no diálogo em que minha tabela é criadaMinhaTabela.addPropertyChangeListener(newjava.beans.PropertyChangeListener(){publicvoidpropertyChange(java.beans.PropertyChangeEventevt){MinhaTabelaPropertyChange(evt);}});
// Adiciono aqui meu segundo listener (já é em outra classe) // Primeiro pego os listeners da tabela, e depois adiciono o Listener no Listener (acho que não precisa do FOR, tem só um mesmo...)MeuListener[]listeners=MinhaTabela.getListeners(MeuListener.class);for(MeuListenerml:listeners){ml.addPropertyChangeListener(newjava.beans.PropertyChangeListener(){publicvoidpropertyChange(java.beans.PropertyChangeEventevt){meuMetodo(evt,jMALTItens);}});}
Agora ele chega no propertyChange do MeuListener, e chama aquele primeiro método corretamente. Mas e como faço pra executar o meuMetodo??
davidtiagoconceicao
O atributo listeners seria a sua lista de listeners. Sua classe ficaria mais ou menos assim:
publicclassMeuListenerimplementsPropertyChangeListener{privateArrayList<PropertyChangeListener>listeners;//não esqueça de inicializarpublicvoidaddPropertyChangeListener(PropertyChangeListenernewListener){listeners.add(newListener);}@OverridepublicvoidpropertyChange(PropertyChangeEventevt){MinhaTabelaPropertyChange(evt);}}
thegoergen
Valeu David.
Vou testar tudo aqui.
davidtiagoconceicao
Beleza, qualquer coisa estamos aí!
thegoergen
Olha… fiquei com uma dúvida agora. Minha classe ficou assim:
publicabstractclassMeuListenerimplementsPropertyChangeListener{privateArrayList<PropertyChangeListener>listeners=newArrayList<PropertyChangeListener>();publicvoidaddPropertyChangeListener(PropertyChangeListenernewListener){listeners.add(newListener);}publicvoidpropertyChange(java.beans.PropertyChangeEventevt){// Não tenho certeza se eu posso fazer isso aqui, talvez tenha que deixar sem o método??for(java.beans.PropertyChangeListenerlistener:listeners){listener.propertyChange(evt);}}}
MinhaTabela.addPropertyChangeListener(newMeuListener(){publicvoidpropertyChange(java.beans.PropertyChangeEventevt){MinhaTabelaPropertyChange(evt);super.propertyChange(evt);// Como o listeners é privado, eu quero chamar o propertyChange lá da classe, que por sua vez chama o propertyChange de todos os seus listeners. Isso pode???}});
Assim que eu conseguir fazer esses eventos em seqïencia, vai ficar barbada… =D
O métododo propertyChange vai ser chamado automáticamente pelo objeto MinhaTabela.
Preste atenção apenas em onde você irá colocar esta linha (não sei onde o NB gerou este código). Sugiro que coloque logo após a classe MinhaTabela ser instanciada.
thegoergen
Mas o méotdo MinhaTabelaPropertyChange é privado da classe, não existe na classe MeuListener…
thegoergen
Cara… funcionou do meu jeito.
Eu consigo implementar como o NetBeans faz, e daí eu chamo o super.pripertyChange(evt), que chama os propertYChange de todos os meus “Listeners do Listener”.;
Valeu David.
davidtiagoconceicao
Ah, tá beleza então.
thegoergen
Desculpa incomodar de novo, mas não consigo pegar os listeners do tipo MeuListener...
Existe o método getListeners que recebe uma classe, mas não acha do meu tipo especial...
Tentei assim:
Daí funciona... Existe algo que eu tenha que fazer? Sei lá... implementar outra interface, extender uma classe específica...
davidtiagoconceicao
Não sei te dizer.
Se for por este caminho, acho que tem que ser como você postou mesmo.
thegoergen
Descobri o problema. :idea: Eu não tinha lido o JavaDoc :oops:
Returns an array of all the objects currently registered as FooListeners upon this JComponent. FooListeners are registered using the addFooListener method.
Ou seja: Como eu adicionei usando o addPropertyChangeListener, ele só acha com essa classe. Estranho, mas deve ser isso… hhehee