How to extend custom JavaFX components that use FXML

柔情痞子 提交于 2019-11-30 13:18:21

From what I understand, you want to be able to extend existing components and avoid copy & pasting the entire markup for the new component.

You can define an extension point for the component with the @DefaultProperty annotation. Look at e.x. javafx.scene.layout.Pane: There is a ObservableList getChildren() defined with @DefaultProperty("children"). In this way, when you use e.x an HBox (extends Pane) as the root element for your component, all child components are added to the children property defined by the Pane.

In the same way you can define extension points in FXML:

SpecializedButton.fxml (I simplified it a little for this example)

<fx:root type="HBox">
  <HBox>
    <Label fx:id="label" text="Click to do something: " />
    <HBox fx:id="extension"></HBox>
  </HBox>

  <HBox>
    <Button fx:id="button" onAction="#doSomething"/>
  </HBox>
</fx:root>

The HBox fx:id="extension" will be my extension point:

@DefaultProperty(value = "extension")
public class SpecializedButton extends HBox
{
    @FXML private HBox extension;

    public ObservableList<Node> getExtension() {
        return extension.getChildren();
    }
    // ... more component specific code
}

SuperSpecializedButton.fxml

<fx:root type="SpecializedButton">
  <Label text="EXTENDED HALLO"/>
</fx:root>

And:

public class SuperSpecializedButton extends SpecializedButton
{
    // ... more component specific code
}

As you can see, I need only to define fxml for the super-specialized component.

This code will work only on JavaFX >= 2.1. Beforehand the component injection for the super class didn't worked with the FXMLLoader.

I added an working example on github: https://github.com/matrak/javafx-extend-fxml

I haven't done that before, but you could implement the Initializable interface to setup the view component when you instantiate a new custom component.

To add new component(labels, buttons, img, etc...) I would wrap all the children component on the view file, within an AnchorPane, GridPane, VBox or the one you prefer to add more components programmatically. Since you are extending your class from HBox you could do this already.

Here's what I would do:

public class SpecializedButton extends HBox implements Initializable{

@FXML private Button button;
@FXML private Label label;

public SpecializedButton(){
    FXMLLoader loader = new FXMLLoader( getClass().getResource( "SpecializedButton.fxml" ) );

    loader.setRoot( this );
    loader.setController( this );

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

// specialized methods for this specialized button
// ...
public void doSomething() {
    button.setText( "Did something!" );
}

@Override
public void initialize(URL url, ResourceBundle rb) {
    button.setText("Initialized Text");
}  
}

So for the HighlySpecializedButton class:

public class HighlySpecializedButton extends SpecializedButton {



public HighlySpecializedButton (){
    super();
}

// HighlySpecializedButton methods


@Override
public void initialize(URL url, ResourceBundle rb) {
    this.getChildren().add(new Button("New Button"));

}  
}

Hope this could help you

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!