嵌入式 fxml 上的 JavaFX-8 setRoot 导致光标闪烁和内存/cpu 资源问题

JavaFX-8 setRoot on embedded fxml causes cursor flickering and memory / cpu resource issues

我想在 JavaFX 中构建向导式应用程序。因此,我有一个带有导航按钮的 wizard.fxml 和每个 step/task 的空 AnchorPane,它们分别位于单独的 fxml 文件中,以便在运行时将它们嵌入到(主)向导中。

现在,当我想在 WizardController 中调用第一步时:

FXMLLoader loader = SpringFXMLLoader.getLoader(this.getClass().getClassLoader().getResource("logon.fxml"));  //creates a loader with the current application context
loader.setController(this);
loader.setRoot(this.taskPane /*The AnchorPane*/);
loader.load();

它按预期加载但我遇到了这个问题:现在每当我将鼠标悬停在按钮或 TextField 之类的东西上时,光标开始在 "hand"-光标和 "default"- 之间闪烁光标。 wizard.fxml 中的按钮闪烁但仍在工作,但我无法单击 and/or 在嵌入式 logon.fxml 的文本字段中键入内容。我想这可能与重叠对象有关,所以我为每个节点禁用了 PickOnBounds 但问题仍然存在。另外运行程序非常消耗CPU和RAM资源,我什至无法流畅地拖动程序windows。

使用此代码(logon.fxml 中没有 fx:root):

FXMLLoader loader = SpringFXMLLoader.getLoader(this.getClass().getClassLoader().getResource("logon.fxml"));  //creates a loader with the current application context
loader.setController(this);
Node task = loader.load();
taskPane.getChildren().clear();
taskPane.getChildren().add(task);
AnchorPane.setTopAnchor(task, 0d);
AnchorPane.setRightAnchor(task, 0d);
AnchorPane.setBottomAnchor(task, 0d);
AnchorPane.setLeftAnchor(task, 0d);

给了我完全相同的输出和问题。当我注释掉单行 loader.load(); 时,问题没有出现,但显然我需要加载。

wizard.fxml(无导入)

<BorderPane stylesheets="@application.css" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1" fx:controller="path.to.my.controller.WizardController">
   <bottom>
      <ButtonBar id="buttonBar" BorderPane.alignment="CENTER">
        <buttons>
          <Button id="btnPrevious" alignment="CENTER" contentDisplay="CENTER" mnemonicParsing="false" pickOnBounds="false" text="&lt; Zurück" />
            <Button id="btnNext" alignment="CENTER" contentDisplay="CENTER" defaultButton="true" mnemonicParsing="false" pickOnBounds="false" text="Weiter &gt;" />
            <Button id="btnFinish" alignment="CENTER" contentDisplay="CENTER" mnemonicParsing="false" pickOnBounds="false" text="Fertigstellen" />
            <Button id="btnCancel" alignment="CENTER" cancelButton="true" contentDisplay="CENTER" mnemonicParsing="false" pickOnBounds="false" text="Abbrechen" />
        </buttons>
      </ButtonBar>
   </bottom>
   <center>
      <AnchorPane fx:id="taskPane" pickOnBounds="false" BorderPane.alignment="CENTER" />
   </center>
</BorderPane>

logon.fxml(含fx:root)

<fx:root type="AnchorPane" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <TitledPane alignment="TOP_LEFT" animated="false" collapsible="false" contentDisplay="CENTER" pickOnBounds="false" styleClass="taskPane" stylesheets="@application.css" text="Logon" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
         <font>
            <Font name="System Bold" size="18.0" />
         </font>
         <content>
            <GridPane maxHeight="150.0" maxWidth="250.0" pickOnBounds="false" styleClass="inputGrid">
              <columnConstraints>
                <ColumnConstraints hgrow="SOMETIMES" maxWidth="94.0" minWidth="10.0" prefWidth="58.0" />
                <ColumnConstraints hgrow="SOMETIMES" maxWidth="142.0" minWidth="10.0" prefWidth="140.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>
               <children>
                  <Label pickOnBounds="false" text="Mandant" />
                  <Label pickOnBounds="false" text="Benutzer" GridPane.rowIndex="1" />
                  <Label pickOnBounds="false" text="Kennwort" GridPane.rowIndex="2" />
                  <TextField id="fldMandant" fx:id="fldMandant" pickOnBounds="false" GridPane.columnIndex="1" />
                  <TextField fx:id="fldBenutzer" pickOnBounds="false" prefWidth="110.0" GridPane.columnIndex="1" GridPane.rowIndex="1" />
                  <TextField fx:id="fldKennwort" pickOnBounds="false" GridPane.columnIndex="1" GridPane.rowIndex="2" />
               </children>
            </GridPane>
         </content>
      </TitledPane>
   </children>
</fx:root>

好的,所以这个问题是偶然的 recursion/loop。我执行的从 FXML 加载节点的代码在 initialize(URL, ResourceBundle) 方法中。现在,将新加载的 fxml 的控制器设置为 相同的 控制器对象,从创建它的地方 (loader.setController(this);) 导致 initialize(URL, ResourceBundle)-method 运行 并因此再次加载相同的 fxml 。这永远不会停止。

我的解决方案是删除 loader.setController(this); 调用并(更重要的是)将 fxml 本身中的控制器设置为某个 other 控制器。为了保持控制器之间的连接,我创建了一个名为 SubController 的接口。所有代表 step/task 而不是向导本身的控制器都实现了它。该接口指定了我要转发给 SubController 的四个 onButtonClick 方法。事件的实际处理现在发生在 SubController 中。

@FXML
void onCancel(ActionEvent event)
{
    this.currentSub.onCancel(event);
}

@FXML
void onFinish(ActionEvent event)
{
    this.currentSub.onFinish(event);
}

@FXML
void onNext(ActionEvent event)
{
    this.currentSub.onNext(event);
}

@FXML
void onPrevious(ActionEvent event)
{
    this.currentSub.onPrevious(event);
}