跨嵌入式场景的 TextField textProperty Listener JavaFX

TextField textProperty Listener across embedded scenes JavaFX

这可能有点令人费解,但请耐心等待。

我有 3 个场景是使用 SceneBuilder 构建的。第一个 ("Main") 我用作父场景。此场景包含 1 个 AnchorPane,其中包含一个 TabPane 和一个 ToolBar,其中包含 3 个 Buttons("Previous"、"Next" 和 "Close" ).

第二个场景("PersonaDetails")包含一个AnchorPane,一个GridPane多个Textflow(我将其用作字段标签)几个TextFieldDatePicker。整个场景嵌入到第一个场景 ("Main") 的 TabPane 的一个选项卡中。

第三个场景 ("Address") 与第二个非常相似,其中包含一个 AnchorPane、一个 GridPane 多个 Textflow(我正在使用作为字段标签)几个 TextFieldComboBox。整个场景嵌入到第一个场景 ("Main") 的 TabPane 的另一个选项卡中。

(我已经包含了下面每个的 FXML 脚本)

应用程序稍后将在第一个场景 ("Main") 的 TabPane 的附加选项卡上包含附加场景。此应用程序将构成更大应用程序的一部分,旨在成为一种允许注册新客户的向导。

此外,每个 FXML 文件及其控制器都在单独的包中。

我遇到的这个问题是我需要在几个 Textfield 上添加 .textProperty() 侦听器,以便我可以启用或禁用 [​​=73=] Button在第一个或父场景中 ("Main")。

我已经在 MainController class 中尝试了以下代码,但它不起作用,尽管它不会产生任何错误。

package com.yas.registrationwizard.main;

import com.yas.registrationwizard.personaldetails.PersonalDetailsController;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.TabPane;
import javafx.scene.control.ToolBar;
import javafx.scene.layout.AnchorPane;

import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;

public class MainController implements Initializable {

    @FXML AnchorPane apMain;
    @FXML ToolBar tbMain;
    @FXML TabPane tpMain;

    @FXML Button btnPrevious;
    @FXML Button btnNext;
    @FXML Button btnClose;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("../personaldetails/PersonalDetails.fxml"));
        try {
            fxmlLoader.load();
        } catch (IOException e) {
            e.printStackTrace();
        }
        PersonalDetailsController personalDetailsController = fxmlLoader.getController();
        personalDetailsController.tfFirstName.textProperty().addListener((obs, oldVal, newVal) -> {
            if(newVal.equals("")) {
                btnNext.setDisable(true);
            } else {
                btnNext.setDisable(false);
            }
        });
    }
}

FXML脚本如下:

主要

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

<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane fx:id="apMain" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.yas.registrationwizard.main.MainController">
    <children>
        <ToolBar fx:id="tbMain" layoutX="259.0" layoutY="339.0" prefHeight="40.0" prefWidth="200.0" AnchorPane.bottomAnchor="5.0" AnchorPane.leftAnchor="5.0" AnchorPane.rightAnchor="5.0" AnchorPane.topAnchor="355.0">
            <items>
                <Pane prefHeight="30.0" prefWidth="370.0" />
                <Button fx:id="btnPrevious" maxHeight="25.0" maxWidth="65.0" minHeight="25.0" minWidth="65.0" mnemonicParsing="false" prefHeight="25.0" prefWidth="65.0" text="Previous" />
                <Button fx:id="btnNext" layoutX="10.0" layoutY="13.0" maxHeight="25.0" maxWidth="65.0" minHeight="25.0" minWidth="65.0" mnemonicParsing="false"  prefHeight="25.0" prefWidth="65.0" text="Next" />
                <Button fx:id="btnClose" layoutX="66.0" layoutY="13.0" maxHeight="25.0" maxWidth="65.0" minHeight="25.0" minWidth="65.0" mnemonicParsing="false" prefHeight="25.0" prefWidth="65.0" text="Close" />
            </items>
        </ToolBar>
        <TabPane fx:id="tpMain" layoutX="14.0" layoutY="14.0" prefHeight="335.0" prefWidth="200.0" tabClosingPolicy="UNAVAILABLE" AnchorPane.bottomAnchor="50.0" AnchorPane.leftAnchor="5.0" AnchorPane.rightAnchor="5.0" AnchorPane.topAnchor="5.0">
            <tabs>
                <Tab fx:id="tabPersonalDetails" text="Personal Deatils">
               <content>
                  <fx:include fx:id="apPersonalDetails" source="../personaldetails/PersonalDetails.fxml" />
               </content></Tab>
                <Tab fx:id="tabAddress" text="Address">
               <content>
                  <fx:include fx:id="apAddress" source="../address/Address.fxml" />
               </content></Tab>
            </tabs>
        </TabPane>
    </children>
