繁体   English   中英

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

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

我遇到的唯一问题是 getAll() 方法,它似乎在我在 PersonnelController class 中的位置立即运行。 不过我在其他很多地方也试过了,但无济于事。 setAll() 方法似乎很好,我已经测试过 setAll() 将值传递给的方法可以将正确的值返回给 main 方法。 他们只是出于某种原因没有在我需要的正确时间将值返回给 controller。

应该发生的是用户输入他们的用户名和密码,然后单击登录按钮,这就是在 secondScene 加载之前可以将可注入值传递给 FXML 的地方。 根据他们输入的用户名,一组不同的图片和标签将出现在第二个场景中。 我有程序调用的getter和setter方法来设置文本和图像。

人员控制器.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();
            }
}

登录控制器.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'.";

            }
}

主.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).

人员.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>

登录后,没有设置任何应该由 getter 方法返回的标签或图像。 我只得到手动输入的“欢迎”字符串。 所以,标题写着“欢迎,null”。

在调用load期间, FXMLLoader会调用initialize方法。 那时还没有设置任何属性,因为您“预加载”了场景。

我强烈建议不要使用static数据来传递信息。 当然,能够访问数据很方便,但这是以无法控制何时/通过什么代码修改值并且永远无法同时拥有超过一艘船为代价的。

您可以改为使用 javafx 属性来处理此问题。 以下 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;
}

这允许您收听船舶数据的修改:

Starship ship = new Starship();

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

登录控制器

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));
}

人事控制器

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);
}

这应该允许您在 JavaFX 应用程序线程的任何位置更新Starship object,并查看人员场景中的变化。 使CrewMember class 不可变会稍微降低更新的复杂性,因为您不再需要使用绑定,而只需要进行分配。 同样,只有一个船+人员场景才能让您删除解除绑定的逻辑,从而进一步简化逻辑......

暂无
暂无

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

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