如何关闭primaryStage并打开新阶段?

问题描述

我曾尝试研究有关如何切换场景甚至阶段的各种页面,但没有运气来帮助我的具体案例。我正在尝试使用管理学校图书馆的登录表单创建一个程序。

我有一个登录表单,它使用 validateLogin() 方法验证用户输入。如果登录成功(即isLoginSuccess = true),我希望我的程序关闭primaryStage并打开一个带有图书馆管理系统的新阶段/窗口。

是在primaryStage上切换场景还是关闭primaryStage并打开一个新阶段更好?你是怎么做的,你应该从 Main.java 做,还是从 LoginController.java 做?我在切换场景时遇到问题,甚至无法从 LoginController.java 创建一个新阶段,因为在该类中无法识别 primaryStage。

Main.java

package sample;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.stage.StageStyle;

public class Main extends Application
{


    @Override
    public void start(Stage primaryStage) throws Exception
    {
        Parent root = FXMLLoader.load(getClass().getResource("login.fxml"));
        primaryStage.initStyle(StageStyle.UNDECORATED);
        primaryStage.setScene(new Scene(root,520,400));
        primaryStage.setResizable(false);
        primaryStage.show();
    }

    //main() method is ignored in correctly deployed JavaFX application.
    public static void main(String[] args)
    {
        launch(args);
    }


}

LoginController.java

package sample;

import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;

import javafx.scene.Parent;
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.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import javafx.event.ActionEvent;
import javafx.stage.StageStyle;

import java.io.File;
import java.util.ResourceBundle;

//Can be removed,StackOverflow import
import java.io.BufferedReader;
import java.io.FileReader;

import java.net.URL;

public class LoginController implements Initializable
{

    @FXML
    private Button cancelButton;
    @FXML
    private Label loginMessageLabel;
    @FXML
    private ImageView brandingImageView;
    @FXML
    private ImageView lockImageView;
    @FXML
    private TextField usernameTextField;
    @FXML
    private PasswordField enterPasswordField;


    @Override
    public void initialize(URL url,ResourceBundle resourceBundle)
    {
        File brandingFile = new File("Images/libmanager.png");
        Image brandingImage = new Image(brandingFile.toURI().toString());
        brandingImageView.setimage(brandingImage);

        File lockFile = new File("Images/LoginLock.png");
        Image lockImage = new Image(lockFile.toURI().toString());
        lockImageView.setimage(lockImage);
    }

    //Activates validateLogin() if there is input in text fields.
    public void loginButtonOnAction(ActionEvent event)
    {
        if (usernameTextField.getText().isBlank() == false && enterPasswordField.getText().isBlank() == false)
        {
            validateLogin();
        }
        else
            {
            loginMessageLabel.setText("Please enter username and password");
            }
    }

    //Closes login window.
    public void cancelButtonOnAction(ActionEvent event)
    {
        Stage stage = (Stage) cancelButton.getScene().getwindow();
        stage.close();
    }

    //Compares user input to txt file contents to authenticate.
    public void validateLogin() {
        {
            try {
                String location = "userdatabase.txt";
                String username = usernameTextField.getText();
                String password = enterPasswordField.getText();

                FileReader fr = new FileReader(location);
                BufferedReader br = new BufferedReader(fr);
                String line,user,pass;
                boolean isLoginSuccess = false;
                while ((line = br.readLine()) != null) {
                    user = line.split(" ")[1].toLowerCase();
                    pass = line.split(" ")[2].toLowerCase();
                    if (user.equals(usernameTextField.getText()) && pass.equals(enterPasswordField.getText())) {
                        isLoginSuccess = true;
                        break;
                    }
                }
                if (!isLoginSuccess)
                {

                    /*
                    public void startlibmanager(Stage primaryStage) {
                    FXMLLoader loader = new FXMLLoader(getClass().getResource("LibDatabase.fxml"));


                            Parent mainCallWindowFXML = loader.load();
                    secondaryStage.initStyle(StageStyle.UNDECORATED);
                    secondaryStage.setScene(new Scene(root,400));
                    secondaryStage.setResizable(false);
                    secondaryStage.show();
                    }
                     */

                    /*
                    //use one of the components on your scene to get a reference to your scene object.

                    Stage stage = (Stage)tfCallerName.getScene.getwindow();//or use any other component in your controller
                    Scene mainCallWindow = new Scene (mainCallWindowFXML,800,600);
                    stage.setScene(newCallDetails);
                    stage.show(); //this line may be unnecessary since you are using the same stage.
                     */
                }
                fr.close();

                } catch (Exception e) {
                e.printstacktrace();
                }
        }
    }
}

