[RESOLVIDO] Ordem de 2 listeners

Pessoal.

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.

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…

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í!

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 é criada
MinhaTabela.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
                  public void propertyChange(java.beans.PropertyChangeEvent evt) {
                        MinhaTabelaPropertyChange(evt);
                  }
            });
// Adiciono aqui meu segundo listener (já é em outra classe)
MinhaTabela.addPropertyChangeListener(new java.beans.PropertyChangeListener() {

            public void propertyChange(java.beans.PropertyChangeEvent evt) {
                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…

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(new java.beans.PropertyChangeListener() {  
                  public void propertyChange(java.beans.PropertyChangeEvent evt) {  
                        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.

Entendi. Ao invés de adicionar

 new java.beans.PropertyChangeListener() {    
                   public void propertyChange(java.beans.PropertyChangeEvent evt) {    
                         MinhaTabelaPropertyChange(evt);    
                   }    
             }

Eu adiciono um

new MeuListener()

E essa classe MeuListener também precisa ter o método addPropertyChangeListener??

Ela precisa ter um método addInterface.
Se você utilizar a interface PropertyChangeListener, então deverá ser um método addPropertyChangeListener.

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:

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(PropertyChangeListener listener : 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
}

Não entendi direito de onde veio essa List listeners…

Eu tenho meu listener agora:

[code]
public class MeuListener implements PropertyChangeListener {

public void addPropertyChangeListener(PropertyChangeListener newListener) {
    // 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??

}

@Override
public void propertyChange(PropertyChangeEvent evt) {
    MinhaTabelaPropertyChange(evt);
}

}[/code]

aqui eu adicionei ele na minha tabela:

// Essa implementação aqui é feita no diálogo em que minha tabela é criada
MinhaTabela.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
                  public void propertyChange(java.beans.PropertyChangeEvent evt) {
                        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 (MeuListener ml : listeners) {
            ml.addPropertyChangeListener(new java.beans.PropertyChangeListener() {

                public void propertyChange(java.beans.PropertyChangeEvent evt) {
                    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??

O atributo listeners seria a sua lista de listeners. Sua classe ficaria mais ou menos assim:

public class MeuListener implements PropertyChangeListener {  

private ArrayList<PropertyChangeListener> listeners; //não esqueça de inicializar

  
    public void addPropertyChangeListener(PropertyChangeListener newListener) {  
        listeners.add(newListener);  
    }  
  
    @Override  
    public void propertyChange(PropertyChangeEvent evt) {  
        MinhaTabelaPropertyChange(evt);  
    }  
}  

Valeu David.

Vou testar tudo aqui. :smiley:

Beleza, qualquer coisa estamos aí!

Olha… fiquei com uma dúvida agora. Minha classe ficou assim:

public abstract class MeuListener implements PropertyChangeListener {

    private ArrayList<PropertyChangeListener> listeners = new ArrayList<PropertyChangeListener>();

    public void addPropertyChangeListener(PropertyChangeListener newListener) {
        listeners.add(newListener);
    }

    public void propertyChange(java.beans.PropertyChangeEvent evt) {
// Não tenho certeza se eu posso fazer isso aqui, talvez tenha que deixar sem o método??
        for (java.beans.PropertyChangeListener listener : listeners) {
            listener.propertyChange(evt);
        }
    }
}
MinhaTabela.addPropertyChangeListener(new MeuListener() {

            public void propertyChange(java.beans.PropertyChangeEvent evt) {
                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

Na verdade, você substitui

MinhaTabela.addPropertyChangeListener(new MeuListener() {  
   
    public void propertyChange(java.beans.PropertyChangeEvent evt) {  
        MinhaTabelaPropertyChange(evt);  
        super.propertyChange(evt); 
    }  
});  

por

MinhaTabela.addPropertyChangeListener(new MeuListener());  

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.

Mas o méotdo MinhaTabelaPropertyChange é privado da classe, não existe na classe MeuListener…

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.

Ah, tá beleza então.

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:

[code]

MeuListener[] listeners = MinhaTabela.getListeners(MeuListener.class);
for (MeuListener nfil : listeners) {
nfil.addPropertyChangeListener(new java.beans.PropertyChangeListener() {

                public void propertyChange(java.beans.PropertyChangeEvent evt) {
                    meuMetodo(evt);
                }
            });            
    }[/code]

mass isso não retornou nada… Quando faço assim:

java.beans.PropertyChangeListener[] listeners = MinhaTabela.getListeners(java.beans.PropertyChangeListener.class);
        for (java.beans.PropertyChangeListener nfil : listeners) {
            if (nfil instanceof NMeuListener) {
                ((NMeuListener) nfil).addPropertyChangeListener(new java.beans.PropertyChangeListener() {

                    public void propertyChange(java.beans.PropertyChangeEvent evt) {
                        meuMetodo(evt);
                    }
                });
            }
        }

Daí funciona… Existe algo que eu tenha que fazer? Sei lá… implementar outra interface, extender uma classe específica…