问题描述
我曾尝试研究有关如何切换场景甚至阶段的各种页面,但没有运气来帮助我的具体案例。我正在尝试使用管理学校图书馆的登录表单创建一个程序。
我有一个登录表单,它使用 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)
希望这有助于回答您的问题。
快乐编码! :)