如何在javafx中关闭弹出窗口?

时间:2015-08-22 15:17:13

标签: java javafx fxml

我有两个场景 - 登录提示和主屏幕。 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");
    }
}

}

1 个答案:

答案 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(); 的引用。但是,您经常遇到可能需要来自另一个控制器的数据的情况,而第一种技术是更常用的方法。