JavaFX FXML 文本组件控制器未更新
JavaFX FXML Text Component Controller not updating
在使用 FXMLLoader 动态创建后,我很难更新 FXML 文本组件。这个看似简单的程序要求用户输入要掷的骰子的数量,根据此输入创建新的骰子,用随机数生成器掷骰子,对这些值求和,并提供一个按钮来重新掷骰子,如果他们想。每个骰子都添加到主 window(使用 FXMLLoader 和自定义骰子组件),显示其索引、掷骰子的值以及要重新掷骰子时要按下的按钮。模具的价值存在和更新很大。重新滚动按钮效果很好。然而,出于某种原因,每个骰子的索引都没有显示在 window 中——甚至一开始也不显示。有问题的文本组件(不显示任何值的组件)在自定义 FXML 文档中被标识为 fx:id="number" 和 @FXML private Text number 在自定义控制器中。
我假设问题与 Text 组件的 getter 和 setter 有关,我很幸运,名为 value 的 Text 组件可以正常工作。但是,如果是这种情况,专有名称已经暗示了我,因为我已经检查了名称中涉及 属性 等的许多替代方案
注意:我知道按下重新滚动按钮时不会更新骰子值的总和。我现在只关心正在更新的模具值。
程序的主要 FXML window 是:
<GridPane fx:id="mainPane"
styleClass="mainFxmlClass"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="org.lgdor.dieSim.MainWindowController"
xmlns="http://javafx.com/javafx/8.0_40"
prefHeight="800.0"
prefWidth="800.0"
hgap="10"
vgap="10" >
<stylesheets>
<URL value="@mainwindow.css"/>
</stylesheets>
<padding>
<Insets top="25" right="25" bottom="10" left="25"/>
</padding>
<Text fx:id="welcomeText" text="Welcome to DieSim"
GridPane.columnIndex="0"
GridPane.rowIndex="0"
GridPane.columnSpan="5"/>
<Label fx:id="spinnerText"
text="Please input the number of dice you want to roll:"
GridPane.columnIndex="0"
GridPane.rowIndex="1"
GridPane.columnSpan="2"/>
<Spinner fx:id="spinner" editable="true"
GridPane.columnIndex="3"
GridPane.rowIndex="1" />
<HBox fx:id="buttonBox"
spacing="10"
alignment="center"
GridPane.columnIndex="5"
GridPane.rowIndex="1">
<Button text="Roll Dice" onAction="#createDice"/>
</HBox>
<Label fx:id="dieNumberText" text="The number of dice is: "
GridPane.columnIndex="0"
GridPane.rowIndex="2"
GridPane.columnSpan="2"/>
<Text fx:id="dieNumber" GridPane.columnIndex="3" GridPane.rowIndex="2" />
<Label fx:id="dieSumText" text="The sum of the dice is: "
GridPane.columnIndex="0"
GridPane.rowIndex="3"
GridPane.columnSpan="2"/>
<Text fx:id="sumNumber" GridPane.columnIndex="3" GridPane.rowIndex="3" />
<VBox fx:id="rowBox"
spacing="10"
alignment="center"
GridPane.columnIndex="0"
GridPane.rowIndex="4"
GridPane.columnSpan="5" >
<Text text="This is where the list of dice goes..."/>
</VBox>
这个的主要控制器是:
public class MainWindowController implements Initializable {
@FXML
Label spinnerText;
@FXML
Spinner spinner;
@FXML
HBox buttonBox;
@FXML
Text dieNumber;
@FXML
Text sumNumber;
@FXML
int numberOfDice = 0;
@FXML
int sumOfDice = 0;
@FXML
VBox rowBox;
private List<Die> dieList = new ArrayList<>();
private List<GridPane> rowList = new ArrayList<>();
public void createDice() throws IOException{
numberOfDice = (int)spinner.getValue();
for (int i=0;i<numberOfDice;i++){
Die die = new Die(i);
die.roll(null);
sumOfDice = sumOfDice + Integer.parseInt(die.getValue());
dieList.add(die);
rowBox.getChildren().add(die);
}
dieNumber.setText(String.valueOf(numberOfDice));
sumNumber.setText(String.valueOf(sumOfDice));
spinner.setVisible(false);
spinnerText.setVisible(false);
buttonBox.setVisible(false);
}
/**
* Initializes the controller class.
*/
@Override
public void initialize(URL url, ResourceBundle rb) {
spinner.setValueFactory(new SpinnerValueFactory.IntegerSpinnerValueFactory(1, 20));
dieNumber.setText("0");
sumNumber.setText(String.valueOf("0"));
spinnerText.setVisible(true);
spinner.setVisible(true);
buttonBox.setVisible(true);
}
}
上面for循环中动态创建的die自定义组件是(问题组件是fx:id="number"):
<fx:root type="javafx.scene.layout.GridPane"
xmlns:fx="http://javafx.com/fxml/1"
xmlns="http://javafx.com/javafx/8.0_40" >
<HBox spacing="30" alignment="center" GridPane.columnIndex="0" GridPane.rowIndex="0" >
<Text fx:id="number" /><!--This is the problem component-->
<Text fx:id="value"/>
<Button fx:id="dieButton" text="Roll Dice" onAction="#roll" />
</HBox>
</fx:root>
其动态创建的控制器是:
public class Die extends GridPane implements Initializable {
@FXML
private Text number;//This is the problem component ...
public String getNumber() {
return numberTextProperty().get();
}
public void setNumber(String number) {
numberTextProperty().set(number);
}
public StringProperty numberTextProperty() {
return number.textProperty();
}
@FXML
private Text value;
public String getValue() {
return valueTextProperty().get();
}
public void setValue(String value) {
valueTextProperty().set(value);
}
public StringProperty valueTextProperty() {
return value.textProperty();
}
public Die(int i) throws IOException{
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("DieGUI.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
this.number = new Text(String.valueOf(i));
this.setNumber(String.valueOf(1));
this.value = new Text();
this.setValue(String.valueOf(1));
fxmlLoader.load();
}
@FXML
public void roll(ActionEvent event){
this.setValue(String.valueOf((int)(6*Math.random()+1)));
}
@Override
public void initialize(URL location, ResourceBundle resources) {
}
}
问题是您创建了一个新的 Text
实例,而不是配置已在 FXML 中创建的实例:
this.number = new Text(String.valueOf(i));
@FXML
注释的全部目的是指示该字段由 FXMLLoader
初始化,因此总是 初始化错误带注释的字段 @FXML
.
这里注意这些字段是在调用load()
的时候由FXMLLoader
初始化的,所以需要在之前调用load()
您可以任意配置它们。
因此您的构造函数应如下所示:
public Die(int i) throws IOException{
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("DieGUI.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
fxmlLoader.load();
// these don't seem to do anything useful?
// this.setNumber(String.valueOf(1));
// this.setValue(String.valueOf(1));
this.number.setText(String.valueOf(i));
this.value.setText(String.valueOf(i));
}
在使用 FXMLLoader 动态创建后,我很难更新 FXML 文本组件。这个看似简单的程序要求用户输入要掷的骰子的数量,根据此输入创建新的骰子,用随机数生成器掷骰子,对这些值求和,并提供一个按钮来重新掷骰子,如果他们想。每个骰子都添加到主 window(使用 FXMLLoader 和自定义骰子组件),显示其索引、掷骰子的值以及要重新掷骰子时要按下的按钮。模具的价值存在和更新很大。重新滚动按钮效果很好。然而,出于某种原因,每个骰子的索引都没有显示在 window 中——甚至一开始也不显示。有问题的文本组件(不显示任何值的组件)在自定义 FXML 文档中被标识为 fx:id="number" 和 @FXML private Text number 在自定义控制器中。
我假设问题与 Text 组件的 getter 和 setter 有关,我很幸运,名为 value 的 Text 组件可以正常工作。但是,如果是这种情况,专有名称已经暗示了我,因为我已经检查了名称中涉及 属性 等的许多替代方案
注意:我知道按下重新滚动按钮时不会更新骰子值的总和。我现在只关心正在更新的模具值。
程序的主要 FXML window 是:
<GridPane fx:id="mainPane"
styleClass="mainFxmlClass"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="org.lgdor.dieSim.MainWindowController"
xmlns="http://javafx.com/javafx/8.0_40"
prefHeight="800.0"
prefWidth="800.0"
hgap="10"
vgap="10" >
<stylesheets>
<URL value="@mainwindow.css"/>
</stylesheets>
<padding>
<Insets top="25" right="25" bottom="10" left="25"/>
</padding>
<Text fx:id="welcomeText" text="Welcome to DieSim"
GridPane.columnIndex="0"
GridPane.rowIndex="0"
GridPane.columnSpan="5"/>
<Label fx:id="spinnerText"
text="Please input the number of dice you want to roll:"
GridPane.columnIndex="0"
GridPane.rowIndex="1"
GridPane.columnSpan="2"/>
<Spinner fx:id="spinner" editable="true"
GridPane.columnIndex="3"
GridPane.rowIndex="1" />
<HBox fx:id="buttonBox"
spacing="10"
alignment="center"
GridPane.columnIndex="5"
GridPane.rowIndex="1">
<Button text="Roll Dice" onAction="#createDice"/>
</HBox>
<Label fx:id="dieNumberText" text="The number of dice is: "
GridPane.columnIndex="0"
GridPane.rowIndex="2"
GridPane.columnSpan="2"/>
<Text fx:id="dieNumber" GridPane.columnIndex="3" GridPane.rowIndex="2" />
<Label fx:id="dieSumText" text="The sum of the dice is: "
GridPane.columnIndex="0"
GridPane.rowIndex="3"
GridPane.columnSpan="2"/>
<Text fx:id="sumNumber" GridPane.columnIndex="3" GridPane.rowIndex="3" />
<VBox fx:id="rowBox"
spacing="10"
alignment="center"
GridPane.columnIndex="0"
GridPane.rowIndex="4"
GridPane.columnSpan="5" >
<Text text="This is where the list of dice goes..."/>
</VBox>
这个的主要控制器是:
public class MainWindowController implements Initializable {
@FXML
Label spinnerText;
@FXML
Spinner spinner;
@FXML
HBox buttonBox;
@FXML
Text dieNumber;
@FXML
Text sumNumber;
@FXML
int numberOfDice = 0;
@FXML
int sumOfDice = 0;
@FXML
VBox rowBox;
private List<Die> dieList = new ArrayList<>();
private List<GridPane> rowList = new ArrayList<>();
public void createDice() throws IOException{
numberOfDice = (int)spinner.getValue();
for (int i=0;i<numberOfDice;i++){
Die die = new Die(i);
die.roll(null);
sumOfDice = sumOfDice + Integer.parseInt(die.getValue());
dieList.add(die);
rowBox.getChildren().add(die);
}
dieNumber.setText(String.valueOf(numberOfDice));
sumNumber.setText(String.valueOf(sumOfDice));
spinner.setVisible(false);
spinnerText.setVisible(false);
buttonBox.setVisible(false);
}
/**
* Initializes the controller class.
*/
@Override
public void initialize(URL url, ResourceBundle rb) {
spinner.setValueFactory(new SpinnerValueFactory.IntegerSpinnerValueFactory(1, 20));
dieNumber.setText("0");
sumNumber.setText(String.valueOf("0"));
spinnerText.setVisible(true);
spinner.setVisible(true);
buttonBox.setVisible(true);
}
}
上面for循环中动态创建的die自定义组件是(问题组件是fx:id="number"):
<fx:root type="javafx.scene.layout.GridPane"
xmlns:fx="http://javafx.com/fxml/1"
xmlns="http://javafx.com/javafx/8.0_40" >
<HBox spacing="30" alignment="center" GridPane.columnIndex="0" GridPane.rowIndex="0" >
<Text fx:id="number" /><!--This is the problem component-->
<Text fx:id="value"/>
<Button fx:id="dieButton" text="Roll Dice" onAction="#roll" />
</HBox>
</fx:root>
其动态创建的控制器是:
public class Die extends GridPane implements Initializable {
@FXML
private Text number;//This is the problem component ...
public String getNumber() {
return numberTextProperty().get();
}
public void setNumber(String number) {
numberTextProperty().set(number);
}
public StringProperty numberTextProperty() {
return number.textProperty();
}
@FXML
private Text value;
public String getValue() {
return valueTextProperty().get();
}
public void setValue(String value) {
valueTextProperty().set(value);
}
public StringProperty valueTextProperty() {
return value.textProperty();
}
public Die(int i) throws IOException{
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("DieGUI.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
this.number = new Text(String.valueOf(i));
this.setNumber(String.valueOf(1));
this.value = new Text();
this.setValue(String.valueOf(1));
fxmlLoader.load();
}
@FXML
public void roll(ActionEvent event){
this.setValue(String.valueOf((int)(6*Math.random()+1)));
}
@Override
public void initialize(URL location, ResourceBundle resources) {
}
}
问题是您创建了一个新的 Text
实例,而不是配置已在 FXML 中创建的实例:
this.number = new Text(String.valueOf(i));
@FXML
注释的全部目的是指示该字段由 FXMLLoader
初始化,因此总是 初始化错误带注释的字段 @FXML
.
这里注意这些字段是在调用load()
的时候由FXMLLoader
初始化的,所以需要在之前调用load()
您可以任意配置它们。
因此您的构造函数应如下所示:
public Die(int i) throws IOException{
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("DieGUI.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
fxmlLoader.load();
// these don't seem to do anything useful?
// this.setNumber(String.valueOf(1));
// this.setValue(String.valueOf(1));
this.number.setText(String.valueOf(i));
this.value.setText(String.valueOf(i));
}