Como colocar um Listener (ou vários) fora do método INICIALIZE?

Estou trabalhando com JavaFX e me deparei com um pequeno problema.

Tentei colocar todos os listeners da classe CONTROLLER de um formulário, em uma classe separada (para não “encher” demais o método INICIALIZE), mas não consigo fazer funcionar.

Alguém já fez isso?

Se sim, pode me dar uma luz?

objetoDoComponente.addTipoDeListener(objetoDoListener);

Você tem um exemplo resumido da codificação ?

Meu post foi um exemplo resumido.

Qual listener você quer adicionar e em qual componente?

Minha pergunta foi pro AlexandreCamelo, quero ver no programa dele onde está o problema.

1 curtida

Seguinte:

Tenho uma classe ‘controller’ de um formulário (FrmCadCliController). No método initialize dessa classe, coloquei vários listeners, para vários textfields, que observam o evento AO PERDER O FOCO.

Um dos listeners, é esse, abaixo:

txtEmail.focusedProperty().addListener (new ChangeListener<Boolean>()
                {
                    @Override
                    public void changed(ObservableValue<? extends Boolean> arg0, Boolean aoPerderFoco, Boolean aoGanharFoco)
                    {
                        
                        if (aoPerderFoco)
                        {
                            if (!txtEmail.getText().isBlank())
                            {
                            
                                String contEmail = txtEmail.getText();

                                if (!contEmail.contains("@") || !contEmail.contains("."))
                                {
                                   Avisos.AvisoSimples("HÁ ALGO ERRADO", "CORRIGIR EMAIL", "O email digitado parece estar errado. Emails precisam ter '@' e '.'");
                                   txtEmail.clear();
                                   txtEmail.requestFocus();
                                }                                   }
                            }
                        
                        }
                    
                    });

Como você pode ver, ele interage com o textfield ‘txtEmail’, emitindo uma mensagem e limpando o campo, caso o usuário digite um email inválido.

Assim como esse listener, existem mais 06, todos no método initialize.

Achei que eram muitas linhas em um só método, então quis organizar: criei a classe “Eventos”, com a intenção de jogar todos os listeners dentro dela. Comecei jogando o listener do email. Criei o método AoPerderFocoTxtEmail() e joguei o código do listener, lá.

No método initialize da classe de controle, fiz uma chamada ao método AoPerderFocoTxtEmail() .

Alguns erros ocorreram, pois os códigos não enxergavam os textfields que ficaram na classe anterior. Resolvi eles, tornando as declarações desses textfields publicas e estáticas. Pronto. O código ficou sem erros aparentes.

Porém, quando chamo o formulário, ocorre um erro (null pointer exception), causado pela chamada do método, pelo “initialize”. O formulário nem chega a abrir.

Detalhe: também tentei deixar a declaração do textfield, somente PÚBLICA. Então instanciei o textfield na classe Eventos. Também deu erro.

Não sei se consegui me fazer entender, mas seguem os erros:

javafx.fxml.LoadException: 
/C:/Camelo/JAVA/TotalXC/build/modules/TotalGeral/Telas/frmCadCli.fxml

	at javafx.fxml/javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2625)
	at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2603)
	at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2466)
	at javafx.fxml/javafx.fxml.FXMLLoader.load(FXMLLoader.java:2435)
	at TotalGeral/Controles.FrmLoginController.AbreJanelaCadastro(FrmLoginController.java:134)
	at TotalGeral/Controles.FrmLoginController.Logar(FrmLoginController.java:73)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:567)
	at com.sun.javafx.reflect.Trampoline.invoke(MethodUtil.java:76)
	at jdk.internal.reflect.GeneratedMethodAccessor2.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:567)
	at javafx.base/com.sun.javafx.reflect.MethodUtil.invoke(MethodUtil.java:273)
	at javafx.fxml/com.sun.javafx.fxml.MethodHelper.invoke(MethodHelper.java:83)
	at javafx.fxml/javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1782)
	at javafx.fxml/javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1670)
	at javafx.base/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
	at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
	at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
	at javafx.base/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
	at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
	at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
	at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
	at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
	at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
	at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
	at javafx.base/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
	at javafx.base/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
	at javafx.base/javafx.event.Event.fireEvent(Event.java:198)
	at javafx.graphics/javafx.scene.Node.fireEvent(Node.java:8879)
	at javafx.controls/javafx.scene.control.Button.fire(Button.java:200)
	at javafx.controls/com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:206)
	at javafx.controls/com.sun.javafx.scene.control.inputmap.InputMap.handle(InputMap.java:274)
	at javafx.base/com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
	at javafx.base/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
	at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
	at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
	at javafx.base/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
	at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
	at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
	at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
	at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
	at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
	at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
	at javafx.base/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
	at javafx.base/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
	at javafx.base/javafx.event.Event.fireEvent(Event.java:198)
	at javafx.graphics/javafx.scene.Scene$MouseHandler.process(Scene.java:3851)
	at javafx.graphics/javafx.scene.Scene$MouseHandler.access$1200(Scene.java:3579)
	at javafx.graphics/javafx.scene.Scene.processMouseEvent(Scene.java:1849)
	at javafx.graphics/javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2588)
	at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:397)
	at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:295)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
	at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$2(GlassViewEventHandler.java:434)
	at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:390)
	at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:433)
	at javafx.graphics/com.sun.glass.ui.View.handleMouseEvent(View.java:556)
	at javafx.graphics/com.sun.glass.ui.View.notifyMouse(View.java:942)
	at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
	at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
	at java.base/java.lang.Thread.run(Thread.java:830)
