JavaFX Node.lookup()仅对于使用FXMLLoader加载的Parent中的某些元素返回null [英] JavaFX Node.lookup() returning null only for some elements in Parent loaded with FXMLLoader

查看:250
本文介绍了JavaFX Node.lookup()仅对于使用FXMLLoader加载的Parent中的某些元素返回null的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我从FXML加载了一个Parent,将它添加到场景/舞台中的一个窗格并显示它,然后立即查找组件。 lookup()为某些人返回null,但对其他人返回非null。在什么情况下它会这样做?

I've loaded a Parent from FXML, added it to a Pane within a scene/stage and shown it, then immediately afterwards I lookup components. lookup() returns null for some but non-null for others. Under what circumstances would it do that?

这是加载和查找代码:

    rootUi = FXMLLoader.load(getClass().getResource("PracticeScreen.fxml"));
    // added to Parent within stage and setVisible(true)
    analysisGroup = (Pane)rootUi.lookup("#analysisGroup");       // null
    stickiesPane = (Pane)rootUi.lookup("#stickiesPane");         // null
    scoreScroll = (ScrollPane)rootUi.lookup("#scoreScrollPane"); // GOOD
    tintLayer = rootUi.lookup("#tintLayer");                     // GOOD
    scoreImageView = (ImageView)rootUi.lookup("#scoreImage");    // null
    StackPane scoreRenderStack = (StackPane)rootUi.lookup("#scoreRenderStack"); // null
    StackPane scoreScrollStack = (StackPane)rootUi.lookup("#scoreScrollStack"); // null

scoreScrollPane返回OK,但随后所有子节点都返回null。

scoreScrollPane comes back OK, but then all of its children come back null.

装入FXML:

  <?import javafx.geometry.Insets?>
  <?import javafx.scene.control.Label?>
  <?import javafx.scene.control.ScrollPane?>
  <?import javafx.scene.control.ToggleButton?>
  <?import javafx.scene.effect.DropShadow?>
  <?import javafx.scene.effect.Glow?>
  <?import javafx.scene.image.ImageView?>
  <?import javafx.scene.layout.*?>
  <?import javafx.scene.shape.Rectangle?>
  <?import javafx.scene.text.Font?>
  <BorderPane style="-fx-background-color: white;" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1">
     <center>
        <StackPane id="scoreScreenStack" style="-fx-background-color: blue;" BorderPane.alignment="CENTER">
           <children>
              <ScrollPane id="scoreScrollPane" fitToHeight="true" hbarPolicy="ALWAYS" vbarPolicy="NEVER">
                 <content>
                    <StackPane id="scoreScrollStack">
                       <children>
                          <StackPane id="scoreRenderStack" alignment="CENTER_LEFT" StackPane.alignment="CENTER_LEFT">
                             <children>
                                <ImageView id="scoreImage" pickOnBounds="true" preserveRatio="true" StackPane.alignment="CENTER_LEFT" />
                                <Pane id="analysisGroup" />
                                <Pane id="stickiesPane" minHeight="200.0" minWidth="200.0" />
                                <Rectangle id="playbackCursor" arcHeight="5.0" arcWidth="5.0" fill="DODGERBLUE" height="150.0" stroke="BLACK" strokeType="INSIDE" strokeWidth="0.0" visible="false" width="2.0">
                                   <effect>
                                      <DropShadow color="DODGERBLUE" />
                                   </effect>
                                </Rectangle>
                             </children>
                          </StackPane>
                       </children>
                    </StackPane>
                 </content>
              </ScrollPane>
              <BorderPane pickOnBounds="false">
                 <top>
                    <StackPane BorderPane.alignment="CENTER">
                       <children>
                          <BorderPane>
                             <left>
                                <Label id="recordingIndicator" text="Listening..." textFill="#00a7ff" BorderPane.alignment="CENTER">
                                   <font>
                                      <Font size="18.0" />
                                   </font>
                                   <effect>
                                      <Glow level="0.86" />
                                   </effect>
                                   <BorderPane.margin>
                                      <Insets />
                                   </BorderPane.margin>
                                   <padding>
                                      <Insets bottom="8.0" left="8.0" right="8.0" top="8.0" />
                                   </padding>
                                </Label>
                             </left>
                             <right>
                                <HBox BorderPane.alignment="CENTER">
                                   <children>
                                      <ToggleButton id="finalPerformance" mnemonicParsing="false" text="Final Performance" />
                                   </children>
                                   <BorderPane.margin>
                                      <Insets bottom="8.0" left="8.0" right="8.0" top="8.0" />
                                   </BorderPane.margin>
                                </HBox>
                             </right>
                          </BorderPane>
                       </children>
                    </StackPane>
                 </top>
              </BorderPane>
              <Pane id="tintLayer" opacity="0.0" pickOnBounds="false" style="-fx-background-color: #00a7ff;" visible="false" />
           </children>
        </StackPane>
     </center>
  </BorderPane>


