Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

FXML control always null when using Kotlin

Using IntelliJ I created a JavaFX application and then added Kotlin and Maven as frameworks to it. It came with a sample.fxml file and a Controller.java and Main.java. I created a new class for the controller in Kotlin (MainWindowController.kt) and renamed the sample.fxml file to MainWindow.fxml. I updated the MainWindow.fxml to look like:

<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.GridPane?>
<GridPane fx:controller="reader.MainWindowController" xmlns:fx="http://javafx.com/fxml" xmlns="http://javafx.com/javafx/8" alignment="center" hgap="10" vgap="10">
    <Label fx:id="helloLabel" text="Hello"/>
</GridPane>

And in my MainWindowController.kt file I have:

package reader

import javafx.fxml.FXML
import javafx.scene.control.Label

class MainWindowController {

    @FXML var helloLabel: Label? = null

    init {
        println("Label is null? ${helloLabel == null}")
    }
}

Here's my Main.java:

import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception{
        Parent root = FXMLLoader.load(getClass().getClassLoader().getResource("MainWindow.fxml"));
        primaryStage.setTitle("My App");
        primaryStage.setScene(new Scene(root, 1000, 600));
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

When I run the app the print line shows that the label is null but otherwise the window shows properly and I see the text from my label. The null is the problem I'm having. I haven't found much on using FXML with Kotlin and what I did find was a little out-dated and didn't appear to have an actual working solution.

Does anyone know why the label is null? I must be doing something wrong or misunderstanding something.

Edit: Here's what I have that now works thanks to the quick replies:

package reader

import javafx.fxml.FXML
import javafx.scene.control.Label

class MainWindowController {

    @FXML var helloLabel: Label? = null

    fun initialize() {
        println("Label is null? ${helloLabel == null}")
    }
}
like image 590
GregInWI2 Avatar asked Jul 17 '16 23:07

GregInWI2


2 Answers

As mentioned before. Check if fx:id is set.

Is also possible to use lateinit modifier.

Your code could looks like:

import javafx.fxml.FXML
import javafx.scene.control.Label

class MainWindowController {
    @FXML 
    lateinit var helloLabel : Label
}
like image 168
Payne Avatar answered Nov 17 '22 00:11

Payne


Just like with Java constructors, fx:id fields will not be populated before but after the init (or in Java the constructor) is called. A common solution is to implement the Initializable interface (or just define an initialize() method) and do additional setup inside the method like so:

import javafx.fxml.FXML
import javafx.scene.control.Label

class MainWindowController : Initializable {
    @FXML 
    var helloLabel: Label? = null

    override fun initialize(location: URL?, resources: ResourceBundle?) {
        println("Label is null? ${helloLabel == null}")
    }
}
like image 32
Marv Avatar answered Nov 16 '22 22:11

Marv