2016-07-17 116 views
5

Uso di IntelliJ Ho creato un'applicazione JavaFX e poi ho aggiunto Kotlin e Maven come framework. È arrivato con un file sample.fxml e un controller.java e Main.java. Ho creato una nuova classe per il controller in Kotlin (MainWindowController.kt) e rinominato il file sample.fxml in MainWindow.fxml. Ho aggiornato il MainWindow.fxml a guardare come:Controllo FXML sempre nullo quando si utilizza Kotlin

<?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> 

E nel mio file MainWindowController.kt ho:

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}") 
    } 
} 

Ecco la mia 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); 
    } 
} 

Quando eseguo l'app la linea di stampa mostra che l'etichetta è nullo ma in caso contrario la finestra mostra correttamente e vedo il testo dalla mia etichetta. Il nullo è il problema che sto avendo. Non ho trovato molto sull'uso di FXML con Kotlin e quello che ho trovato era un po 'obsoleto e non sembrava avere una soluzione funzionante.

Qualcuno sa perché l'etichetta è nullo? Devo fare qualcosa di sbagliato o fraintendere qualcosa.

Edit: Ecco quello che ho che ora funziona grazie alle risposte rapide:

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}") 
    } 
} 
+0

non so Kotlin: è il metodo 'init' chiamato come parte della costruzione di un oggetto? –

+2

Dovresti controllare [TornadoFX] (https://github.com/edvin/tornadofx). Rende JavaFX in Kotlin davvero bello e ha DSL sicuri per tipo sia per il layout che per gli stili. –

+2

Per aggiungere al commento di @RuckusT-Boom, supporta anche FXML e lo ottimizza molto bene. https://github.com/edvin/tornadofx-guide/blob/master/Part%202%20-%20Usage%20Basics/10.%20FXML.md – tmn

risposta

5

Proprio come con i costruttori Java, fx:id campi non verranno compilati prima, ma dopo la init (o in Java del costruttore) è chiamato. Una soluzione comune è quello di implementare l'interfaccia Initializable (o semplicemente definire un metodo initialize()) e fare ulteriori configurazioni nel metodo in questo modo:

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}") 
    } 
} 
+5

Si noti che in realtà non è necessario implementare 'Inizializzabile'; è sufficiente definire un metodo 'initialize()'. –

+0

Sì, è così! Eccezionale. L'ho fatto nel modo più breve senza l'override. – GregInWI2

+0

Questo è il modo consigliato come da [documentazione JavaFX] (https://docs.oracle.com/javafx/2/api/javafx/fxml/Initializable.html) comunque: NOTA Questa interfaccia è stata sostituita dall'iniezione automatica di posizione e risorse proprietà nel controller. 'FXMLLoader' chiamerà automaticamente qualsiasi metodo' initialize() 'di no-arg opportunamente annotato definito dal controller. Si raccomanda di utilizzare l'approccio di iniezione laddove possibile. – Marv

6

Come menzionato prima. Controlla se fx: id è impostato.

È anche possibile utilizzare il modificatore lateinit.

il codice potrebbe assomiglia:

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

class MainWindowController { 
    @FXML 
    lateinit var helloLabel : Label 
}