首页  >  文章  >  如何正确继承 FXML 带注释的属性以使其在子类中可用?

如何正确继承 FXML 带注释的属性以使其在子类中可用?

WBOY
WBOY转载
2024-02-22 13:46:14713浏览

php小编小新为您带来本期的Java问答:如何正确继承FXML带注释的属性以使其在子类中可用?在Java开发中,正确继承FXML带注释的属性是一个常见问题,也是开发过程中需要注意的地方。下面我们将详细讨论如何正确继承带注释的属性,使其在子类中可用,以帮助您更好地解决这一问题。

问题内容

问题

我正在尝试通过控制器区域网络实现消息传输,其中消息是通过使用 javafx 创建的 gui 根据用户输入构建的。

我有一个链接到 main.fxml 的 maincontroller 类。在 maincontroller 中,我定义了一个带 fxml 注释的 textfield 属性 in_desiredvelocity,该属性正确链接到 main.fxml 中的 fx:id

然后我定义了一个抽象类 canmessage,它定义了必须通过网络发送的消息的主干。

现在类 pctovcumessage 实现了特定类型的 canmessage。为了能够访问 fxml 属性(在 maincontroller 中定义),我决定抽象类 canmessage 扩展 maincontroller,而 pctovcumessage 扩展 canmessage

应用程序编译正确,但当我在 gui 中输入时,将启动 textfield in_desiredvelocity nullpointerexception

问题

尽管上述 fxml 属性是由 pctovcumessage 继承的(它继承自抽象类 canmessage 并且扩展了 maincontroller),但我如何在此类中使用它来实现我的目标?

主要

package canbusgui;

import javafx.application.application;
import javafx.fxml.fxmlloader;
import javafx.scene.scene;
import javafx.stage.stage;

import java.io.ioexception;

public class mainapplication extends application {
    public static stage stage = null;

    @override
    public void start(stage stage) throws ioexception {
        
        stage.setoncloserequest(event -> {
           system.exit(0);
        });

        mainapplication.stage = stage;

        // create a fxmlloader to load the fxml file that defines the user interface
        fxmlloader fxmlloader = new fxmlloader(mainapplication.class.getresource("mainview.fxml"));

        scene scene = new scene(fxmlloader.load());

        stage.settitle("canbus gui");
        stage.setscene(scene);
        stage.setresizable(false);
        stage.setminheight(768);
        stage.setminwidth(1366);
        stage.show();
    }

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

主控制器

package canbusgui;

import javafx.application.platform;
import javafx.collections.fxcollections;
import javafx.fxml.fxml;
import javafx.scene.input.keycode;
import javafx.scene.input.keyevent;


public class mainviewcontroller {
  @fxml
  protected textfield in_desiredvelocity;

  @fxml
  public void initialize (){

        in_desiredvelocity.addeventfilter(keyevent.key_pressed, event -> {
                if (event.getcode() == keycode.enter) {
                    try {
                        sendmessage(new pctovcumessage("222"));
                    }
                    catch (exception e) {
                        throw new runtimeexception(e);
                    }
                }
        });
  }
  

  public void sendmessage(canmessage message) throws exception {
        
        message.constructdata();
       
        message.validateinputs();
        
        byte[] data = message.getdata();

        // send the data array to the can bus
        canbuscontroller.sendcommand(hexformat.fromhexdigits(message.getid()), data);
  }

}

canmessage.java(它包含一个抽象类 canmessagepctovcumessage 扩展它):

package canbusgui;

import static java.lang.Integer.parseInt;

public abstract class canMessage extends MainViewController{

    // Declare common attributes
    protected String id;
    protected byte[] data;

    public canMessage(String id) {
        this.id = id;
        // Initialize an empty byte array for data
        this.data = new byte[8];
    }


    // Define an abstract method to construct the data array
    public abstract void constructData();

    // Define an abstract method to validate the inputs
    public abstract void validateInputs() throws Exception;

    // Define a getter method for the data array
    public byte[] getData() {
        return this.data;
    }

    public String getId() {
        return this.id;
    }

}


// Define a subclass for PC_to_VCUMessage message
class PcToVcuMessage extends canMessage {


    public PcToVcuMessage(String id) {
        // Call the superclass constructor
        super(id);
    }


