简体   繁体   English

卡在 javafx 程序上,该程序不会将可注入字段加载到 FXML 文档中

[英]Stuck on a javafx program that won't load the injectable fields into FXML document

The only issue I'm having with this is the getAll() method, it seems that it runs immediately where I have it in the PersonnelController class.我遇到的唯一问题是 getAll() 方法,它似乎在我在 PersonnelController class 中的位置立即运行。 I've tried it in many other spots as well though, to no avail.不过我在其他很多地方也试过了,但无济于事。 The setAll() method seems fine and I've tested that the methods which setAll() is passing values to can return the correct values to the main method. setAll() 方法似乎很好,我已经测试过 setAll() 将值传递给的方法可以将正确的值返回给 main 方法。 They just for some reason don't return the values to the controller at the correct time I need them to.他们只是出于某种原因没有在我需要的正确时间将值返回给 controller。

What is supposed to happen is that a user enters in their username and password, then clicks the login button and that is where the injectable values can be passed to the FXML, before the secondScene loads.应该发生的是用户输入他们的用户名和密码,然后单击登录按钮,这就是在 secondScene 加载之前可以将可注入值传递给 FXML 的地方。 Depending on the username that they entered, a different set of pictures and labels will appear on the second scene.根据他们输入的用户名,一组不同的图片和标签将出现在第二个场景中。 I have getter and setter method that the program is calling to set the text and images.我有程序调用的getter和setter方法来设置文本和图像。

PersonnelController.java人员控制器.java

package application.controller;

import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;

import application.Main;
import application.model.CrewMember;
import application.model.Starship;
import application.model.User;

public class PersonnelController implements Initializable {

    @FXML Label welcomeMsg;

    @FXML Label shipName;

    @FXML
    ImageView commandOfficer;

    @FXML
    ImageView engineOfficer;

    @FXML
    ImageView commOfficer;

    @FXML
    ImageView firstOfficer;

    @FXML
    ImageView nurse;

    @FXML
    ImageView medOfficer;

    @FXML
    ImageView navigator;

    @FXML
    ImageView helmsman;

    @FXML
    Label crew8;

    @FXML
    Label crew7;

    @FXML
    Label crew6;

    @FXML
    Label crew5;

    @FXML
    Label crew4;

    @FXML
    Label crew3;

    @FXML
    Label crew2;

    @FXML
    Label crew1;


    private Scene firstScene;

    public void getAll() {
          welcomeMsg.setText("Welcome, " + Starship.getCapt());
          shipName.setText(Starship.getShip());

          commandOfficer.setImage(CrewMember.getInput1());
          firstOfficer.setImage(CrewMember.getInput2());
          commOfficer.setImage(CrewMember.getInput3());
          engineOfficer.setImage(CrewMember.getInput4());
          helmsman.setImage(CrewMember.getInput5());
          navigator.setImage(CrewMember.getInput6());
          medOfficer.setImage(CrewMember.getInput7());
          nurse.setImage(CrewMember.getInput8());

          crew1.setText(CrewMember.getCrew1());
          crew2.setText(CrewMember.getCrew2());
          crew3.setText(CrewMember.getCrew3());
          crew4.setText(CrewMember.getCrew4());
          crew5.setText(CrewMember.getCrew5());
          crew6.setText(CrewMember.getCrew6());
          crew7.setText(CrewMember.getCrew7());
          crew8.setText(CrewMember.getCrew8());
}

    public void setFirstScene(Scene scene) {
        firstScene = scene;
    }


    public void openFirstScene(ActionEvent actionEvent) {    
        Stage primaryStage = (Stage)((Node)actionEvent.getSource()).getScene().getWindow();
        primaryStage.setScene(firstScene);
    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {
                getAll();
            }
}

LoginController.java登录控制器.java

package application.controller;

import java.io.FileNotFoundException;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.Scanner;
import javafx.stage.*;
import javafx.scene.*;
import javafx.scene.layout.*;
import javafx.scene.control.*;
import javafx.geometry.*;

import application.Main;
import application.model.CrewMember;
import application.model.Starship;
import application.model.User;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.Window;

import java.awt.Label;
import java.io.*;

public class LoginController implements Initializable {

