php editor Xiaoxin brings you this issue of Java Q&A: How to correctly inherit FXML annotated properties to make them available in subclasses? In Java development, correctly inheriting FXML annotated properties is a common problem and something that needs attention during the development process. Below we will discuss in detail how to correctly inherit annotated properties and make them available in subclasses to help you better solve this problem.
Question
I'm trying to implement message transfer over a controller area network, where the messages are built based on user input through a gui created using javafx.
I have a maincontroller
class linked to main.fxml. In maincontroller
I have defined a textfield attribute with fxml annotation in_desiredvelocity
which is properly linked to fx:id
in main.fxml.
I then defined an abstract class canmessage
which defines the backbone of messages that must be sent over the network.
Now class pctovcumessage
implements a specific type of canmessage. To be able to access the fxml properties (defined in maincontroller
) I decided that the abstract class canmessage
extends maincontroller
and pctovcumessage
extends canmessage
.
The application compiles correctly but when I type in the gui the textfield in_desiredvelocity
nullpointerexception
is launched.
question
Although the above fxml properties are inherited by pctovcumessage
(which inherits from the abstract class canmessage
and extends maincontroller
), how do I add it in this class Use it to achieve my goals?
main:
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(); } }
main controller:
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 (it contains an abstract class canmessage
and pctovcumessage
extends it):
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{} }
edit
The format of the can message is as follows: id(hex), data0, data1, data2, data3, ..., data7. So when I call the constructor of pcutovcumessage
in the controller I pass the id of message 222 (which by the way is specified in the device's datasheet)
In pcutovcumessage
I need to access the fxml property in_desiredvelocity
which has been set by the user by typing the value in the textfield of the gui: In this way the user can be retrieved Value typed to build the message.
Edit 2
Since there can be multiple messages with different ids, I thought of using polymorphism in the sendmessage method in the controller. Additionally, there may be messages that require access to multiple fxml properties from the controller class.
This is not the role of inheritance at all. Inheritance is a relationship between classes, not between objects.
When you do this
public class mainviewcontroller { // ... protected textfield indesiredvelocity; // ... }
This means that every instance of mainviewcontroller
will have a field named indesiredvelocity
of type textfield
.
When you do this
public abstract class canmessage extends mainviewcontroller { // ... }
This means that every instance of canmessage
is also an instance of mainviewcontroller
.
When loading fxml, fxmlloader
will create an instance of mainviewcontroller
(because there is fx:controller="canbusgui.mainviewcontroller"
in fxml), and in the The indesiredvelocity
field initialized in the instance is a reference to the text field declared in fxml.
Later in your controller you will do this
new pctovcumessage("222")
Of course, this will create a new pctovcumessage
instance with the id "222"
. Since pctovcumessage
inherits from canmessage
, this new instance is also an instance of canmessage
, and since canmessage
inherits from mainviewcontroller
, so this instance is also an instance b of mainviewcontrollerzqbendczq, since each instance of <code>mainviewcontroller
has a field indesiredvelocity
, so this new instance of pctovcumessage
There is a field named indesiredvelocity
, of type textfield
.
However, you never initialize the field (and there is no sensible way to do so), so the indesiredvelocity
field in pctovcumessage
is null.
It makes no sense to do so. I don't really understand what your domain model is (I probably don't need to answer this question), but it doesn't make any sense for textfield
to be part of an object of type some kind of message.
Instead, it might make sense to send the data with this message as part of the pctovcumessage
. ie. you can do
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{} }
And replace new pctovcumessage("222")
in the controller with
new PcToVcuMessage("222", Integer.parseInt(inDesiredVelocity.getText()))
然后只需从 canmessage
类中删除 extends mainviewcontroller
即可。这显然完全没有意义(消息不是控制 ui 的东西)。
一些与您的代码无关的问题:
canmessage
是一个动词(或动词短语)。可能 message
更合适,但我还是不太明白你在这里建模的内容。The above is the detailed content of How to properly inherit FXML annotated properties to make them available in subclasses?. For more information, please follow other related articles on the PHP Chinese website!