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(它包含一个抽象类 canmessage 和 pctovcumessage 扩展它):
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,由于 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("222") 替换为
new PcToVcuMessage("222", Integer.parseInt(inDesiredVelocity.getText()))
然后只需从 canmessage 类中删除 extends mainviewcontroller 即可。这显然完全没有意义(消息不是控制 ui 的东西)。
一些与您的代码无关的问题:
- 不要使用文本字段注册按键处理程序。要处理用户按 enter 的操作,请以通常的方式使用操作处理程序。
- 适当地命名类和变量。类名称应该是名词(它们代表事物)。
canmessage是一个动词(或动词短语)。可能message更合适,但我还是不太明白你在这里建模的内容。










