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}")
}
}
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
}
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}")
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With