Java Reading Group BOF organise depuis janvier 2018 un groupe de lecture «Kotlin in Action».
Si vous voulez apprendre Kotlin de toutes vos forces, j'ai décidé de réécrire l'interface graphique que le message Hello world circule dans le JavaFX créé précédemment avec Kotlin parce que je voulais faire quelque chose.
Cet article vise à remplacer le code Java ci-dessus par Kotlin. Par conséquent, veuillez vous référer au blog ci-dessus pour l'explication de JavaFX.
Stockez le code créé dans le référentiel suivant (URL de la visionneuse du référentiel)
http://www.torutk.com/projects/swe/repository/revisions/master/show/learn/kotlin/javafx/MessageBoard
Si vous souhaitez éviter les problèmes liés à la création d'un environnement et utiliser beaucoup de support de codage tel que l'achèvement de code, l'environnement de développement de JetBrains IntelliJ IDEA, qui développe Kotlin, ou Android Studio, basé sur IntelliJ IDEA, est presque le choix. est.
Dans l'article "Hello world qui coule avec JavaFX", j'ai présenté comment créer dans l'environnement de ligne de commande Java. La connaissance de l'environnement d'exécution Java est utile et doit être connue. Cependant, dans le cas de Kotlin, il y a beaucoup de travail dans la préparation de l'environnement Kotlin en plus de l'environnement Java, et je n'ai pas beaucoup l'occasion d'utiliser ces connaissances, donc cette fois j'utiliserai l'EDI depuis le début.
IntelliJ IDEA Community Edition IntelliJ IDEA est un produit d'environnement de développement commercial, mais Community Edition est fourni gratuitement. L'environnement de développement de Kotlin est inclus dans Community Edition, nous allons donc l'utiliser cette fois.
Je pense qu'il peut être utilisé dans Android Studio (également fourni gratuitement par Google) de la même manière, mais je ne l'ai pas vérifié.
Pleiades, un outil de localisation japonais familier dans Eclipse, prend également en charge la localisation japonaise d'IntelliJ IDEA. Ensuite, j'écris une petite méthode d'introduction.
Dans l'environnement Windows japonais, les polices européennes sont belles, mais les polices japonaises sont MS Gothic et dentelées. Ensuite, j'écris un paramètre pour nettoyer un peu la police.
Dans IntelliJ IDEA, créez un projet pour un programme Hello world fluide.
MessageBoard.kt
class MessageBoard {
}
De là, nous appellerons JavaFX et créerons un monde Hello fluide.
Appelez JavaFX avec Kotlin et programmez l'interface graphique du message Hello world.
JavaFX hérite de la classe Application et prépare une classe qui est l'entrée du traitement JavaFX.
Laissez la classe créée par l'application hériter de la classe Application JavaFX.
MessageBoard.kt
class MessageBoard : Application {
}
Dans Kotlin, l'héritage est spécifié par un symbole deux-points. Ici, la classe Application doit être importée, donc dans le code IntelliJ IDEA, le message contextuel suivant s'affiche.
Suivez le message contextuel et appuyez sur Alt + Entrée et sélectionnez javafx.application.Application dans la liste des candidats.
Une instruction d'importation est générée.
MessageBoard.kt
import javafx.application.Application
class MessageBoard : Application {
}
Cependant, il est toujours incomplet et est dans un état d'erreur de compilation. L'écran suivant montre la situation dans laquelle le contenu de l'erreur est affiché.
Vous devez définir une méthode de démarrage. Dans le menu Code> Implémenter la méthode, générez le début de méthode abstraite de la classe Application.
Le code généré est:
MessageBoard.kt
import javafx.application.Application
import javafx.stage.Stage
class MessageBoard : Application {
override fun start(primaryStage: Stage?) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
}
Cependant, il y a encore des erreurs. Une ligne ondulée rouge est dessinée sous l'application. Lorsque vous déplacez le curseur sur Application, le contenu de l'erreur apparaîtra comme suit.
Le message est "Ce type a un constructeur et doit donc être initialisé ici". Qu'est-ce que c'est? Les détails seront décrits dans la section suivante.
«Kotlin en action» à la page 106 de la section 4.2.1
Open class Button ← Un constructeur par défaut sans argument est généré
Si vous héritez de la classe Button et n'avez pas de constructeur, vous devez appeler explicitement le constructeur de cette super classe, même si le constructeur de la super classe n'a pas d'arguments.
class RadioButton : Button()
Donc, cette fois, nous ne définissons pas de constructeur dans la classe MessageBoard, donc la bonne réponse est de mettre des parenthèses dans la superclasse héritée.
MessageBoard.kt
import javafx.application.Application
import javafx.stage.Stage
class MessageBoard : Application() {
override fun start(primaryStage: Stage?) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
}
Vous avez maintenant le code avec l'erreur de compilation supprimée.
Mais je ne peux toujours pas le faire. Définissez la méthode principale qui est le point d'entrée du programme. Dans Kotlin, au lieu de définir la méthode principale comme une méthode statique dans la classe comme en Java, elle est définie comme une fonction de niveau supérieur.
MessageBoard.kt
class MessageBoard : Application() {...}
fun main(args: Array<String>) {
//Écrivez le code qui appelle la méthode de lancement de la classe Application ici
}
Kotlin n'a pas de méthodes statiques / champs statiques, mais il est possible d'accéder aux méthodes statiques / champs statiques définis dans les classes Java, et leurs expressions d'appel sont les mêmes qu'en Java.
La méthode de lancement de la classe Application JavaFX a des arguments différents lorsqu'elle est appelée à partir d'une sous-classe de la classe Application et lorsqu'elle est appelée depuis l'extérieur de cette sous-classe. Cette fois, comme il s'agit de l'extérieur de la sous-classe, Java appelle la méthode de lancement du format suivant.
public static void launch(
Class<? extends Application> appClass,
String... args
)
Il y a deux défis ici:
La première consiste à récupérer la référence de classe (type KClass) avec :: class pour la classe, puis à appeler et à acquérir la propriété étendue java de type KClass.
Le second utilise l'opérateur de diffusion pour étendre le tableau.
fun main(args: Array<String>) {
Application.launch(MessageBoard::class.java, *args)
}
Où spécifier des arguments de longueur variable avec l'opérateur de propagation, voir «Kotlin en action», Section 3.4.2 (p.76).
Kotlin doit récupérer explicitement le contenu du tableau, de sorte que tous les éléments du tableau soient des arguments indépendants de la fonction appelante. Techniquement, cette fonctionnalité est appelée en utilisant l'opérateur spread, mais c'est en fait aussi simple que de mettre un * devant l'argument correspondant.
fun main(args: Array<String>) { val list = listOf("args: ", *args)← L'opérateur Spread récupère le contenu d'un tableau print(list) }
Il y a.
Ceci termine l'implémentation minimale. Lançons-le (bien que la fenêtre ne soit pas encore affichée).
Si vous définissez la fonction principale au niveau supérieur du fichier, l'icône suivante sera ajoutée sur le côté gauche de la ligne.
Cliquez sur cette icône pour afficher les options de couverture d'exécution, de débogage et d'exécution. Sélectionnez Exécuter.
Le code sera ensuite construit et exécuté. Lorsqu'il est exécuté à partir de cette icône pour la première fois, [Exécuter] est activé dans le menu [Exécuter], et le nom de classe (nom de fichier) du fichier dans lequel la fonction principale est définie dans la liste dans le menu [Exécuter]> [Exécuter la configuration de démarrage]. Une classe nommée avec Kt) sera ajoutée et peut être sélectionnée.
Lorsqu'il est exécuté, le code d'implémentation du modèle TODO de la méthode start est appelé pour afficher une exception.
"C:\Program Files\Java\jdk-9\bin\java" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2017.3.1\lib\idea_rt.jar=52509:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2017.3.1\bin" -Dfile.encoding=UTF-8 -classpath "D:\work\java\repos\swe.primus\learn\kotlin\javafx\MessageBoard\out\production\MessageBoard;C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2017.3.1\plugins\Kotlin\kotlinc\lib\kotlin-stdlib.jar;C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2017.3.1\plugins\Kotlin\kotlinc\lib\kotlin-reflect.jar;C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2017.3.1\plugins\Kotlin\kotlinc\lib\kotlin-test.jar;C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2017.3.1\plugins\Kotlin\kotlinc\lib\kotlin-stdlib-jdk7.jar;C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2017.3.1\plugins\Kotlin\kotlinc\lib\kotlin-stdlib-jdk8.jar" MessageBoardKt
Exception in Application start method
Exception in thread "main" Exception in thread "Thread-2" java.lang.RuntimeException: Exception in Application start method
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:973)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:198)
at java.base/java.lang.Thread.run(Thread.java:844)
Caused by: kotlin.NotImplementedError: An operation is not implemented: not implemented
at MessageBoard.start(MessageBoard.kt:6)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:919)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$11(PlatformImpl.java:449)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$9(PlatformImpl.java:418)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:417)
at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:175)
... 1 more
java.lang.IncompatibleClassChangeError
Il est enfin temps de mettre en œuvre. Tout d'abord, décrivez la visualisation de la scène avec la méthode de démarrage. En tant que programmeur Java, je coderais ce qui suit, qui est une erreur de compilation. Le fait est que le type d'argument est Stage? Et a un? À la fin.
MessageBoard.kt
override fun start(primaryStage: Stage?) {
primaryStage.show()
}
L'erreur de compilation s'affiche dans la fenêtre contextuelle suivante.
Les types d'argument de la méthode start sont Stage? Type et Nullable type. Par conséquent, il est nécessaire de vérifier null avant d'appeler la méthode ou d'appeler la méthode pour null.
Ici, si l'argument primaryStage devient nul, rien n'est fait, donc la méthode show est appelée avec l'opérateur d'appel sécurisé (?.).
MessageBoard.kt
override fun start(primaryStage: Stage?) {
primaryStage?.show()
}
Dans «Kotlin en action», section 6.1.3 (p.181)
L'opérateur d'appel sécurisé?. Il s'agit d'une combinaison de vérification de null et d'invocation de méthode en un seul opérateur. (Omis) Autrement dit, si la valeur à laquelle vous essayez d'appeler une méthode n'est pas nulle, l'appel de méthode sera exécuté normalement, si la valeur est nulle, l'appel sera ignoré et nul sera utilisé comme valeur à la place.
Il y a.
Lors de l'exécution, une fenêtre vide apparaîtra.
Affichez le texte dans une fenêtre vide.
Tout d'abord, générez un texte qui affiche les caractères. La différence avec Java est qu'il n'y a pas de nouvel opérateur et que le type de variable est déclaré avec une valeur immuable.
MessageBoard.kt
val message = Text("Hello, world. This is JavaFX from Kotlin.")
Créez un groupe pour regrouper les nœuds JavaFX. La création d'instances et les types de variables sont similaires au texte ci-dessus. Ensuite, ce qu'on appelait setLayoutY (50d) en Java devient une instruction d'affectation à une propriété dans Kotlin. De plus, en java, Kotlin n'a pas de D (ou d) qui indique un littéral numérique double, donc la valeur après la virgule décimale est spécifiée comme .0. En passant, si vous écrivez 50 et un littéral entier (type Int), une erreur se produira si les types sont différents.
MessageBoard.kt
val group = Group(message)
group.layoutY = 50.0
Générez une scène. Quant à la taille (largeur, hauteur), si le type est différent pour les entiers, une erreur se produira, donc les valeurs après la virgule décimale sont spécifiées. De plus, en java, il est défini sur primaryStage avec la méthode setScene, et dans Kotlin, il est affecté à une propriété.
MessageBoard.kt
val scene = Scene(group, 320.0, 160.0)
primaryStage?.scene = scene
La méthode de démarrage entière ressemble à ceci:
MessageBoard.kt
override fun start(primaryStage: Stage?) {
val message = Text("Hello, world. This is JavaFX from Kotlin.")
val group = Group(message)
group.layoutY = 50.0
val scene = Scene(group, 320.0, 160.0)
primaryStage?.scene = scene
primaryStage?.show()
}
Je le ferai.
Utilisez l'animation JavaFX pour déplacer le texte de droite à gauche.
Dans la méthode de démarrage, définissez TranslateTransition pour l'animation.
MessageBoard.kt
val messageTransition = TranslateTransition(Duration.seconds(8.0), message)
messageTransition.fromX = 320.0
messageTransition.toX = -320.0
messageTransition.interpolator = Interpolator.LINEAR
messageTransition.cycleCount = TranslateTransition.INDEFINITE
Encore une fois, la différence est que vous n'avez pas besoin du nouvel opérateur et que la méthode set est une affectation à une propriété, mais c'est presque la même chose que le code Java. Appelez également play () à la fin.
MessageBoard.kt
messageTransition.play()
Une fois exécuté, le monde Hello qui coule s'affiche. Ce qui suit est un GIF animé de l'écran affiché à 10 fps (le plus fou est le problème du FPS lors de la création d'un GIF animé, JavaFX dessine à un maximum de 60 fps).
Dans le code ci-dessus, la description de TranslateTransition est redondante pour Kotlin (l'attribution de propriété à une variable locale apparaît à plusieurs reprises), donc apply est utilisé pour réduire la quantité de description. La méthode de démarrage complète après réduction est indiquée ci-dessous.
MessageBoard.kt
override fun start(primaryStage: Stage?) {
val message = Text("Hello, world. This is JavaFX from Kotlin.")
val group = Group(message)
group.layoutY = 80.0
val scene = Scene(group, 320.0, 160.0)
primaryStage?.scene = scene
primaryStage?.show()
TranslateTransition(Duration.seconds(8.0), message).apply {
fromX = 320.0
toX = -320.0
interpolator = Interpolator.LINEAR
cycleCount = TranslateTransition.INDEFINITE
}.play()
}
Enfin, définissez la couleur et la taille du texte du message.
MessageBoard.kt
override fun start(primaryStage: Stage?) {
val message = Text().apply {
text = "Hello, world. This is JavaFX from Kotlin."
fill = Color.DARKMAGENTA
font = Font.font("Serif", FontWeight.SEMI_BOLD, 32.0)
}
val messageWidth = message.layoutBounds.width
val messageHeight = message.layoutBounds.height
val group = Group(message)
group.layoutY = messageHeight * 2
val scene = Scene(group, messageWidth, messageHeight * 3)
primaryStage?.scene = scene
primaryStage?.show()
TranslateTransition(Duration.seconds(8.0), message).apply {
fromX = messageWidth
toX = -messageWidth
interpolator = Interpolator.LINEAR
cycleCount = TranslateTransition.INDEFINITE
}.play()
}
Je le ferai.
Cette fois, le but est de le regrouper dans un JAR exécutable.
Dans l'EDI NetBeans, lorsque j'ai créé un projet Java, il a créé un fichier JAR qui pouvait être exécuté sans aucun paramètre supplémentaire.
Après avoir étudié ce que IntelliJ IDEA devrait être en mesure de faire, vous pouvez générer un fichier JAR exécutable en suivant les étapes ci-dessous.
Vous devez spécifier la classe principale. Dans Kotlin, la fonction principale est écrite au niveau supérieur du fichier. Une fois compilé en code d'octet Java, ce sera une classe nommée d'après le nom du fichier (inclus dans la classe MessageBoardKt si la fonction principale est définie au niveau supérieur du fichier MessageBoard.kt).
Lors de la construction et de l'exécution avec IntelliJ IDEA, le fichier de classe suivant est généré sous out \ production \ MessageBoard sous le répertoire du projet.
Examinez les méthodes définies dans chaque fichier de classe avec la commande javap du JDK.
D:~> javap MessageBoard
Compiled from "MessageBoard.kt"
public final class MessageBoard extends javafx.application.Application {
public void start(javafx.stage.Stage);
public MessageBoard();
}
D:~>javap MessageBoardKt
Compiled from "MessageBoard.kt"
public final class MessageBoardKt {
public static final void main(java.lang.String[]);
}
La classe qui a la méthode principale est MessageBoardKt.class. Donc, dans la suite de la précédente, spécifiez la classe principale sur l'écran suivant. Cliquez sur […] à l'extrémité droite de la colonne principale de la classe.
Cela fera apparaître l'écran Sélectionner la classe principale. Dans l'onglet Recherche par nom, entrez une partie du nom de la classe principale (ici «M») car il est initialement vide. Ensuite, la classe correspondant à ce nom sera répertoriée, donc sélectionnez [MessageBoardKt] ici.
Le champ de fichier JAR de la bibliothèque est défini sur Extraire vers JRA cible par défaut. Cela inclura les fichiers de classe de la bibliothèque ensemble dans le fichier exécutable JAR lors de l'utilisation d'une bibliothèque standard non Java SE. [Copier dans le répertoire de sortie et lien via le manifeste] est la différence entre la préparation d'un fichier de bibliothèque séparément du fichier JAR exécutable et l'écriture d'une référence au fichier de bibliothèque dans le manifeste dans le fichier JAR exécutable.
Cette fois, nous laisserons la valeur par défaut pour qu'elle puisse être exécutée en ne distribuant qu'un seul fichier JAR. Cliquez sur OK pour afficher la configuration comme indiqué ci-dessous.
Si vous cochez [Inclure dans la construction du projet], un fichier JAR sera généré lors de l'exécution de la construction. Si vous n'aimez pas le temps nécessaire, laissez-la décochée et choisissez le menu Construire> Créer des artefacts pour générer un fichier JAR. Sélectionnez Build / Rebuild avec le nom de la configuration que vous venez de créer.
Le fichier JAR a été généré dans le répertoire du projet out \ artifacts \ MessageBoard_jar \ MessageBoard.jar. La capacité est aussi grande que 3,3 Mo. C'est parce qu'il inclut également la bibliothèque d'exécution Kotlin.
Si vous distribuez ce fichier JAR indépendamment, vous pouvez exécuter le programme créé par Kotlin dans l'environnement où JRE est inclus.
Si le code suivant commence à se sentir redondant,
val messageWidth = message.layoutBounds.width
val messageHeight = message.layoutBounds.height
Je souhaite appliquer la déclaration de décomposition
val (messageWidth, messageHeight) = message.layoutBounds
Je veux ecrire. Cependant, les classes Java n'ont pas de méthodes définies component1 (), component2 (), ... pour appliquer les déclarations de décomposition.
Par conséquent, définissez-le avec une méthode d'extension.
operator fun Bounds.component1(): Double = width
operator fun Bounds.component2(): Double = height
Cela permettra à la classe Bounds d'être utilisée dans les déclarations de décomposition.
Cependant, c'est une grande exagération. Ce n'est «pas de grâce» (il est inévitable de passer).
Recommended Posts