2012-01-20 13 views
7

Parece que WindowEvent.WINDOW_SHOWN nunca se distribuye en ninguno de los nodos en el gráfico de escena, ni tampoco hay (que pude encontrar) que sepa cuándo un nodo es visible/renderizado/mostrado. Por ejemplo:¿Cómo se escucha WindowEvent.WINDOW_SHOWN en los nodos del gráfico de escena?

TestLauncher.java

package com.example.javafx.event; 

import javafx.application.Application; 
import javafx.fxml.FXMLLoader; 
import javafx.scene.Parent; 
import javafx.scene.Scene; 
import javafx.stage.Stage; 

public class TestLauncher extends Application 
{ 
    public static void main(String[] args) 
    { 
     Application.launch(TestLauncher.class, args); 
    } 

    @Override 
    public void start(Stage stage) throws Exception 
    { 
     Parent root = FXMLLoader.load(TestController.class.getResource("TestView.fxml")); 
     Scene scene = new Scene(root); 
     stage.setScene(scene); 
     stage.show(); 
    } 
} 

TestController.java

package com.example.javafx.event; 

import java.net.URL; 
import java.util.ResourceBundle; 
import javafx.event.EventHandler; 
import javafx.fxml.FXML; 
import javafx.fxml.Initializable; 
import javafx.scene.Parent; 
import javafx.scene.control.TextField; 
import javafx.stage.WindowEvent; 

public class TestController implements Initializable 
{ 
    @FXML private Parent root; 
    @FXML private TextField serverAddressInput; 
    @FXML private TextField usernameInput; 

    @Override 
    public void initialize(URL url, ResourceBundle rb) 
    { 
     serverAddressInput.setText("127.0.0.1"); 

     //won't work because stage isn't visible yet 
     trySetFocusOnUsernameInput1(); 

     //apparently Stage never passes on any WindowEvents to the children... 
     trySetFocusOnUsernameInput2(); 
    } 

    private void trySetFocusOnUsernameInput1() 
    { 
     usernameInput.requestFocus(); 
    } 

    private void trySetFocusOnUsernameInput2() 
    { 
     root.addEventFilter(WindowEvent.WINDOW_SHOWN, new EventHandler<WindowEvent>() 
     { 
      @Override 
      public void handle(WindowEvent window) 
      { 
       usernameInput.requestFocus(); 
      } 
     }); 

     root.addEventHandler(WindowEvent.WINDOW_SHOWN, new EventHandler<WindowEvent>() 
     { 
      @Override 
      public void handle(WindowEvent window) 
      { 
       usernameInput.requestFocus(); 
      } 
     }); 
    } 

    public void handleWindowShownEvent() 
    { 
     usernameInput.requestFocus(); 
    } 
} 

TestView.fxml

<?xml version="1.0" encoding="UTF-8"?> 

<?import java.lang.*?> 
<?import javafx.scene.*?> 
<?import javafx.scene.control.*?> 
<?import javafx.scene.layout.*?> 

<VBox 
    xmlns:fx="http://javafx.com/fxml" 

    fx:id="root" 
    fx:controller="com.example.javafx.event.TestController" 

    prefHeight="150" 
    prefWidth="200" 
> 
    <children> 
     <TextField fx:id="serverAddressInput" /> 
     <TextField fx:id="usernameInput" /> 
    </children> 
</VBox> 

Entonces, en realidad, ¿de qué otro modo puede un nodo darse cuenta del hecho de que es visible/renderizado/mostrado?

Respuesta

4

supongo que una de las posibles soluciones es añadir el siguiente método para TestController.java

public void handleWindowShownEvent() 
    { 
     usernameInput.requestFocus(); 
    } 

y luego cambiar el método de start en TestLauncher a lo siguiente:

@Override 
    public void start(Stage stage) throws Exception 
    { 
     FXMLLoader loader = new FXMLLoader(); 
     Parent root = (Parent)loader.load(TestController.class.getResourceAsStream("TestView.fxml")); 
     final TestController controller = (TestController)loader.getController(); 
     stage.addEventHandler(WindowEvent.WINDOW_SHOWN, new EventHandler<WindowEvent>() 
     { 
      @Override 
      public void handle(WindowEvent window) 
      { 
       controller.handleWindowShownEvent(); 
      } 
     }); 
     Scene scene = new Scene(root); 
     stage.setScene(scene); 
     stage.show(); 
    } 

Realmente agradecería otras soluciones, ya que esta parece demasiado torpe ...

+0

Querido Andrey. Mi aplicación tiene una cantidad de Controladores y necesito hacerlo mientras estoy en medio de algún flujo de IU. Cuando agregue el controlador de eventos WindowEvent.WINDOW_SHOWN como mencionas, intentará ejecutar este controlador de eventos lugar que he declarado que significa con la ejecución del inicio de la aplicación (método de escenario), luego obtuve algunas excepciones de null puntero. ¿Puedes decirme cómo puedo solucionar este problema? Gracias. – Channa

+0

Si todavía está interesado en la solución anoter (4 años después ...), eche un vistazo a mi respuesta –

3

Otra solución que es cierto que no es muy atractiva, pero desacopla el nodo de la aplicación:

root.sceneProperty().addListener(new ChangeListener<Scene>() { 
    @Override 
    public void changed(ObservableValue<? extends Scene> observable, Scene oldValue, Scene newValue) { 
    newValue.windowProperty().addListener(new ChangeListener<Window>() { 
     @Override 
     public void changed(ObservableValue<? extends Window> observable, Window oldValue, Window newValue) { 
     newValue.addEventHandler(WindowEvent.WINDOW_SHOWN, new EventHandler<WindowEvent>() { 
      @Override 
      public void handle(WindowEvent event) { 
      usernameInput.requestFocus(); 
      } 
     }); 
     } 
    }); 
    } 
}); 

tenía más sentido en mi caso.

+2

Creo que esta es la mejor solución, debido al desacoplamiento – DevWurm

Cuestiones relacionadas