    @FXML 
    private Button loginButton;

    @FXML
    private TextField username;

    @FXML
    private PasswordField password;

    private static Scene secondScene;   

    private void setAll(String user) {

        Starship.setShip(user);
        Starship.setCapt(user);

        CrewMember.setInput1(user);
        CrewMember.setInput2(user);
        CrewMember.setInput3(user);
        CrewMember.setInput4(user);
        CrewMember.setInput5(user);
        CrewMember.setInput6(user);
        CrewMember.setInput7(user);
        CrewMember.setInput8(user);

        CrewMember.setCrew1(user);
        CrewMember.setCrew2(user);
        CrewMember.setCrew3(user);
        CrewMember.setCrew4(user);
        CrewMember.setCrew5(user);
        CrewMember.setCrew6(user);
        CrewMember.setCrew7(user);
        CrewMember.setCrew8(user);


}

    public void setSecondScene(Scene scene) {
        secondScene = scene;
    }

    public void openSecondScene(ActionEvent actionEvent) {

        String user = username.getText();
        String pass = password.getText();
        setAll(user);   



         /* If the username/password are valid, open the Personnel viewer. 
        Otherwise, alert the user that credentials are invalid. */
        if(User.validate(user,pass,"data/users.csv")== true) {  

            Stage primaryStage = (Stage)((Node)actionEvent.getSource()).getScene().getWindow();  
            primaryStage.setScene(secondScene);


          }
        else{

            User.invalid();

                }   
    }


