在fxml中定义的自定义控件 - 如何获取父ID?

时间:2014-04-11 16:11:32

标签: java javafx custom-controls fxml

我有一个像这样定义的自定义控件:

<fx:root type="javafx.scene.Group" xmlns:fx="http://javafx.com/fxml" fx:controller="com.theCorp.theTool.controllers.LimitsController">
  <Group id="Group" layoutX="0.0" layoutY="0.0">
    <children>
        <Group id="Count" layoutX="0.0" layoutY="20.0">
            <children>
                <Label layoutX="0.0" layoutY="3.0" prefWidth="59.0" text="Count" />
                <TextField id="Count.Min" fx:id="countMin" layoutX="59.0" layoutY="0.0" prefWidth="132.0" promptText="Min" />
                <TextField id="Count.Max" fx:id="countMax" layoutX="191.0" layoutY="0.0" prefWidth="132.0" promptText="Max" />
            </children>
        </Group>
        <Button id="SaveButton" fx:id="saveButton" layoutX="12.0" layoutY="85.0" mnemonicParsing="false" onAction="#save" text="Save" />
    </children>
  </Group>
</fx:root>

我有一个Control类,以通常的方式加载它:

public class LimitsControl extends Group {
  private static final String fxmlFileName = "Limits.fxml";

  public LimitsControl() {
    super();
    URL fxml = getClass().getResource(fxmlFileName);
    if (fxml == null) {
      fxml = getClass().getResource("/fxml/" + fxmlFileName);
    }
    // Create the loader.
    FXMLLoader loader = new FXMLLoader(fxml);
    loader.setRoot(this);
    try {
      // Load the fxml.
      loader.load();
      // Pull back the controller.
      LimitsController controller = loader.getController();
      // Tell it about me.
      controller.setControl(this);
    } catch (IOException exception) {
      throw new RuntimeException(exception);
    }
  }

}

我有一个Controller类看起来有点像这样:

public class LimitsController implements Initializable {
  // Control.
  private LimitsControl control;

  @FXML
  private TextField countMin;
  @FXML
  private TextField countMax;
  @FXML
  private Button saveButton;

  /**
   * Initializes the controller class.
   *
   * @param url
   * @param rb
   */
  @Override
  public void initialize(URL url, ResourceBundle rb) {
    log.info("Loading: " + url + " rb=" + rb+" control="+control);
    // Make the save button call my save.
    saveButton.setOnAction((ActionEvent e) -> {
      save(e);
    });
  }


  public void setControl(LimitsControl control) {
    log.info("Control="+control);
    this.control = control;
  }

  @FXML
  private void save(ActionEvent event) {
    // What is the ID of me?
    Parent myGroup = saveButton.getParent();
    // Pull the id of the control that enclosed my group.
    String myId = myGroup.getParent().getId();
    log.info("Saving: " + myId);
  }

}

我在几个地方的场景中插入这些控件,每次使用不同的id,如下所示:

        <TitledPane fx:id="Today" animated="false" text="Today">
          <tooltip>
            <Tooltip text="Parameters will only be used for today." />
          </tooltip>
          <content>
            <LimitsControl id="Today.Limits" />
          </content>
        </TitledPane>

我的问题是这些控件必须从需要id控件的数据中填充,但是当控制器初始化时,它没有父控件。

按下保存按钮时id可用 - 请参阅攀爬父树的save方法以收集控件的ID。遗憾的是,父级在初始化时为空。

如何在父ID可用时正确初始化字段?或者我做错了还有right方式?

1 个答案:

答案 0 :(得分:2)

首先,注入控件而不是使用set方法耦合所有内容:

<fx:root type="javafx.scene.Group" xmlns:fx="http://javafx.com/fxml" fx:controller="com.theCorp.theTool.controllers.LimitsController" fx:id="control">

  // Control.
  @FXML
  private LimitsControl control;

如果我理解正确,你想要获得的id是LimitsControl本身的id。为了使其可用&#34;早期&#34;,在LimitsControl的构造函数中定义一个参数并在那里设置id:

  public LimitsControl(String id) {
    super();
    setId(id);
        // code as before...
      }

现在,因为您不再拥有默认构造函数,所以需要为LimitsControl创建一个Builder:

public class LimitsControlBuilder {
    private String id ;
    private LimitsControlBuilder() {
        this.id = "" ;
    }
    public static LimitsControlBuilder create() {
        return new LimitsControlBuilder();
    }
    public LimitsControlBuilder id(String id) {
        this.id = id ;
        return this ;
    }

    public LimitsControl build() {
        return new LimitsControl(id);
    }
}

现在你可以做到

<LimitsControl id="Today.Limits" />

,一旦调用构造函数,就会设置它。

您当然可以在此处创建自己的属性,而不是使用id,这可能是fxml将信息传递给自定义控件实例比使用css id更合适的方式。