我有两个场景 - 登录提示和主屏幕。 openLoginPrompt()函数打开登录提示。然后我调用handleLogin()函数,该函数尝试验证用户。登录成功后,我想关闭登录提示并返回主屏幕。但是,如果我没有将primaryStage设置为静态,则在调用handleLogin()函数时,primaryStage似乎为null。为什么会发生这种情况,是否有更好的选择来关闭舞台?
/*
* 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 :(得分:1)
您有两个控制器实例,一个用于<xsl:stylesheet version="1.0" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output encoding="UTF-8" indent="yes" method="xml" version="1.0"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="soap:Envelope | soap:Body">
<xsl:apply-templates select="@*|node()"/>
</xsl:template>
</xsl:stylesheet>
,另一个用于另一个您尚未显示的FXML(让我们将其称为&#34; main&#34; fxml)。在{&#34; main&#34;}上调用LoginPrompt.fxml
实例,并初始化openLoginPrompt
,并加载primaryStage
。当您加载FXML时,LoginPrompt.fxml
会创建一个新的控制器实例,该实例没有FXMLLoader
初始化(假设它不是primaryStage
);因此,在static
控制器上调用handleLogin()
时,它是LoginPrompt.fxml
。
对两个不同的FXML文件使用相同的控制器类是一个非常糟糕的主意,因为它会导致各种混乱的情况,例如,在不同的类实例中初始化不同的字段。您应该为每个FXML文件使用不同的控制器类。
在这种情况下,您可以定义null
类。编辑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();
}
}
字段。
我还应该提到一个快速而又肮脏的&#34;直接从Stage
:
LoginController
这将避免需要属性,甚至从主控制器获取对loginMessage.getScene().getWindow().hide();
的引用。但是,您经常遇到可能需要来自另一个控制器的数据的情况,而第一种技术是更常用的方法。