Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 301
fangio Avatar asked May 16 '15 10:05

fangio


People also ask

What is JavaFX FXML controller?

This is a JavaFX FXML Controller Example. FXML is an XML-based language designed to build the user interface for JavaFX applications. You can use FXML to build an entire Scene or part of a Scene. FXML allows application developers to separate the logic for building the UI from the business logic.

How to bind JavaFX components to fields in the controller class?

You can bind the JavaFX components in the FXML file to fields in the controller class. To bind a JavaFX component to a field in the controller class, you need to give the FXML element for the JavaFX component an fx:id attribute which has the name of the controller field to bind it to as value.

How do I create a custom control in JavaFX?

From the File menu, choose New Project. In the JavaFX category, choose JavaFX FXML Application. Click Next. Name the project CustomControlExample and click Finish. Rename SampleController.java to CustomControl.java so that the name is more meaningful for this application.

Can a JavaFX component have a default property?

A JavaFX component can have a default property. That means, that if a FXML element contains children which are not nested inside a property element, then it is assumed that the children are belonging to the default property. Let us look at an example. The VBox class has the children property as default property.


2 Answers

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>
like image 180
James_D Avatar answered Sep 30 '22 03:09

James_D


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.

like image 31
Ben Arceneaux Avatar answered Sep 30 '22 01:09

Ben Arceneaux