如何将 FXML 加载到 class 实例中?

How to load FXML in to a class instance?

我需要将 fxml 表单加载到 class 对象并对其进行操作。 可能吗 ?目前我正在尝试这样做:

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

<!-- imports -->
<?import javafx.geometry.Insets ?>
<?import javafx.scene.control.Label ?>
<?import javafx.scene.text.Font ?>
<?import org.bsoftware.parcel.domain.components.LogItem ?>

<!-- layout -->
<LogItem spacing = "3" xmlns:fx = "http://javafx.com/fxml" >
   <padding>
      <Insets bottom = "2" left = "5" right = "5" top = "2" />
   </padding>
   <Label fx:id = "labelTimestamp">
      <font>
         <Font name = "System Bold" size = "11" />
      </font>
   </Label>
   <Label fx:id = "labelMessage">
      <font>
         <Font name = "System Italic" size = "11" />
      </font>
   </Label>
</LogItem>

@Getter
public class LogItem extends HBox
{
    @FXML
    private Label labelTimestamp;

    @FXML
    private Label labelMessage;
}

我正在尝试像这样访问它

final LogItem logItem = FXMLLoader.load(Objects.requireNonNull(LogView.class.getResource("/fxml/components/log_item.fxml")));

但在这里我总是得到 null pionter exeption

logItem.getLabelTimestamp()

使用 fx:root 中记录的结构:

示例应用程序

实施说明:

  • 使用 fx:root 构造 link FXML 加载节点到 Java 对象。
  • 添加 CSS 文件以将样式与布局分开。
  • 应用 MVC 模式,从视图对象 (LogItemView) 中抽象出模型对象 (LogItem)。
  • 在视图中封装视图元素(节点),而不是通过 API.
  • 公开它们
  • 将 LogItem 公开为 LogItemView 的 属性,以便可以直接查询日志项的数据,并在必要时在视图中替换。
  • 为不可变的 read-only LogItem 而不是 Lombok 使用记录。
  • 使用 Instant 表示时间。
  • 使用日期格式化程序将即时格式化为默认时区中的日期字符串。
  • 如果与视图关联的 logitem 属性 发生更改,则使用更改侦听器刷新视图。

module-info.java

module com.example.logdemo {
    requires javafx.controls;
    requires javafx.fxml;

    opens com.example.logdemo to javafx.fxml;
    exports com.example.logdemo;
}

LogApplication.java

package com.example.logdemo;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.io.IOException;
import java.time.Instant;

public class LogApplication extends Application {
    @Override
    public void start(Stage stage) throws IOException {
        LogItemView logItemView = new LogItemView();
        logItemView.setLogItem(
            new LogItem(Instant.now(), "hello, world")
        );

        stage.setScene(new Scene(logItemView));
        stage.show();
    }

    public static void main(String[] args) {
        launch();
    }
}

LogItem.java

package com.example.logdemo;

import java.time.Instant;

public record LogItem(
    Instant timestamp, 
    String message
) {}

LogItemView.java

package com.example.logdemo;

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;

import java.io.IOException;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;

public class LogItemView extends HBox  {
    @FXML
    private Label timestamp;

    @FXML
    private Label message;

    private final ObjectProperty<LogItem> logItem = new SimpleObjectProperty<>();

    private static final DateTimeFormatter formatter =
            DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT)
                    .withZone(ZoneId.systemDefault());

    public LogItemView() throws IOException {
        FXMLLoader fxmlLoader = new FXMLLoader(
            LogItemView.class.getResource(
                "log-item.fxml"
            )
        );
        fxmlLoader.setRoot(this);
        fxmlLoader.setController(this);
        fxmlLoader.load();

        logItem.addListener((observable, oldValue, newValue) -> {
            if (newValue == null) {
                timestamp.setText(null);
                message.setText(null);
            } else {
                timestamp.setText(
                        formatter.format(
                           logItem.getValue().timestamp()
                        )
                );
                message.setText(
                        logItem.getValue().message()
                );
            }
        });
    }

    public LogItem getLogItem() {
        return logItem.get();
    }

    public void setLogItem(LogItem logItem) {
        this.logItem.set(logItem);
    }

    public ObjectProperty<LogItem> logItemProperty() {
        return logItem;
    }
}

log-item.fxml

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

<?import javafx.scene.control.Label ?>
<?import com.example.logdemo.LogItemView?>

<?import java.net.URL?>
<fx:root type="com.example.logdemo.LogItemView" styleClass="log-item" xmlns:fx = "http://javafx.com/fxml">
    <Label fx:id = "timestamp" styleClass="timestamp"/>
    <Label fx:id = "message" styleClass="message"/>
    <stylesheets>
        <URL value="@log-item.css" />
    </stylesheets>
</fx:root>

log-item.css

.log-item {
    -fx-padding: 2px 5px 2px 5px;
    -fx-spacing: 8px;

    -fx-font-family: monospace;
    -fx-font-size: 15px;
}

.log-item > .timestamp {
    -fx-font-weight: bold;
}

.log-item > .message {
    -fx-font-style: italic;
}