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!

James_D
  • 201,275
  • 16
  • 291
  • 322
Romeo
  • 311
  • 1
  • 2
  • 9
  • 3
    Tryout both of them ;) – ItachiUchiha May 13 '15 at 09:04
  • I can't see any differences :| – Romeo May 13 '15 at 09:13
  • I never seen the second solution. I think it's not possible. just try – agonist_ May 13 '15 at 09:14
  • @Romeo Have you tried using them? ;) – ItachiUchiha May 13 '15 at 09:22
  • 6
    @Romeo 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. – ItachiUchiha May 13 '15 at 09:36
  • I know it's a stupid question... I have already used them. I was just wondering if there are any syntactic differences – Romeo May 13 '15 at 09:36
  • Should I initialize timerLabel in initialize(URL location, ResourceBundle resources)? – Romeo May 13 '15 at 09:38
  • 5
    What do you mean by "initialize timerLabel"? You should never write `timerLabel = new TimerLabel()` if the timerLabel reference definition was annotated with `@FXML`. – jewelsea May 13 '15 at 09:42
  • 3
    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. – James_D May 13 '15 at 11:13
  • 2
    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(). – Uluk Biy May 13 '15 at 11:22

3 Answers3

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.

Pablo Fernandez
  • 279,434
  • 135
  • 377
  • 622
James_D
  • 201,275
  • 16
  • 291
  • 322
  • Is injection required? Is there a way to just ask the loader for the control I'm interested in (by fx:id)? – Joel May 31 '16 at 23:24
  • 1
    Not sure I understand that question. Isn't that exactly what injection does? – James_D May 31 '16 at 23:26
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
hanbin615
  • 575
  • 1
  • 5
  • 13
  • 1
    won't `timerLabel = new Label();` be overridden by an `FXMLLoader `? – Andrew Tobilko Sep 07 '17 at 11:19
  • 2
    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;`. –  Apr 27 '18 at 10:43
0
@FXML
private TextField idTextField;

@FXML
private TextField passwordTextField;

OR

@FXML
private TextField idTextField, passwordTextField;
UMEGS Hamza
  • 23
  • 1
  • 7