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,由于 <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("222")
替换为
new PcToVcuMessage("222", Integer.parseInt(inDesiredVelocity.getText()))
然后只需从 canmessage
类中删除 extends mainviewcontroller
即可。这显然完全没有意义(消息不是控制 ui 的东西)。
一些与您的代码无关的问题:
canmessage
是一个动词(或动词短语)。可能 message
更合适,但我还是不太明白你在这里建模的内容。以上是如何正确继承 FXML 带注释的属性以使其在子类中可用?的详细内容。更多信息请关注PHP中文网其他相关文章!