Caused by: java.lang.NullPointerException
	at TotalGeral/Controles.Eventos.AoPerderFocoTxtEmail(Eventos.java:24)
	at TotalGeral/Controles.FrmCadCliController.initialize(FrmCadCliController.java:477)
	at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2573)
	... 62 more

Sim, nesse caso pode usar um getController()

FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("sua.fxml"));

OController controller = fxmlLoader.getController();
controller.setApplication(this); // É uma boa pratica criar dentro do Controller um metodo que receba a Classe Principal e nela você coloca tudo o que deseja e não na initialize.

Quando o getController() é chamado, tudo em termos de @FXML estará devidamente instanciado.

Então…

Coloco esse código dentro de um método, criado dentro do controller?

E, logo abaixo de “controller.setApplication(this);”, já vou colocando os listeners?

É assim?

Nesse caso, se você resolver criar um metodo chamado setApplication( SuaMainClass )
dentro dele você coloca todos os seus listeners.

Valeu, Jotão!

Mais uma vez, resolvendo minhas broncas.

Mais tarde testo e marco como resolvido!

:+1::+1::+1::+1::+1::+1::+1::+1::+1::+1::+1::+1::+1::+1::+1::+1:

Criei uma classe à parte e coloquei o seu código e, logo após ele, coloquei o listener. Ocorreram os mesmos erros. Acho que fiz errado:

    public void TodosOsEventos()
    {
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("frmCadCli.fxml"));
        FrmCadCliController controlador = fxmlLoader.getController();
     
    
                
                controlador.txtEmail.focusedProperty().addListener (new ChangeListener<Boolean>()
                {
                    @Override
                    public void changed(ObservableValue<? extends Boolean> arg0, Boolean aoPerderFoco, Boolean aoGanharFoco)
                    {
                        
                        if (aoPerderFoco)
                        {
                            if (!controlador.txtEmail.getText().isBlank())
                            {
                            
                                String contEmail = controlador.txtEmail.getText();

                                if (!contEmail.contains("@") || !contEmail.contains("."))
                                {
                                   Avisos.AvisoSimples("HÁ ALGO ERRADO", "CORRIGIR EMAIL", "O email digitado parece estar errado. Emails precisam ter '@' e '.'");
                                   controlador.txtEmail.clear();
                                   controlador.txtEmail.requestFocus();
                                }                                   }
                            }
                        
                        }
                    
                    });
    
    }

Nesse caso, convem você debugar e ver onde está parando.
Em relação ao codigo acima, não está errado, mas pra dar manutenção poderá ser melhor ter as listeners dentro do Controller, mas isso é de cada um e não é um erro.

Tambem verifica nesse txtEmail, se ele foi criado dentro do fxml veja se acima dele tem a anotação @FXML lá no Controller, se não tiver não será instanciado, Agora se você criou a parte, precisa instanciar ele. pode ser dentro da initialize(…) ou setApplication(…) ou logo no inicio mesmo.

As vezes ocorre tambem, estando no Scene Builder adicionar um componente na Tela e esquecer de dentro do projeto “Make Controller” depois de “Clean and Build”.

Se mesmo assim não estiver visualizando o problema, Eu posso dar uma olhada melhor no seu programa.

Bons Codigos.