提问人:Naeem Ahmad 提问时间:1/5/2023 更新时间:1/5/2023 访问量:71
FXMLLoader.getController() 不返回 null,但其中的组件仍为 null [duplicate]
FXMLLoader.getController() doesn't return null, but the components inside it remain null [duplicate]
问:
所以我有一个学校项目,我正在创建一个小型个人追踪器。我正在将任务和爱好动态添加到 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 和整个编程还是陌生的。谢谢。
答:
2赞
Slaw
1/5/2023
#1
问题就在这里:
@FXML ToggleButton[] toggles={mon,tue,wed,thu,fri,sat,sun}
这是在实例化控制器时执行的,这发生在注入 FXML 字段之前。换句话说,在执行这行代码时,、、、和都是。mon
tue
wed
thu
fri
sat
sun
null
一种解决方案是在以下方法中创建数组: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:define
fx:reference
关于设计的注意事项:你的类看起来是一个模型类。模型不应知道视图。负责设置各种UI节点的内容和属性并不理想。这是控制器的工作。此外,鉴于您正在处理一周中的几天,您可能需要考虑使用 API(例如,DayOfWeek)。Hobby
Hobby
java.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
是的,这正是我想问的,一个模型。非常感谢您抽出时间接受采访。
评论
camelCase
hobby_display
hobbyDisplay