Is @FXML needed for every declaration?
Asked Answered
P

3

22

Is @FXML needed for every declaration or just for the first?

In other words, should I use

@FXML
public Label timerLabel = new Label();
@FXML
public TextField mainTextField, projectTextField ;
@FXML
public Button goButton, deleteAllButton ;
@FXML
public ComboBox<String> projectComboBox ;
@FXML
public TableView<Entry> mainTable ;
@FXML
public TableColumn<Entry, String> titleColumn, timeColumn, dateColumn ;
@FXML
public TableColumn<Entry, Boolean> checkColumn, buttonColumn ;
@FXML
public checkBox checkAllCheckBox ;

Or

@FXML
public Label timerLabel = new Label();
public TextField mainTextField, projectTextField ;
public Button goButton, deleteAllButton ;
public ComboBox<String> projectComboBox ;
public TableView<Entry> mainTable ;
public TableColumn<Entry, String> titleColumn, timeColumn, dateColumn ;
public TableColumn<Entry, Boolean> checkColumn, buttonColumn ;
public checkBox checkAllCheckBox ;

Thank you!

Perturbation answered 13/5, 2015 at 9:1 Comment(10)
Tryout both of them ;)Touchstone
I can't see any differences :|Perturbation
I never seen the second solution. I think it's not possible. just tryBedrock
@Perturbation Have you tried using them? ;)Touchstone
@Perturbation Just to point out, your statement public Label timerLabel = new Label(); annotated by @FXML is incorrect. The references annotated with @FXML are initialized at the time of fxml load and should not be initialized externally.Touchstone
I know it's a stupid question... I have already used them. I was just wondering if there are any syntactic differencesPerturbation
Should I initialize timerLabel in initialize(URL location, ResourceBundle resources)?Perturbation
What do you mean by "initialize timerLabel"? You should never write timerLabel = new TimerLabel() if the timerLabel reference definition was annotated with @FXML.Solangesolano
You don't actually need any @FXML annotations if your fields are public. Of course, you should never make these fields public anyway; you should make them private, in which case all the @FXML annotations are required. But with the code as it is, omitting the annotations will make no difference.Bowel
I think it is time to FXMLLoader to log error or warn if the @FXML annotated field is already instantiated while loading. Or use instantiated one as in setController().Saltarello
B
56

The @FXML annotation enables an FXMLLoader to inject values defined in an FXML file into references in the controller class. In other words, if you annotate your timerLabel with @FXML, then it will be initialized by the FXMLLoader when the load() method is called by an element in the FXML file with fx:id="timerLabel". As others have pointed out in the comments, this means you should never write code like

@FXML
private Label timerLabel = new Label();

Here timerLabel will first be initialized to the new Label(); you create in the code, and will then almost immediately be re-initialized to the value defined in the FXML file. This is at best redundant, and at worst misleading. If you don't correctly match the variable names to the fx:id, your variable will be referring to the wrong Label and the error will be very difficult to track down.

To get to your actual question:

When the FXMLLoader loads the FXML file, it will attempt to inject any elements that have an fx:id attribute into the controller. It will look for

  1. Any public field with a variable name matching the fx:id attribute, or
  2. Any field (public or not) with a variable name matching the fx:id attribute that is annotated with @FXML.

So in your example, since all your fields are public, you can omit all the @FXML annotations (even the first) and it will still work.

However, if you follow good practice and make your fields private, then each declaration must be annotated @FXML for the injection to work.

So

@FXML
private Label timerLabel;
@FXML
private TextField mainTextField;

etc will work, but

@FXML
private Label timerLabel;
private TextField mainTextField;

will not.

Bowel answered 13/5, 2015 at 11:9 Comment(2)
Is injection required? Is there a way to just ask the loader for the control I'm interested in (by fx:id)?Instructive
Not sure I understand that question. Isn't that exactly what injection does?Bowel
H
8

for each

fx:id="somename"

you need a

@FXML
public SomeClass somename;

I prefer writing it in one line, because it's easier to read when there are many

@FXML public SomeClass somename;

without initializing

@FXML
public Label timerLabel = new Label(); // this is wrong
Hybris answered 13/5, 2015 at 11:5 Comment(2)
won't timerLabel = new Label(); be overridden by an FXMLLoader ?Terrorist
This answer is misleading, since @FXML isn't needed when the field is public. So public SomeClass somename; without @FXML does also work, but you need it when somename isn't public for example @FXML private SomeClass somename;.Pillage
F
0
@FXML
private TextField idTextField;

@FXML
private TextField passwordTextField;

OR

@FXML
private TextField idTextField, passwordTextField;
Fornof answered 7/7, 2019 at 9:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.