2015-08-22 35 views
-1

我有兩個場景 - 登錄提示和主屏幕。 openLoginPrompt()函數打開登錄提示符。然後我調用嘗試驗證用戶的handleLogin()函數。登錄成功時,我想關閉登錄提示並返回主屏幕。但是,如果我沒有將primaryStage設置爲靜態,則在調用handleLogin()函數時,primaryStage似乎爲null。爲什麼會發生這種情況,是否有更好的選擇來關閉舞臺?如何關閉javafx中的彈出窗口?

/* 
* To change this license header, choose License Headers in Project Properties. 
* To change this template file, choose Tools | Templates 
* and open the template in the editor. 
*/ 
package chatapplication; 

import java.io.IOException; 
import java.sql.Connection; 
import java.sql.PreparedStatement; 
import java.sql.ResultSet; 
import java.sql.SQLException; 
import javafx.fxml.FXML; 
import javafx.fxml.FXMLLoader; 
import javafx.scene.Scene; 
import javafx.scene.control.Button; 
import javafx.scene.control.Label; 
import javafx.scene.control.PasswordField; 
import javafx.scene.control.TextField; 
import javafx.scene.layout.AnchorPane; 
import javafx.stage.Stage; 

/** 
* 
* @author babaji 
*/ 
public class Controller { 


private static Stage primaryStage; 

@FXML 
private Button openLoginPrompt; 
@FXML 
private Button login; 
@FXML 
private TextField username; 
@FXML 
private PasswordField password; 
@FXML 
private Label loginMessage; 
@FXML 
private AnchorPane loginPrompt; 

@FXML 
private void openLoginPrompt() { 
    try { 
     primaryStage = new Stage(); 
     // Load root layout from fxml file. 
     FXMLLoader loader = new FXMLLoader(); 
     loader.setLocation(ChatApplication.class.getResource("LoginPrompt.fxml")); 
     AnchorPane rootLayout = (AnchorPane) loader.load(); 

     // Show the scene containing the root layout. 
     Scene scene = new Scene(rootLayout); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 

    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
} 

@FXML 
private void handleLogin() { 
    Database dbObj = new Database(); 
    Connection conn = dbObj.connectToDb("chat"); 
    String uname = username.getText(); 
    String psswd = password.getText(); 
    ResultSet rs = null; 
    try { 
     String sql = "SELECT * FROM user WHERE user_name=? AND password=?"; 
     PreparedStatement ps = conn.prepareStatement(sql); 
     ps.setString(1, uname); 
     ps.setString(2, psswd); 
     rs = ps.executeQuery(); 
    } 
    catch(SQLException e) { 
     e.printStackTrace(); 
    } 
    int count = 0; 
    try { 
     if(rs != null) while(rs.next()) count++; 
    } 
    catch(SQLException e) { 
     count = 0; 

    } 
    if(count == 1) { 
     System.out.println("Successfully Logged in"); 
     /*This is where the problem Lies. If I dont't set primaryStage as 
     static, primaryStage returns null. Why does this happen and is there 
     some other way to close the window?s 
     */ 
     if(primaryStage != null) primaryStage.close(); 
    } 
    else { 
     System.out.println("Failed to login."); 
     loginMessage.setText("Incorrect username or password"); 
    } 
} 

}

+0

這是LoginPrompt.fxml和MainScreen.fxml的控制器 – banad

+0

'primaryStage'只能在爲MainScreen.fxml創建的實例中設置。 –

+0

您可以建議一種替代方法來打開彈出窗口而不使用相同的控制器類嗎? – banad

回答

1

你有兩個控制器實例,一個是LoginPrompt.fxml,一個用於您還沒有表現出另一種FXML(姑且稱之爲「主」 FXML)。在「main」實例上調用openLoginPrompt,並初始化primaryStage,並加載LoginPrompt.fxml。當您加載FXML時,FXMLLoader創建控制器的新實例,該實例沒有primaryStage初始化(假設它不是static);所以當在LoginPrompt.fxml控制器上被調用時,它是null

對兩個不同的FXML文件使用相同的控制器類是一個非常糟糕的想法,因爲它會導致各種令人困惑的場景,比如這種情況,其中不同的字段在類的不同實例中被初始化。您應該爲每個FXML文件使用不同的控制器類。

在這種情況下,您可以定義一個LoginController類。編輯LoginPrompt.fxml來代替使用此控制器類。您可以從該類暴露各種屬性,並從主控制器觀察他們,當你打開登錄窗口:

public class LoginController { 

    @FXML 
    private Label loginMessage ; 

    private final BooleanProperty loggedIn = new SimpleBooleanProperty(); 
    public BooleanProperty loggedInProperty() { 
     return loggedIn ; 
    } 

    public final boolean isLoggedIn() { 
     return loggedInProperty().get(); 
    } 

    public final void setLoggedIn(boolean loggedIn) { 
     loggedInProperty().set(loggedIn); 
    } 

    @FXML 
    private void handleLogin() { 
     // existing code you had in the previous version... 
     if (count == 1) { 
      System.out.println("Successfully logged in"); 
      setLoggedIn(true); 
     } else { 
      System.out.println("Failed to login."); 
      loginMessage.setText("Incorrect username or password"); 
     } 
    } 

} 

然後在你的主控制器,你做

@FXML 
private void openLoginPrompt() { 
    try { 
     Stage loginStage = new Stage(); 
     // Load root layout from fxml file. 
     FXMLLoader loader = new FXMLLoader(); 
     loader.setLocation(ChatApplication.class.getResource("LoginPrompt.fxml")); 
     AnchorPane rootLayout = (AnchorPane) loader.load(); 

     LoginController loginController = loader.getController(); 
     loginController.loggedInProperty().addListener((obs, wasLoggedIn, isNowLoggedIn) -> { 
      if (isNowLoggedIn) { 
       loginStage.hide(); 
      } 
     }); 

     // Show the scene containing the root layout. 
     Scene scene = new Scene(rootLayout); 
     loginStage.setScene(scene); 
     loginStage.show(); 

    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
} 

沒有必要使Stage這個版本的一個字段。

我還要提到有一個「快速和骯髒」的方式直接從LoginController關閉階段:

loginMessage.getScene().getWindow().hide(); 

這將避免需要的財產,甚至正從主控制器到LoginController參考。但是,您經常會遇到需要將數據從一個控制器傳輸到另一個控制器的情況,而第一種技術則是更常用的方法。