    @Override
    public void initialize(URL location, ResourceBundle resources) {
        assert loginButton != null : "fx:id=\"loginButton\" was not injected: check your FXML file '/Login.fxml'.";

            }
}

Main.java主.java

package application;

import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.ButtonBase;
import javafx.scene.control.CheckBox;
import javafx.scene.layout.BorderPane;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

import application.model.CrewMember;

public class Main extends Application {
    @Override
    public void start(Stage primaryStage) {

        try {
            /* getting loader and a pane for the first scene.
            Loader will then give a possibility to get related controller */
            FXMLLoader firstPaneLoader = new FXMLLoader(getClass().getResource("/Login.fxml"));
            Parent firstPane = firstPaneLoader.load();
            Scene firstScene = new Scene(firstPane);

            // getting loader and a pane for the second scene
            FXMLLoader secondPageLoader = new FXMLLoader(getClass().getResource("/Personnel.fxml"));
            Parent secondPane = secondPageLoader.load();
            Scene secondScene = new Scene(secondPane);

            // injecting second scene into the controller of the first scene
            application.controller.LoginController firstPaneController = (application.controller.LoginController) firstPaneLoader.getController();
            firstPaneController.setSecondScene(secondScene);

            // injecting first scene into the controller of the second scene
            application.controller.PersonnelController secondPaneController = (application.controller.PersonnelController) secondPageLoader.getController();
            secondPaneController.setFirstScene(firstScene);

            // open the login screen on start       
            primaryStage.setScene(firstScene);
            primaryStage.show();

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

            }

    public static void main(String[] args) {
        launch(args);
            }
    }

And here Starship.java is one of two classes with getter and setter methods that are called on by the setAll() method in the controller for the login screen and getAll() method in the controller for the second screen (Personnel.FXML). And here Starship.java is one of two classes with getter and setter methods that are called on by the setAll() method in the controller for the login screen and getAll() method in the controller for the second screen (Personnel.FXML).

Personnel.fxml人员.fxml

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

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.text.Font?>

<AnchorPane prefHeight="480.0" prefWidth="720.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.controller.PersonnelController">
   <children>
      <ImageView fitHeight="90.0" fitWidth="120.0" onMouseClicked="#getAll" pickOnBounds="true" preserveRatio="true">
         <image>
            <Image url="@../Starfleet_Command_logo.jpg" />
         </image>
      </ImageView>
      <Label fx:id="welcomeMsg" layoutX="302.0" layoutY="45.0" prefHeight="16.0" prefWidth="116.0" AnchorPane.bottomAnchor="419.0" AnchorPane.leftAnchor="302.0" AnchorPane.rightAnchor="302.0" AnchorPane.topAnchor="45.0" />
      <Label fx:id="shipName" layoutX="302.0" layoutY="74.0" prefHeight="14.0" prefWidth="91.0" AnchorPane.bottomAnchor="390.0" AnchorPane.leftAnchor="302.0" AnchorPane.rightAnchor="302.0" AnchorPane.topAnchor="74.0">
         <font>
            <Font size="10.0" />
         </font>
      </Label>
      <GridPane layoutX="8.0" layoutY="131.0" prefHeight="347.0" prefWidth="703.0">
        <columnConstraints>
            <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
            <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
          <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
          <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
        </columnConstraints>
        <rowConstraints>
          <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
          <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
        </rowConstraints>
         <children>
            <ImageView fx:id="commandOfficer" fitHeight="120.0" fitWidth="100.0" pickOnBounds="true" preserveRatio="true" GridPane.halignment="CENTER" GridPane.valignment="TOP" />
            <ImageView fx:id="engineOfficer" fitHeight="120.0" fitWidth="100.0" layoutX="48.0" layoutY="10.0" pickOnBounds="true" preserveRatio="true" GridPane.columnIndex="3" GridPane.halignment="CENTER" GridPane.valignment="TOP" />
            <ImageView fx:id="commOfficer" fitHeight="120.0" fitWidth="100.0" layoutX="10.0" layoutY="37.0" pickOnBounds="true" preserveRatio="true" GridPane.columnIndex="2" GridPane.halignment="CENTER" GridPane.valignment="TOP" />
            <ImageView fx:id="firstOfficer" fitHeight="120.0" fitWidth="100.0" layoutX="10.0" layoutY="37.0" pickOnBounds="true" preserveRatio="true" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.valignment="TOP" />
            <ImageView fx:id="nurse" fitHeight="120.0" fitWidth="100.0" layoutX="48.0" layoutY="10.0" pickOnBounds="true" preserveRatio="true" GridPane.columnIndex="3" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="TOP" />
            <ImageView fx:id="medOfficer" fitHeight="120.0" fitWidth="100.0" layoutX="10.0" layoutY="37.0" pickOnBounds="true" preserveRatio="true" GridPane.columnIndex="2" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="TOP" />
            <ImageView fx:id="navigator" fitHeight="120.0" fitWidth="100.0" layoutX="10.0" layoutY="37.0" pickOnBounds="true" preserveRatio="true" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="TOP" />
            <ImageView fx:id="helmsman" fitHeight="120.0" fitWidth="100.0" layoutX="10.0" layoutY="37.0" pickOnBounds="true" preserveRatio="true" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="TOP" />
            <Label text="Commanding Officer" GridPane.halignment="CENTER" GridPane.valignment="BOTTOM">
               <GridPane.margin>
                  <Insets bottom="30.0" />
               </GridPane.margin>
            </Label>
            <Label layoutX="80.0" layoutY="138.0" text="Chief Medical Officer" GridPane.columnIndex="2" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="BOTTOM">
               <GridPane.margin>
                  <Insets bottom="30.0" />
               </GridPane.margin>
            </Label>
            <Label layoutX="10.0" layoutY="89.0" text="Navigator" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="BOTTOM">
               <GridPane.margin>
                  <Insets bottom="30.0" />
               </GridPane.margin>
            </Label>
            <Label layoutX="10.0" layoutY="89.0" text="Helmsman" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="BOTTOM">
               <GridPane.margin>
                  <Insets bottom="30.0" />
               </GridPane.margin>
            </Label>
            <Label layoutX="10.0" layoutY="89.0" text="Chief Engineering Officer" GridPane.columnIndex="3" GridPane.halignment="CENTER" GridPane.valignment="BOTTOM">
               <padding>
                  <Insets bottom="30.0" />
               </padding>
            </Label>
            <Label layoutX="10.0" layoutY="89.0" text="Communications Officer" GridPane.columnIndex="2" GridPane.halignment="CENTER" GridPane.valignment="BOTTOM">
               <GridPane.margin>
                  <Insets bottom="30.0" />
               </GridPane.margin>
            </Label>
            <Label layoutX="10.0" layoutY="89.0" text="First Officer" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.valignment="BOTTOM">
               <GridPane.margin>
                  <Insets bottom="30.0" />
               </GridPane.margin>
            </Label>
            <Label layoutX="80.0" layoutY="138.0" text="Nurse" GridPane.columnIndex="3" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="BOTTOM">
               <GridPane.margin>
                  <Insets bottom="30.0" />
               </GridPane.margin>
            </Label>
            <Label fx:id="crew1" text="Label" GridPane.halignment="CENTER" GridPane.valignment="BOTTOM">
               <GridPane.margin>
                  <Insets bottom="10.0" />
               </GridPane.margin></Label>
            <Label fx:id="crew8" layoutX="10.0" layoutY="89.0" text="Label" GridPane.columnIndex="3" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="BOTTOM">
               <GridPane.margin>
                  <Insets bottom="10.0" />
               </GridPane.margin></Label>
            <Label fx:id="crew7" layoutX="10.0" layoutY="89.0" text="Label" GridPane.columnIndex="2" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="BOTTOM">
               <GridPane.margin>
                  <Insets bottom="10.0" />
               </GridPane.margin></Label>
            <Label fx:id="crew6" layoutX="10.0" layoutY="89.0" text="Label" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="BOTTOM">
               <GridPane.margin>
                  <Insets bottom="10.0" />
               </GridPane.margin></Label>
            <Label fx:id="crew5" layoutX="10.0" layoutY="89.0" text="Label" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="BOTTOM">
               <GridPane.margin>
                  <Insets bottom="10.0" />
               </GridPane.margin></Label>
            <Label fx:id="crew4" layoutX="10.0" layoutY="89.0" text="Label" GridPane.columnIndex="3" GridPane.halignment="CENTER" GridPane.valignment="BOTTOM">
               <GridPane.margin>
                  <Insets bottom="10.0" />
               </GridPane.margin></Label>
            <Label fx:id="crew3" layoutX="10.0" layoutY="89.0" text="Label" GridPane.columnIndex="2" GridPane.halignment="CENTER" GridPane.valignment="BOTTOM">
               <GridPane.margin>
                  <Insets bottom="10.0" />
               </GridPane.margin></Label>
            <Label fx:id="crew2" layoutX="10.0" layoutY="89.0" text="Label" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.valignment="BOTTOM">
               <GridPane.margin>
                  <Insets bottom="10.0" />
               </GridPane.margin></Label>
         </children>
      </GridPane>
      <Button layoutX="627.0" layoutY="32.0" mnemonicParsing="false" onAction="#openFirstScene" text="Log Out" />
   </children>
</AnchorPane>

After logging in, none of the labels or images that should be returned by the getter methods are set.登录后,没有设置任何应该由 getter 方法返回的标签或图像。 I get only the "Welcome" string that I entered manually.我只得到手动输入的“欢迎”字符串。 So, the title says "Welcome, null."所以,标题写着“欢迎,null”。

The initialize method is called by FXMLLoader during the call of load .在调用load期间, FXMLLoader会调用initialize方法。 At that time none of the properties have been set, since you "preload" the scene.那时还没有设置任何属性,因为您“预加载”了场景。

I strongly recommend not using static data to pass around info.我强烈建议不要使用static数据来传递信息。 Sure it's convenient to be able to access the data, but this comes at the expense of not having any control on when/by what code the values are modified and never being able to have more than a single ship at once.当然,能够访问数据很方便,但这是以无法控制何时/通过什么代码修改值并且永远无法同时拥有超过一艘船为代价的。

You could instead use javafx properties to deal with this.您可以改为使用 javafx 属性来处理此问题。 The following class design is just abreviated missing the proper visibility modifiers, setters, (property) getters, initialisations and constructors, but I'm sure you could add this on your own:以下 class 设计只是省略了适当的可见性修饰符、设置器、(属性)获取器、初始化和构造函数,但我相信您可以自己添加:

class Starship

