FXMLLoader.getController() 不返回 null,但其中的组件仍为 null [duplicate]

FXMLLoader.getController() doesn't return null, but the components inside it remain null [duplicate]

提问人:Naeem Ahmad 提问时间:1/5/2023 更新时间:1/5/2023 访问量:71

问:

所以我有一个学校项目,我正在创建一个小型个人追踪器。我正在将任务和爱好动态添加到 FXML 文件中 GridPane 内的 FlowPane,该文件作为另一个 FXML 文件中 BorderPane 的中心元素加载。

   private void hobbies() throws IOException {
        Node[] taskview= new Node[GodHands.hobby.size()];
        for(int i=0;i<GodHands.hobby.size();i++){

            FXMLLoader loader=new FXMLLoader(getClass().getResource("/hobbies.fxml"));
            taskview[i]=loader.load();
            System.out.println(loader.getController()==null);
            GodHands.hobbycontroller.add(loader.getController());
            GodHands.hobbycontroller.get(i).update(GodHands.hobby.get(i));
            hobbysection.getChildren().add(taskview[i]);
        }
    }

这是用于将爱好添加到 Flowpane 的代码。然后,我尝试通过循环将数据应用于FXML文件内部的节点。控制器即使不是 null,单选按钮也始终为 null,我认为我缺少控制器工作的某些东西。

这是 Hobbies 控制器类的代码:

