fangio
fangio

Reputation: 1796

Component constructor arguments fxml javafx

First, I give you the code I have.

COMPONENT

public class Schuiver extends VBox{

private final SchuiverCompanion companion;

public Schuiver(String text) {
    try {
        FXMLLoader loader = new FXMLLoader(
                Schuiver.class.getResource("nuleenschuiver.fxml"));
        loader.setRoot(this);
        this.companion = new SchuiverCompanion();
        loader.setController(companion);
        companion.setText(text);

        loader.load();
    } catch (IOException exception) {
        throw new RuntimeException(exception);
    }

  }
}

COMPONENTCONTROLLER

public class SchuiverCompanion {

   public TextField kleurveld;
   public Label titel;
   public Slider schuiver;

   public void initialize() {
        kleurveld.textProperty().bindBidirectional(schuiver.valueProperty(),
            new NumberStringConverter());
   }

   public void setText(String text){
       titel.setText(text);
   }

}

COMPONENTFXML

 <?xml version="1.0" encoding="UTF-8"?>

 <?import javafx.geometry.*?>
 <?import javafx.scene.control.*?>
 <?import java.lang.*?>
 <?import javafx.scene.layout.*?>

 <fx:root fx:id="vbox" minHeight="-1.0" prefHeight="-1.0" prefWidth="-1.0" spacing="5.0" type="javafx.scene.layout.VBox" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="kleurenkiezer.SchuiverCompanion">
  <children>
  <Label fx:id="titel" alignment="TOP_LEFT" text="Hier een titel" />
  <HBox prefHeight="44.0" prefWidth="299.0">
     <children>
        <Slider fx:id="schuiver" prefHeight="14.0" prefWidth="215.0" />
        <TextField fx:id="kleurveld" prefHeight="25.0" prefWidth="76.0" />
     </children>
  </HBox>
  </children>
  </fx:root>

Like you see my Component asks a String that will be placed in a Label, the problem is that you can't pass arguments in an fxml file if you create the objects like this:

 <Schuiver  fx:id="red" GridPane.columnIndex="1" GridPane.rowIndex="0"/>
 <Schuiver fx:id="blue" GridPane.columnIndex="1" GridPane.rowIndex="1"/>

So my question is how can I change the text of the label 'Titel' if I start a program using my Component? The titel should be like the fix:id.

Upvotes: 5

Views: 6384

Answers (2)

Ben Arceneaux
Ben Arceneaux

Reputation: 185

Overview

Although OP already selected an answer as best, from the comments it appears that there was some confusion and the selected answer did not outright answer their question and is missing information so I am posting what I believe to be the full/complete answer:

When creating a custom component in JavaFX and you'd like to provide one or more default values to the component upon it's creation, you cannot simply add a parameter to the default constructor as it is used behind the scenes when JavaFX is doing it's FXML loading thing.

To handle this conundrum we're provided with the ability to add parameters to the default constructor only if they are annotated with the @NamedArg("name of parameter here") annotation. This allows one to provide custom components with values at run-time when they are constructed either programmatically or through FXML.

Details and Examples

Custom Component Controller Constructor

public MyCustomComponent(@NamedArg("foo") String foo) { }

Behind the scenes, JavaFX recognizes that the component's constructor now has a parameter annotated with @NamedArg and this will be reflected wherever the component is currently being used. Find or create a FXML document and put your component into the text. You should then be able to set the named argument from the FXML and your IDE's intellisense should support this as well.

Adding the value to the component via FXML

<MyCustomComponent foo="myStringValue"/>

You can set the parameter programmatically:

MyCustomComponent myComp = new MyCustomComponent("myStringValue");

Now, the current selected answer to OP's question does not mention this, but as far as I know, there is one more step you have to take care of or none of this will work. The controller class must have a property that matches the named argument. I believe this is required for initializing the FXML behind the scenes but I could be wrong. Properties in Java, for the most part, look like so:

private StringProperty foo = new SimpleStringProperty();

public String getFoo()
{
  return foo.get();
}

public void setFoo(String value)
{
  this.foo.set(value);
}

public StringProperty fooProperty()
{
  return foo;
}

Conclusion

I wanted to add this here because the previous answer does answer the question but not completely and while it does appear that OP was able to figure out the issue, the answer makes no mention of what OP realized/changed to get it to work because at first it did not solve the issue. I know 100% that this will function as intended.

Upvotes: 3

James_D
James_D

Reputation: 209705

In JavaFX 8 you can do this by annotating the constructor argument with @NamedArg(...):

public class Schuiver extends VBox{

    private final SchuiverCompanion companion;

    public Schuiver(@NamedArg("text") String text) {

        // ...
    }

}

And then you can use the parameter in FXML:

<Schuiver  fx:id="red" text="red" GridPane.columnIndex="1" GridPane.rowIndex="0"/>
<Schuiver fx:id="blue" GridPane.columnIndex="1" GridPane.rowIndex="1">
    <text>
        <String fx:value="blue" />
    </text>
</Schuiver>

Upvotes: 10

Related Questions