</AnchorPane>

地址

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

<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane fx:id="apAddress" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="325.0" prefWidth="590.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.yas.registrationwizard.address.AddressController">
   <children>
      <GridPane fx:id="gpAddress" layoutX="195.0" layoutY="103.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
        <columnConstraints>
            <ColumnConstraints hgrow="SOMETIMES" maxWidth="103.0" minWidth="3.0" prefWidth="82.0" />
            <ColumnConstraints hgrow="SOMETIMES" maxWidth="219.0" minWidth="10.0" prefWidth="155.0" />
            <ColumnConstraints hgrow="SOMETIMES" maxWidth="422.0" minWidth="10.0" prefWidth="274.0" />
          <ColumnConstraints hgrow="SOMETIMES" maxWidth="93.0" minWidth="0.0" prefWidth="78.0" />
        </columnConstraints>
        <rowConstraints>
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
          <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
        </rowConstraints>
         <children>
            <Label alignment="CENTER_RIGHT" contentDisplay="RIGHT" prefHeight="17.0" prefWidth="295.0" text="House Name / Number:" GridPane.columnIndex="1" GridPane.rowIndex="2">
               <GridPane.margin>
                  <Insets right="10.0" />
               </GridPane.margin></Label>
            <Label alignment="CENTER_RIGHT" contentDisplay="RIGHT" prefHeight="17.0" prefWidth="246.0" text="Address Line 1:" GridPane.columnIndex="1" GridPane.rowIndex="3">
               <GridPane.margin>
                  <Insets right="10.0" />
               </GridPane.margin></Label>
            <Label alignment="CENTER_RIGHT" contentDisplay="RIGHT" prefHeight="17.0" prefWidth="239.0" text="Address Line 2:" GridPane.columnIndex="1" GridPane.rowIndex="4">
               <GridPane.margin>
                  <Insets right="10.0" />
               </GridPane.margin></Label>
            <Label alignment="CENTER_RIGHT" contentDisplay="RIGHT" prefHeight="17.0" prefWidth="234.0" text="Town / City:" GridPane.columnIndex="1" GridPane.rowIndex="5">
               <GridPane.margin>
                  <Insets right="10.0" />
               </GridPane.margin></Label>
            <Label alignment="CENTER_RIGHT" contentDisplay="RIGHT" prefHeight="17.0" prefWidth="237.0" text="Region / County:" GridPane.columnIndex="1" GridPane.rowIndex="6">
               <GridPane.margin>
                  <Insets right="10.0" />
               </GridPane.margin></Label>
            <TextField fx:id="tfHseNameNum" GridPane.columnIndex="2" GridPane.rowIndex="2" />
            <TextField fx:id="tfAddLine1" GridPane.columnIndex="2" GridPane.rowIndex="3" />
            <TextField fx:id="tfAddLine2" GridPane.columnIndex="2" GridPane.rowIndex="4" />
            <TextField fx:id="tfTownCity" GridPane.columnIndex="2" GridPane.rowIndex="5" />
            <TextField fx:id="tfRegionCounty" GridPane.columnIndex="2" GridPane.rowIndex="6" />
            <Label alignment="CENTER_RIGHT" contentDisplay="RIGHT" prefHeight="17.0" prefWidth="234.0" text="Postcode:" GridPane.columnIndex="1" GridPane.rowIndex="7">
               <GridPane.margin>
                  <Insets right="10.0" />
               </GridPane.margin>
            </Label>
            <TextField fx:id="tfPostcode" GridPane.columnIndex="2" GridPane.rowIndex="7" />
            <Label alignment="CENTER_RIGHT" contentDisplay="RIGHT" prefHeight="17.0" prefWidth="234.0" text="Country:" GridPane.columnIndex="1" GridPane.rowIndex="8">
               <GridPane.margin>
                  <Insets right="10.0" />
               </GridPane.margin>
            </Label>
            <ComboBox fx:id="cboCountry" prefHeight="25.0" prefWidth="294.0" GridPane.columnIndex="2" GridPane.rowIndex="8" />
         </children>
      </GridPane>
   </children>
</AnchorPane>

人物详情

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

<?import javafx.scene.text.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.paint.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>