    // Override the constructData method
    @Override
    public void constructData() {


        data[0] = (byte) 0;
        data[1] = (byte) 0;
        data[2] = (byte) 0;
        data[3] = (byte) parseInt(in_desiredVelocity.getText()); //HERE in_desiredVelocity is null and a NillPointerException is launched
        data[4] = (byte) 0;
        data[5] = (byte) 0;
        data[6] = (byte) 0;
        data[7] = (byte) 0;
    }

    public  void validateInputs() throws Exception{}


}

编辑

can 报文的格式如下:id(hex), data0, data1, data2, data3, ......, data7。因此,当我在控制器中调用 pcutovcumessage 的构造函数时,我传递消息 222 的 id(顺便说一句,该 id 在设备的数据表中指定)

pcutovcumessage 中,我需要访问 fxml 属性 in_desiredvelocity,该属性已由用户通过在 gui 的 textfield 中键入值来设置:通过这种方式,可以检索用户键入的值以构建消息。

编辑2

由于可以有多个具有不同id的消息,所以我想到了在控制器中的sendmessage方法中使用多态性。此外,可能存在需要从控制器类访问多个 fxml 属性的消息。

解决方法

这根本不是继承的作用。继承是之间的关系,而不是对象之间的关系。

当你这样做时

public class mainviewcontroller {
    // ...
    protected textfield indesiredvelocity;
    // ...
}

这意味着 mainviewcontroller 的每个实例都会有一个名为 indesiredvelocity 的字段,其类型为 textfield

当你这样做时

public abstract class canmessage extends mainviewcontroller {
    // ...
}

这意味着 canmessage 的每个实例也是 mainviewcontroller 的实例。

加载 fxml 时,fxmlloader 会创建 mainviewcontroller 的实例(因为 fxml 中有 fx:controller="canbusgui.mainviewcontroller"),并在该实例中初始化 indesiredvelocity 字段对 fxml 中声明的文本字段的引用。

稍后在你的控制器中,你会这样做

new pctovcumessage("222")

当然,这会创建一个新的 pctovcumessage 实例,其 id 为 "222"。由于 pctovcumessage 继承自 canmessage,因此该新实例也是 canmessage 的实例,并且由于 canmessage 继承自 mainviewcontroller,因此该实例也是 mainviewcontrollerzqbendczq 的实例b,由于 <code>mainviewcontroller 的每个实例都有一个字段 indesiredvelocity,因此 pctovcumessage 的这个新实例有一个名为 indesiredvelocity 的字段,类型为 textfield

但是,您永远不会初始化该字段(并且没有明智的方法这样做),因此 pctovcumessage 中的 indesiredvelocity 字段为 null。

这样做没有任何意义。我真的不明白你的域模型是什么(我可能不需要回答这个问题),但是对于 textfield 作为类型为某种消息的对象的一部分没有任何意义.

相反,将此消息发送的数据作为 pctovcumessage 的一部分可能是有意义的。 ie。你可以做

class pctovcumessage extends canmessage {

    private int desiredvelocity ;


    public pctovcumessage(string id, int desiredvelocity) {
        // call the superclass constructor
        super(id);
        this.desiredvelocity = desiredvelocity;
    }


    // override the constructdata method
    @override
    public void constructdata() {


        data[0] = (byte) 0;
        data[1] = (byte) 0;
        data[2] = (byte) 0;
        data[3] = (byte) desiredvelocity;
        data[4] = (byte) 0;
        data[5] = (byte) 0;
        data[6] = (byte) 0;
        data[7] = (byte) 0;
    }

    public  void validateinputs() throws exception{}


}

并在控制器中将 new pctovcumessage(&quot;222&quot;) 替换为

new PcToVcuMessage("222", Integer.parseInt(inDesiredVelocity.getText()))

然后只需从 canmessage 类中删除 extends mainviewcontroller 即可。这显然完全没有意义(消息不是控制 ui 的东西)。

一些与您的代码无关的问题:

  1. 不要使用文本字段注册按键处理程序。要处理用户按 enter 的操作,请以通常的方式使用操作处理程序。
  2. 适当地命名类和变量。类名称应该是名词(它们代表事物)。 canmessage 是一个动词(或动词短语)。可能 message 更合适,但我还是不太明白你在这里建模的内容。

以上是如何正确继承 FXML 带注释的属性以使其在子类中可用?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文转载于:stackoverflow.com。如有侵权,请联系admin@php.cn删除