2012-01-20 19 views
7

Sembra che WindowEvent.WINDOW_SHOWN non venga mai inviato su nessuno dei nodi nel grafico di scena, né esiste comunque (che potrei trovare) sapere quando un nodo è visibile/renderizzato/mostrato. Ad esempio:Come ascoltare WindowEvent.WINDOW_SHOWN nei nodi del grafico di scena?

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> 

Quindi, in realtà, in quale altro modo un nodo può rendersi conto del fatto che è visibile/reso/mostrato?

risposta

4

Credo che una delle possibili soluzioni è quella di aggiungere il seguente metodo per TestController.java

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

e quindi modificare il metodo start in TestLauncher al seguente:

@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(); 
    } 

Sarei davvero felice di altre soluzioni in quanto questo sembra troppo goffo ...

+0

Caro Andrey. La mia applicazione ha un numero di controller e ho bisogno di farlo mentre sono al centro di un flusso di interfaccia utente. Quando aggiungo il gestore di eventi WindowEvent.WINDOW_SHOWN come si menziona, tenterà di eseguire questo posto gestore di eventi che ho dichiarato tale con l'esecuzione di avvio dell'applicazione (metodo Stage), quindi ho ottenuto alcune eccezioni di puntatori nulli. Puoi dirmi come posso risolvere questo problema. Grazie. – Channa

+0

Se sei ancora interessato alla soluzione anoter (4 anni dopo ..), dai un'occhiata alla mia risposta –

3

Un'altra soluzione che certamente non è molto sexy ma disaccoppia il nodo dall'applicazione:

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(); 
      } 
     }); 
     } 
    }); 
    } 
}); 

aveva più senso nel mio caso.

+2

Penso che questa sia la soluzione migliore, a causa del disaccoppiamento – DevWurm

Problemi correlati