`public class HobbyController implements Initializable {

    @FXML private Label name; @FXML private Label often; @FXML private ProgressIndicator progress;
    @FXML private ToggleButton mon; @FXML private ToggleButton tue;  
    @FXML private ToggleButton wed; @FXML private ToggleButton thu;
    @FXML private ToggleButton fri; @FXML private ToggleButton sat; @FXML private ToggleButton sun;

    @FXML ToggleButton[] toggles={mon,tue,wed,thu,fri,sat,sun};


    public void update(Hobby hobby) {
        System.out.println(toggles[0]=null);
        hobby.hobby_display(name, often, toggles, progress);

    }


    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {}

}

这是控制器所指的爱好类:

public class Hobby{

    public String name; public String often; public int[] days; public int[] progress = new int[2];

    public Hobby(){}

    public Hobby(String name, String often, int[] days){
        this.name=name;
        this.often = often;
        this.days = days;
    }

    public void add_new_hobby(String name, String oftenbox, int[] days) {
        this.name= name; this.often =oftenbox; this.days=days;
        GodHands.hobby.add(this);
    }

    public void hobby_display(Label name, Label often, ToggleButton[] toggles, ProgressIndicator progress){
        name.setText(this.name);
        often.setText(this.often);
        often.setAlignment(Pos.CENTER);
        this.progress[1]=7;
        int i=0;
        for(ToggleButton TB: toggles){
            button_state(TB, this.days[i]);
            i+=1;
        }
        progress.setProgress((double) this.progress[0]/this.progress[1]);
        action_setter(toggles, progress);
    }


    private void button_state(ToggleButton a, int i){
        if(i==0){
            a.setDisable(true);
            a.setOpacity(0.5);
            this.progress[1] -=1;}
        if(i==2){
            a.setSelected(true);
            a.setDisable(true);
            a.setOpacity(1);
        }
    }

    public void action_setter(ToggleButton[] toggles, ProgressIndicator progress){
        int i=0;
        for(ToggleButton TB: toggles){
            int index = i;
            TB.setOnAction(actionEvent -> { button_pressed(TB, progress, index);});
            i+=1;
        }
    }

    private void button_pressed(ToggleButton a, ProgressIndicator progress, int index){
        a.setDisable(true);
        a.setOpacity(1);
        this.progress[0]+=1;
        this.days[index]=2;
        progress.setProgress((double) this.progress[0]/this.progress[1]);
    }
}

FXML 文件:

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

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ProgressIndicator?>
<?import javafx.scene.control.ToggleButton?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.paint.Color?>
<?import javafx.scene.paint.LinearGradient?>
<?import javafx.scene.paint.Stop?>
<?import javafx.scene.shape.Line?>
<?import javafx.scene.shape.Rectangle?>
<?import javafx.scene.text.Font?>

<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="66.0" prefWidth="515.0" spacing="20.0" style="-fx-background-color: #19B89B; -fx-background-radius: 20; -fx-border-color: white; -fx-border-radius: 20;" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Project.HobbyController">
   <children>
      <Pane prefHeight="65.0" prefWidth="531.0">
         <children>
            <Rectangle arcHeight="5.0" arcWidth="5.0" height="65.0" layoutX="-1.0" layoutY="-1.0" stroke="WHITE" strokeType="INSIDE" style="-fx-arc-height: 40; -fx-arc-width: 40;" width="515.0">
               <fill>
                  <LinearGradient endX="1.0" endY="1.0" startX="0.03546099290780142" startY="0.08983451536643026">
                     <stops>
                        <Stop>
                           <color>
                              <Color red="0.4470588266849518" green="0.2705882489681244" blue="0.929411768913269" />
                           </color>
                        </Stop>
                        <Stop offset="1.0">
                           <color>
                              <Color red="0.7904239892959595" green="0.28344297409057617" blue="0.8684210777282715" />
                           </color>
                        </Stop>
                     </stops>
                  </LinearGradient>
               </fill>
            </Rectangle>
            <ImageView fitHeight="24.0" fitWidth="26.0" layoutX="14.0" layoutY="3.0" pickOnBounds="true" preserveRatio="true">
               <image>
                  <Image url="@icons/about.png" />
               </image>
            </ImageView>
            <Label fx:id="name" layoutX="49.0" layoutY="7.0" prefHeight="16.0" prefWidth="157.0" text="Studying" textFill="WHITE">
               <font>
                  <Font name="Arial" size="14.0" />
               </font>
            </Label>
            <Line endX="100.0" endY="13.0" layoutX="-57.0" layoutY="25.0" startX="100.0" startY="-20.0" stroke="WHITE" />
            <Label fx:id="often" layoutX="49.0" layoutY="28.0" prefHeight="14.0" prefWidth="58.0" style="-fx-border-color: white; -fx-border-radius: 15; -fx-background-color: #3A545A;" text=" Everyday" textFill="WHITE">
               <font>
                  <Font name="Arial" size="7.0" />
               </font>
            </Label>
            <ProgressIndicator fx:id="progress" layoutX="477.0" layoutY="15.0" mouseTransparent="true" prefHeight="57.0" prefWidth="27.0" progress="0.0" style="-fx-background-color: transparent;" stylesheets="@pi.css" />
         </children>
      </Pane>
      <HBox prefHeight="100.0" prefWidth="386.0" spacing="5.0">
         <children>
            <ToggleButton fx:id="mon" mnemonicParsing="false" prefHeight="25.0" prefWidth="33.0" stylesheets="@button%20-%20Copy%20-%20Copy.css" text="M">
               <font>
                  <Font name="Arial Bold" size="10.0" />
               </font>
               <HBox.margin>
                  <Insets left="130.0" top="10.0" />
               </HBox.margin>
            </ToggleButton>
            <ToggleButton fx:id="tue" mnemonicParsing="false" prefHeight="25.0" prefWidth="33.0" stylesheets="@button%20-%20Copy%20-%20Copy.css" text="Tu">
               <font>
                  <Font name="Arial Bold" size="10.0" />
               </font>
               <HBox.margin>
                  <Insets top="10.0" />
               </HBox.margin>
            </ToggleButton>
            <ToggleButton fx:id="wed" mnemonicParsing="false" prefHeight="25.0" prefWidth="36.0" stylesheets="@button%20-%20Copy%20-%20Copy.css" text="We">
               <font>
                  <Font name="Arial Bold" size="10.0" />
               </font>
               <HBox.margin>
                  <Insets top="10.0" />
               </HBox.margin>
            </ToggleButton>
            <ToggleButton fx:id="thu" mnemonicParsing="false" prefHeight="25.0" prefWidth="33.0" stylesheets="@button%20-%20Copy%20-%20Copy.css" text="Th">
               <font>
                  <Font name="Arial Bold" size="10.0" />
               </font>
               <HBox.margin>
                  <Insets top="10.0" />
               </HBox.margin>
            </ToggleButton>
            <ToggleButton fx:id="fri" mnemonicParsing="false" prefHeight="25.0" prefWidth="33.0" stylesheets="@button%20-%20Copy%20-%20Copy.css" text="Fr">
               <font>
                  <Font name="Arial Bold" size="10.0" />
               </font>
               <HBox.margin>
                  <Insets top="10.0" />
               </HBox.margin>
            </ToggleButton>
            <ToggleButton fx:id="sat" mnemonicParsing="false" prefHeight="25.0" prefWidth="33.0" stylesheets="@button%20-%20Copy%20-%20Copy.css" text="Sa">
               <font>
                  <Font name="Arial Bold" size="10.0" />
               </font>
               <HBox.margin>
                  <Insets top="10.0" />
               </HBox.margin>
            </ToggleButton>
            <ToggleButton fx:id="sun" mnemonicParsing="false" prefHeight="25.0" prefWidth="33.0" stylesheets="@button%20-%20Copy%20-%20Copy.css" text="Su">
               <font>
                  <Font name="Arial Bold" size="10.0" />
               </font>
               <HBox.margin>
                  <Insets top="10.0" />
               </HBox.margin>
            </ToggleButton>
         </children>
         <VBox.margin>
            <Insets left="65.0" />
         </VBox.margin>
      </HBox>
   </children>
</VBox>

这是错误:

false
null
Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: com.example.personalmanagementsystem/Project.Internal.switchers.dashboard(switchers.java:52)
    at com.example.personalmanagementsystem/Project.DashboardController.dashboard(DashboardController.java:29)
    ... 57 more
Caused by: java.lang.NullPointerException: Cannot invoke "javafx.scene.control.ToggleButton.setDisable(boolean)" because "a" is null
    at com.example.personalmanagementsystem/Project.Internal.Hobby.button_state(Hobby.java:44)
    at com.example.personalmanagementsystem/Project.Internal.Hobby.hobby_display(Hobby.java:34)
    at com.example.personalmanagementsystem/Project.HobbyController.update(HobbyController.java:23)
    at com.example.personalmanagementsystem/Project.DashboardContentController.hobbies(DashboardContentController.java:86)
    at com.example.personalmanagementsystem/Project.DashboardContentController.initialize(DashboardContentController.java:31)
    at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2655)
    ... 61 more

我还没有找到任何解决方案。请提供一些关于为什么会发生这种情况的见解。我对 FX 和整个编程还是陌生的。谢谢。

Java JavaFX 控制器 NullPointerException

评论

0赞 Naeem Ahmad 1/5/2023
@kloeopatra我不确定你的意思,你在代码中的意思吗?
0赞 Slaw 1/5/2023
例如:方法名称使用(例如,应该是)。对方法使用驼峰大小写是标准 Java 命名约定的一部分。它们不会影响代码的行为(至少在这种情况下不会),但是在公共论坛上发帖时使用广泛接受的标准有助于提高可读性。camelCasehobby_displayhobbyDisplay
0赞 Naeem Ahmad 1/5/2023
@Slaw 哦,对不起。我不知道。从下次开始,我会注意遵循标准惯例。
0赞 Slaw 1/5/2023
查看 javatpoint.com/java-naming-conventions

答:

2赞 Slaw 1/5/2023 #1

问题就在这里:

@FXML ToggleButton[] toggles={mon,tue,wed,thu,fri,sat,sun}

这是在实例化控制器时执行的,这发生在注入 FXML 字段之前。换句话说,在执行这行代码时,、、、和都是。montuewedthufrisatsunnull

一种解决方案是在以下方法中创建数组:initialize


// ...

private ToggleButton[] toggles; // no @FXML necessary, as it's not being injected

// ...

@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
    // the FXML-injected fields are injected by the time this method is called
    toggles = new ToggleButton[]{mon, tue, wed, thu, fri, sat, sun};
}

// ...

如果您想尝试在 FXML 中定义数组并注入它,请查看 and(请参阅 FXML 简介)。尽管您可能必须更改为列表实现而不是数组;我不确定FXML是否能够创建数组。fx:definefx:reference


关于设计的注意事项:你的类看起来是一个模型类。模型不应知道视图。负责设置各种UI节点的内容和属性并不理想。这是控制器的工作。此外,鉴于您正在处理一周中的几天,您可能需要考虑使用 API(例如,DayOfWeek)。HobbyHobbyjava.time

评论

0赞 Naeem Ahmad 1/5/2023
谢谢,这解决了我的问题。我只是在理解一般流程的工作原理时遇到了一些问题。是的,我将努力使模型独立。如果它不是问题/违反论坛政策,我还有一个问题,就像上面的代码一样,如果我必须从动态添加的 FXML 文件访问 FXML 文件的控制器,最好的方法是什么?如果这是一个问题,如果你能把我链接到某个地方就好了。谢谢!
0赞 Slaw 1/5/2023
我不确定我是否理解这个问题。您可以从实例中获取控制器,这很好。这就是获取托管控制器实例的方式。从那里,理想情况下,您将通过模型在控制器之间进行通信。研究 MVC、MVP 和 MVVM 等软件架构模式。例如:将 MVC 与 JavaFx 一起应用FXMLLoader
0赞 Naeem Ahmad 1/5/2023
是的,这正是我想问的,一个模型。非常感谢您抽出时间接受采访。