2

enter image description here

The picture above shows a UI design that I wish to implement in my project.

As you can see, there are 2 similar rectangles with varying details in them. These details are from a custom object Bell in my project. There is a List of Bells that needs to have their details displayed like shown above.

My plan was to create a class called BellBox that will represent the rectangles containing the details of a single Bell. This class will have a method called build() that will load the FXML file named "BellBoxFMXL.fxml". The FXML file contains an AnchorPane as the root and has the necessary containers to represent all the information of a Bell. The AnchorPane will then be returned.

The BellBox class:

public class BellBox {

    protected final Bell bell ;
    protected final int index ;

    public BellBox(Bell bell, int index) {
        this.bell = bell;
        this.index = index;
    }

    public Pane build() throws IOException {
        Pane pane = FXMLLoader.load(Objects.requireNonNull(this.getClass().getResource("/model/BellBoxFXML.fxml"))) ;

        return pane ;
    }
}

Now, for the controller class. The controller class of the FXML file is called BellBoxController. Remember I said that the AnchorPane will have containers to show the details of a Bell object? Yeah, so I decided have the controller class to extend the BellBox class. The reason was so that when the initialize() method is called, the labels can be updated using the bell attribute/property of the BellBox class.

The BellBoxController class:

public class BellBoxController extends BellBox implements Initializable {

    public Label indexLbl ;

    public BellBoxController(Bell bell, int index) {
        super(bell, index) ;
        System.out.println("called with " + index) ;
    }

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
        System.out.println("initializing labels and stuff...");
        this.indexLbl.setText("#" + (this.index + 1));
    }
}

However, when I compiled the program and tried to run it, it crashed with a LoadException error.

javafx.fxml.LoadException: 
/D:/.../model/BellBoxFXML.fxml:9

    at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2625)
    at javafx.fxml.FXMLLoader.access$700(FXMLLoader.java:105)
    at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:941)
    at javafx.fxml.FXMLLoader$InstanceDeclarationElement.processAttribute(FXMLLoader.java:980)
    at javafx.fxml.FXMLLoader$Element.processStartElement(FXMLLoader.java:227)
    at javafx.fxml.FXMLLoader$ValueElement.processStartElement(FXMLLoader.java:752)
    at javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2722)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2552)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2466)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3237)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3194)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3163)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3136)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3113)
    at javafx.fxml.FXMLLoader.load(FXMLLoader.java:3106)
    at model.BellBox.build(BellBox.java:20)
    at mainapp.Main.openHomeView(Main.java:126)
    at mainapp.Main.start(Main.java:109)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:846)
    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:455)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
    at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.InstantiationException: model.BellBoxController
    at java.base/java.lang.Class.newInstance(Class.java:571)
    at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:936)
    ... 24 more
Caused by: java.lang.NoSuchMethodException: model.BellBoxController.<init>()
    at java.base/java.lang.Class.getConstructor0(Class.java:3350)
    at java.base/java.lang.Class.newInstance(Class.java:556)
    ... 25 more

Process finished with exit code 0

I also noticed that both output statements in the constructor and initialize() method were not displayed in the console. Could someone explain to me why this is and how I could go about to achieve what I hope to do? And point out what I'm doing wrong (if that's the case).

  • [mcve] please .. that said: you might want to set the controller before loading (vs. have the fx:controller attribute in the fxml) or set a controllerFactory - both allows you to have constructor with parameters – kleopatra Jun 26 '22 at 10:52
  • @kleopatra I've edited the question. Please have a look. – space-ninja-x Jun 26 '22 at 11:29
  • A compete example is shown [here](https://stackoverflow.com/a/53800394/230513). – trashgod Jun 26 '22 at 12:25
  • 1
    The exception occurs because the `FXMLLoader` is looking for, and cannot find, a no-parameter constructor. The `BellBoxController` is never instantiated because the no-parameter constructor doesn’t exist, so you never see your concise output. – James_D Jun 26 '22 at 13:12
  • 1
    Your controller should probably not be a subclass of `BellBox`, but should just have a reference to one (“favor aggregation over inheritance”). You can pass it a reference using the techniques shown at https://stackoverflow.com/q/14187963/2189127, or use a `controllerFactory`. – James_D Jun 26 '22 at 13:15
  • 2
    If you are going to implement build() then you should probably make BellBox implement Builder. And rename it to something like BellBoxBuilder. In build() instantiate the FXMLLoader and then get the Controller from it. Put some methods in BellBoxController to set the bell and index fields. Then ncall them from build(). – DaveB Jun 26 '22 at 13:40
  • 1
    Also see https://stackoverflow.com/q/32342864/2189127. You can think of `BellBox` as the model for the individual components. – James_D Jun 26 '22 at 18:58
  • 1
    And finally, you could also consider a `ListView` here, with a `cellFactory` returning a cell which used the FXML. You would just need the `Bell` and could remove `BellBox` entirely, as the cells already have access to the item’s index. – James_D Jun 26 '22 at 19:01
  • 1
    It looks like you are trying to create a custom node using `FXML`. If so, have a look at https://docs.oracle.com/javase/8/javafx/api/javafx/fxml/doc-files/introduction_to_fxml.html#custom_components. – SedJ601 Jun 26 '22 at 19:50
  • Thanks everyone. The MVC from the link @James_D shared solves the problem. – space-ninja-x Jun 27 '22 at 12:02

0 Answers0