代码之家  ›  专栏  ›  技术社区  ›  tlarson

JavaFX FXML文本组件控制器未更新

  •  0
  • tlarson  · 技术社区  · 7 年前

    在使用FXMLLoader动态创建FXML文本组件之后,我很难更新它。这个看似简单的程序要求用户输入要掷骰子的数量,根据此输入创建新骰子,使用随机数生成器掷骰子,对这些值求和,并提供一个按钮,如果需要,可以重新掷骰子。每个模具都会添加到主窗口(使用FXMLoader和自定义模具组件),显示其索引、滚动值,以及要重新滚动特定模具时要按下的按钮。模具的价值呈现并更新得很好。重新滚动按钮工作得很好。然而,由于某些原因,每个模具的索引不会显示在窗口中,甚至最初也不会显示。所讨论的文本组件(不会显示任何值的组件)标识为 fx:id=“编号” 在自定义FXML文档中,并作为@ FXML专用文本编号 在自定义控制器中。

    我假设这个问题与文本组件的getter和setter有关,我很幸运 价值 作品然而,如果是这样的话,专有名称已经暗示了我,因为我已经检查了许多涉及 所有物 以名称等。

    注:我知道当按下重新滚动按钮时,模具值的总和不会更新。我现在只关心模具值的更新。

    该程序的FXML主窗口为:

    <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循环中动态创建的模具自定义组件为(问题组件为 fx:id=“编号” ):

    <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) {
    }
    }
    
    1 回复  |  直到 7 年前
        1
  •  1
  •   James_D    7 年前

    问题是您创建了一个新的 Text 实例,而不是配置已在FXML中创建的实例:

    this.number = new Text(String.valueOf(i));
    

    一个 @FXML 注释是指字段由 FXMLLoader ,确实如此 总是 初始化带注释的字段时出错 @FXML

    请注意,这些字段由 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));
    }