推荐答案

在应用CSS之前,不保证查找工作有效到了现场。这通常发生在第一次布局过程中(即第一次将场景图渲染到屏幕上),并且在某些情况下甚至可能在此之后发生。查找通常不推荐作为获取您在场景图中定义的节点的机制。

Lookups are not guaranteed to work until CSS has been applied to the scene. This typically happens on the first layout pass (i.e. the first time the scene graph is rendered to the screen), and in some cases may even happen later than that. Lookups are generally not recommended as a mechanism to get nodes you have defined in the scene graph.

引用FXML中定义的控件的推荐方法是使用控制器类。将FXML中的所有 id 属性更改为 fx:id 属性,并将根控件类属性添加到根元素:

The recommended way to reference controls defined in FXML is to use a controller class. Change all your id attributes in the FXML to fx:id attributes, and add a controller class attribute to the root element:

<BorderPane style="-fx-background-color: white;" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1"
    fx:controller="com.my.company.PracticeScreenController">
     <center>
        <StackPane fx:id="scoreScreenStack" style="-fx-background-color: blue;" BorderPane.alignment="CENTER">
           <children>
              <ScrollPane fx:id="scoreScrollPane" fitToHeight="true" hbarPolicy="ALWAYS" vbarPolicy="NEVER">
                 <content>
                    <StackPane fx:id="scoreScrollStack">

                        <!-- etc -->

                    </StackPane>
                 </content>
              </ScrollPane>
           </children>
        </StackPane>
    </center>
</BorderPane>

现在定义一个控制器类,其中包含相应的 @FXML - 注释字段。您可以在 initialize()方法中访问这些字段(注意在调用构造函数时它们不会被初始化):

Now define a controller class with corresponding @FXML-annotated fields. You can access those fields in the initialize() method (note they will not have been initialized when the constructor is called):

package com.my.company ;

// imports...

public class PracticeScreenController {

    @FXML
    private StackPane scoreScreenStack ;
    @FXML
    private ScrollPane scoreScrollPane ;
    @FXML
    private ScrollPane scoreScrollStack ;

    // etc...

    public void initialize() {
        // configure controls here, as needed...
    }
}

如果迫切需要从FXML文件中检索对FXML文件中定义的节点的引用加载FXML文件的位置,而不是在控制器中,您可以通过 FXMLLoader 的命名空间来完成。同样,我应该强调这是不是推荐的方法,你应该使用控制器类来访问它们,但这确实提供了另一种解决方案。

If there is some pressing need to retrieve references to nodes defined in the FXML file from the point where the FXML file is loaded, instead of in the controller, you can do so via the FXMLLoader's namespace. Again, I should emphasize that this is not the recommended approach, and you should really use a controller class to access these, but this does provide another solution.

使用上面FXML中显示的相同 fx:id 属性,您可以这样做:

Using the same fx:id attributes shown in the FXML above, you can do:

FXMLLoader loader =  new FXMLLoader(getClass().getResource("PracticeScreen.fxml"));
rootUi = loader.load();

Map<String, Object> namespace = loader.getNamespace();

// added to Parent within stage and setVisible(true)
analysisGroup = (Pane)namespace.get("analysisGroup");
stickiesPane = (Pane)namespace.get("stickiesPane");
scoreScroll = (ScrollPane)namespace.get("scoreScrollPane"); 
tintLayer = (Pane)namespace.get("tintLayer");                     
scoreImageView = (ImageView)namespace.get("scoreImage");
StackPane scoreRenderStack = (StackPane)namespace.get("scoreRenderStack");
StackPane scoreScrollStack = (StackPane)namespace.get("scoreScrollStack");

这篇关于JavaFX Node.lookup()仅对于使用FXMLLoader加载的Parent中的某些元素返回null的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