<AnchorPane fx:id="apPersonalDetails" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="325.0" prefWidth="590.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.yas.registrationwizard.personaldetails.PersonalDetailsController">
   <children>
      <GridPane fx:id="gpPersonalDetails" layoutX="195.0" layoutY="103.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
        <columnConstraints>
            <ColumnConstraints hgrow="SOMETIMES" maxWidth="80.0" minWidth="37.0" prefWidth="37.0" />
            <ColumnConstraints hgrow="SOMETIMES" maxWidth="236.0" minWidth="10.0" prefWidth="236.0" />
            <ColumnConstraints hgrow="SOMETIMES" maxWidth="422.0" minWidth="10.0" prefWidth="277.0" />
          <ColumnConstraints hgrow="SOMETIMES" maxWidth="80.0" minWidth="38.0" prefWidth="41.0" />
        </columnConstraints>
        <rowConstraints>
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
          <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
        </rowConstraints>
         <children>
            <TextField fx:id="tfFirstName" GridPane.columnIndex="2" GridPane.rowIndex="2" />
            <TextField fx:id="tfMidNameInit" GridPane.columnIndex="2" GridPane.rowIndex="3" />
            <TextField fx:id="tfLastName" GridPane.columnIndex="2" GridPane.rowIndex="4" />
            <DatePicker fx:id="dpDoB" prefHeight="25.0" prefWidth="365.0" GridPane.columnIndex="2" GridPane.rowIndex="5" />
            <TextField fx:id="tfNatInsNum" GridPane.columnIndex="2" GridPane.rowIndex="6" />
            <TextFlow fx:id="tflFirstName" prefHeight="16.0" prefWidth="162.0" style="-fx-text-alignment: right;" styleClass="txtFlow" GridPane.columnIndex="1" GridPane.rowIndex="2">
               <GridPane.margin>
                  <Insets right="10.0" top="10.0" />
               </GridPane.margin></TextFlow>
            <TextFlow fx:id="tflLastName" prefHeight="16.0" prefWidth="162.0" style="-fx-text-alignment: right;" styleClass="txtFlow" GridPane.columnIndex="1" GridPane.rowIndex="4">
               <padding>
                  <Insets right="10.0" top="10.0" />
               </padding>
            </TextFlow>
            <TextFlow fx:id="tflDoB" prefHeight="16.0" prefWidth="162.0" style="-fx-text-alignment: right;" styleClass="txtFlow" GridPane.columnIndex="1" GridPane.rowIndex="5">
               <padding>
                  <Insets right="10.0" top="10.0" />
               </padding>
            </TextFlow>
            <TextFlow fx:id="tflNatInsNum" prefHeight="16.0" prefWidth="162.0" style="-fx-text-alignment: right;" styleClass="txtFlow" GridPane.columnIndex="1" GridPane.rowIndex="6">
               <padding>
                  <Insets right="10.0" top="10.0" />
               </padding>
            </TextFlow>
            <TextFlow fx:id="tflMidNameInit" prefHeight="16.0" prefWidth="162.0" style="-fx-text-alignment: right;" styleClass="txtFlow" GridPane.columnIndex="1" GridPane.rowIndex="3">
               <padding>
                  <Insets right="10.0" top="10.0" />
               </padding>
            </TextFlow>
         </children>
      </GridPane>
   </children>
</AnchorPane>

项目的文件夹结构如下图所示:

首先,我对问题中的 "scene" 措辞有点困惑。我相信你在问题中提到的是关于处理节点的,因为所有的 fxml 都是在同一个 Scene/Stage.

中处理的

总之,问题的主要出在MainController的initialize方法上。您正在加载 PersonalDetailsController 的新实例并对其进行处理,而不是处理实际绑定到 MainController 的控制器。

当在 fxml 中包含 fxml 时,子 fxml 的控制器将已经注入到主 fxml 控制器中。所以我相信如下更改 MainController 代码应该会按预期工作。

更新: 抱歉有点误导性的信息。正确的是,您需要使用特定的命名约定注入控制器。如果您使用 fx:include 包含 fxml,要获取控制器,您需要注入命名约定 <fxid>Controller<fxid> 以获取节点引用。

因此,考虑到您的示例,对于给定的 fx:include 行:

<fx:include fx:id="apPersonalDetails" source="../personaldetails/PersonalDetails.fxml" />

您在 MainController 中的代码应该是:

// For controller reference
@FXML PersonalDetailsController apPersonalDetailsController;

// For Node reference
@FXML AnchorPane apPersonalDetails;

所以更新后的代码如下:

import com.yas.registrationwizard.personaldetails.PersonalDetailsController;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.TabPane;
import javafx.scene.control.ToolBar;
import javafx.scene.layout.AnchorPane;

import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;

public class MainController implements Initializable {

    @FXML AnchorPane apMain;
    @FXML ToolBar tbMain;
    @FXML TabPane tpMain;

    @FXML Button btnPrevious;
    @FXML Button btnNext;
    @FXML Button btnClose;

    @FXML PersonalDetailsController apPersonalDetailsController;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        apPersonalDetailsController.tfFirstName.textProperty().addListener((obs, oldVal, newVal) -> {
            if(newVal.equals("")) {
                btnNext.setDisable(true);
            } else {
                btnNext.setDisable(false);
            }
        });
    }
}