2012-01-20 50 views
7

似乎WindowEvent.WINDOW_SHOWN永遠不會派發到場景圖中的任何節點上,也無論如何(我可以找到)知道節點何時可見/呈現/顯示。例如:如何在場景圖的節點中偵聽WindowEvent.WINDOW_SHOWN?

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> 

實際上,節點如何才能意識到它是可見/呈現/顯示的事實?

回答

4

我猜可能的解決方案之一是將下面的方法添加到TestController.java

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

然後TestLauncher改變start方法以下幾點:

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

我真的很歡迎其他解決方案,因爲這個看起來太笨重了......

+0

親愛的安德烈。我的應用程序有很多控制器,我需要在某些UI流程的中間進行此操作。當我添加WindowEvent.WINDOW_SHOWN事件處理程序時,它會嘗試執行這個事件處理程序,我已經聲明這意味着執行Application的開始(Stage方法),然後我得到了一些空指針異常。你能告訴我如何解決這個問題。謝謝。 – Channa

+0

如果你仍然對anoter解決方案感興趣(4y後..),看看我的回答 –

3

另一種解決方案,固然是不是很性感,但解耦應用程序的節點:

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

於我而言更有意義。

+2

我認爲這是最好的解決方案,因爲解耦 – DevWurm

相關問題