如何在 JavaFX 中从 SceneBuilder 访问 UI 组件

Posted

技术标签:

【中文标题】如何在 JavaFX 中从 SceneBuilder 访问 UI 组件【英文标题】:How to access UI components from SceneBuilder in JavaFX 【发布时间】:2015-06-10 08:56:45 【问题描述】:

(重复并已解决 - 请参阅下面的答案)

我在 JavaFX 中迈出了第一步,使用“SceneBuilder”似乎相当困难。我习惯了 android 和 QtCreator。在我看来,访问 UI 组件要容易得多。

类似于findViewById(R.id.btnPushMe);

其实我有一个解决方案,但使用起来很不舒服。这看起来像这样:

FXMLLoader loader = new FXMLLoader(MainApp.class.getResource("../fmxl/main.fxml"));

AnchorPane pane = loader.load();
System.out.println("panechilds:" + pane.getChildren().size());

BorderPane border = (BorderPane) pane.getChildren().get(0);
System.out.println("borderchilds:" + border.getChildren().size());

xml..

<AnchorPane fx:id="mAnchor" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="800.0"
            xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="app.progui.MainController">
    <children>
        <BorderPane layoutX="-1.0" prefHeight="600.0" prefWidth="800.0">
            <top>

               ...

提前致谢 马丁

编辑:

这是一个重复的问题(但我不会删除它,因为我花了一些时间才找到答案 - 可能是因为 JavaFX 没有像 Android 问题那样被问到那么多......)

AnchorPane anchor = (AnchorPane) scene.lookup("#mAnchor");

在这里找到:How to find an element with an ID in JavaFX?

【问题讨论】:

使用 FXML,您将在控制器中为您感兴趣的 UI 元素定义实例字段。在加载控制器类实例期间初始化的那些字段将包含对您希望使用的 GUI 对象的引用。 是的,这是我经常阅读的内容。但我看不出这种“编码风格”有什么优势。像这样编写的代码对我来说看起来很混乱.. :-/ 也许我错了,其他程序员会说这是结构良好,但我对使用 SceneBuilder 调用方法等不太满意.. lookup 方法非常不稳定。查找仅在应用 CSS 后可用,这(通常)是在节点显示之后(有时是一帧之后)。使用控制器方法,或者在最坏的情况下使用FXMLLoader.getNamespace() 【参考方案1】:

您应该使用 controller class 并访问那里的 UI 元素。

基本上你会这样做:

<AnchorPane fx:id="mAnchor" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="800.0"
            xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="app.progui.MainController">
    <children>
        <BorderPane fx:id="border" layoutX="-1.0" prefHeight="600.0" prefWidth="800.0">
            <top>

               ...

然后你可以访问控制器中的fx:id-attributed 元素

package app.progui ;

// ...

public class MainController 

    @FXML
    private BorderPane border ;


    public void initialize() 
        border.setStyle("-fx-background-color: antiquewhite;");
        // ...
    

    // ...

控制器类中的字段名称必须与 FXML 文件中的 fx:id 值匹配。

可以访问调用FXMLLoader 的类中的fx:id 属性元素,但是如果您需要这样做,通常表明您的整体设计是错误的。你可以这样做:

FXMLLoader loader = new FXMLLoader(MainApp.class.getResource("../fmxl/main.fxml"));

AnchorPane pane = loader.load();
Map<String, Object> fxmlNamespace = loader.getNamespace();
BorderPane border = (BorderPane) fxmlNamespace.get("border");

假设上面截断的 FXML 中定义的 fx:id

【讨论】:

【参考方案2】:

当您为 FXML 进行设计时,您通常会设计三件事:应用程序逻辑、GUI 控制器逻辑和 FXML。

您希望访问的 UI 控件的引用由 FXML 加载器在其加载和初始化期间注入到您的控制器类中,因此您无需使用 FindById() 方法。

控制器类看起来类似于:

class DCServRecEditor extends DialogController 


@FXML // ResourceBundle that was given to the FXMLLoader
private ResourceBundle resources;

@FXML // URL location of the FXML file that was given to the FXMLLoader
private URL location;

@FXML // fx:id="ancMatchSelector"
private AnchorPane ancMatchSelector; // Value injected by FXMLLoader

@FXML // fx:id="ancServEditor"
private AnchorPane ancServEditor; // Value injected by FXMLLoader

@FXML // fx:id="ancServRecEditor"
private AnchorPane ancServRecEditor; // Value injected by FXMLLoader
:
:

FXML 加载工具会自动将引用注入到使用@FXML 标记注释的实例字段中。要操作 UI 控件,只需使用适当的引用访问其方法即可。

将 UI 控制逻辑与应用程序逻辑分离是非常可取的,并且会实现“关注点分离”。当您习惯以这种方式设计 FXML UI 时,您会喜欢上它的。

【讨论】:

我知道...@FXML 使该字段可访问,因此它不需要公开。但是,如果我设置了 initialize() 方法,它会被标记出来(在 IntelliJ 中为“unsed”)——这正常吗?您是否知道任何好的教程可以从哪里获取有关“生命周期”或更好的“如何通过 JavaFX 传递对象”的信息?我真的不觉得熟悉。

以上是关于如何在 JavaFX 中从 SceneBuilder 访问 UI 组件的主要内容,如果未能解决你的问题,请参考以下文章

javafx如何在同一个面板界面切换

如何在 JavaFX 中设置占位符?

如何在 IntelliJ IDEA 中创建 JavaFX 模块

如何在 Eclipse 中获取 Javafx 9?

JavaFX概览

如何获取 JavaFX 的版本号?