login.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.PasswordField?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.borderpane?>

<borderpane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefheight="400.0" prefWidth="520.0" style="-fx-background-color: #FFFFFF;" xmlns="http://javafx.com/javafx/15.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.LoginController">
   <left>
      <AnchorPane prefheight="407.0" prefWidth="227.0" borderpane.alignment="CENTER">
         <children>
            <ImageView fx:id="brandingImageView" fitHeight="400.0" fitWidth="226.0" pickOnBounds="true" preserveRatio="true">
               <image>
                  <Image url="@../../Images/libmanager.png" />
               </image>
            </ImageView>
         </children></AnchorPane>
   </left>
   <right>
      <AnchorPane prefheight="400.0" prefWidth="332.0" style="-fx-background-color: FFFFFF;" borderpane.alignment="CENTER">
         <children>
            <ImageView fx:id="lockImageView" fitHeight="32.0" fitWidth="46.0" layoutX="134.0" layoutY="65.0" pickOnBounds="true" preserveRatio="true">
               <image>
                  <Image url="@../../Images/LoginLock.png" />
               </image>
            </ImageView>
            <Label layoutX="23.0" layoutY="157.0" prefheight="17.0" prefWidth="60.0" text="Username" textFill="#01989e" />
            <TextField fx:id="usernameTextField" layoutX="96.0" layoutY="152.0" prefWidth="173.0" promptText="Username" />
            <Label layoutX="26.0" layoutY="205.0" text="Password" textFill="#01989e" />
            <PasswordField fx:id="enterPasswordField" layoutX="96.0" layoutY="200.0" prefheight="27.0" prefWidth="173.0" promptText="Password" />
            <Button fx:id="loginButton" layoutX="22.0" layoutY="294.0" mnemonicParsing="false" onAction="#loginButtonOnAction" prefheight="27.0" prefWidth="249.0" style="-fx-background-color: ff914d;" text="Login" textFill="WHITE" />
            <Button fx:id="cancelButton" layoutX="22.0" layoutY="342.0" mnemonicParsing="false" onAction="#cancelButtonOnAction" prefheight="27.0" prefWidth="249.0" style="-fx-background-color: ff914d;" text="Cancel" textFill="WHITE" />
            <Label fx:id="loginMessageLabel" layoutX="26.0" layoutY="248.0" prefheight="17.0" prefWidth="160.0" textFill="RED" />
         </children></AnchorPane>
   </right>
</borderpane>

解决方法

@Loritt 我可能有点晚了,但我在使用 JavaFX 时使用这种方法来改变场景。

如果您要在场景之间来回切换,此方法可避免您编写冗余代码。

Stage stage;
Parent scene;
public void switchViews(ActionEvent event,String fileLocation) throws IOException {

    stage = (Stage) ((Button) event.getSource()).getScene().getWindow();
    scene = FXMLLoader.load(getClass().getResource(fileLocation));
    stage.setScene(new Scene(scene));
    stage.show();
}

我通常将此方法放在控制器类中,这是完全可以接受的,因为它与控制应用程序中的视觉效果有关,而不是任何业务逻辑。

此外,当我最初自己学习如何做到这一点,然后在使用此视频的场景和在 JavaFX/Scene Builder 上有一些不错内容的 youtuber 之间传递信息时。 (链接:https://www.youtube.com/watch?v=XCgcQTQCfJQ

希望这有助于回答您的问题。

快乐编码! :)