   StringProperty name;
   ObjectProperty<CrewMember> captain;

   // possibly replace the following property with individual properties for roles
   // or use a ObservableMap<Role, CrewMember> instead???
   ObservableList<CrewMember> crew;
}

// could we make this immutable instead??? 
class CrewMember {
    StringProperty name;
    ObjectProperty<Image> image;
}

This allows you to listen to modifications of the ship data:这允许您收听船舶数据的修改:

Starship ship = new Starship();

firstPaneController.setShip(ship);
secondPaneController.setShip(ship);

LoginController登录控制器

private Starship ship;

public void setShip(Starship ship) {
    this.ship = ship;
}

private void setAll(String user) {
    ship.setCaptain(new CrewMember(user));

    ship.getCrew().setAll(Stream.generate(() -> new CrewMember(user))
                                .limit(8)
                                .toArray(CrewMember[]::new));
}

PersonnelController人事控制器

private Label[] crewNameLabels;
private ImageView[] crewImageViews;

@Override
public void initialize(URL location, ResourceBundle resources) {
    crewNameLabels = new Label[] { crew1, crew2, crew3, crew4, crew5, crew6, crew7, crew8  };
    crewImageViews = new ImageView[] {
        commandOfficer,
        firstOfficer,
        commOfficer,
        engineOfficer,
        helmsman,
        navigator,
        medOfficer,
        nurse
    };
}

private final InvalidationListener crewUpdater = o -> {
    int newCrewSize = 0;
    if (ship != null) {
        List<Crew> crew = ship.getCrew();
        newCrewSize = ship.getCrew().size();
        if (newCrewSize > crewNameLabels.length) {
            newCrewSize = crewNameLabels.length;
        }
        for (int i = 0; i < newCrewSize; i++) {
            CrewMember c = crew.get(i);
            crewNameLabels[i].textProperty().bind(c.nameProperty());
            crewImageViews[i].imageProperty().bind(c.imageProperty());
        }
    }

    // unbind everything that has no corresponding CrewMember
    for (int i = newCrewSize; i < crewNameLabels.length; i++) {
        crewNameLabels[i].textProperty().unbind();
        crewNameLabels[i].setText("");
        crewImageViews[i].imageProperty().unbind();
        crewImageViews[i].setImage(null);
    }
};

private final InvalidationListener captainUpdater = o -> {
    CrewMember captain = null;
    if (ship != null) {
        captain = ship.getCaptain();
    }
    if (captain == null) {
        welcomeMsg.textProperty().unbind();
        welcomeMsg.setText("");
    } else {
        welcomeMessage.bind(Bindings.concat("Welcome, ", captain.nameProperty()));
    }
};

private Starship ship;

public void setShip(Starship ship) {
    if (this.ship != null) {
        // remove old listener when replacing the ship
        this.ship.getCrew().removeListener(crewUpdater);
        this.ship.captainProperty().removeListener(captainUpdater);
    }

    this.ship = ship;
    if (ship != null) {
        ship.getCrew().addListener(crewUpdater);
        ship.captainProperty().addListener(captainUpdater);
        shipName.textProperty().bind(ship.nameProperty());
    } else {
        shipName.textProperty().unbind();
        shipName.setText("");
    }

    // update content
    crewUpdater.invalidated(null);
    captainUpdater.invalidated(null);
}

This should allow you to update the Starship object anywhere on the JavaFX application thread and see the change in the personnel scene.这应该允许您在 JavaFX 应用程序线程的任何位置更新Starship object,并查看人员场景中的变化。 Making the CrewMember class immutable would reduce the complexity of the update a bit, since you'd no longer need to use bindings, but simply would need to do assignments.使CrewMember class 不可变会稍微降低更新的复杂性,因为您不再需要使用绑定,而只需要进行分配。 Also only ever having a single ship+personnel scene would allow you to remove the unbinding logic further simplifying the logic...同样,只有一个船+人员场景才能让您删除解除绑定的逻辑,从而进一步简化逻辑......

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM