Les contrôles JavaFX et la gestion des événements
Les contrôles sont les éléments interactifs d'une interface utilisateur JavaFX. Ils permettent à l'utilisateur de visualiser des informations et d'interagir avec l'application. Cette page présente les contrôles de base et la manière de gérer les événements qui leur sont associés.
Contrôles de base
JavaFX propose une large gamme de contrôles prêts à l'emploi. Voici les plus couramment utilisés :
Label
Un Label est un contrôle simple qui affiche du texte non modifiable par l'utilisateur.
Label simpleLabel = new Label("Texte simple");
// Label avec mise en forme
Label formattedLabel = new Label("Texte en gras");
formattedLabel.setStyle("-fx-font-weight: bold; -fx-text-fill: blue;");
// Label avec graphique
Label iconLabel = new Label("Important");
iconLabel.setGraphic(new ImageView(new Image("warning.png")));
iconLabel.setContentDisplay(ContentDisplay.LEFT); // Icône à gauche du texte
TextField et TextArea
Contrôles permettant la saisie de texte par l'utilisateur. TextField est sur une ligne, TextArea sur plusieurs.
// Champ texte simple
TextField nameField = new TextField();
nameField.setPromptText("Entrez votre nom"); // Texte d'invite (placeholder)
// Champ avec validation
TextField emailField = new TextField();
emailField.textProperty().addListener((observable, oldValue, newValue) -> {
if (newValue.matches("^[\\w-\\.]+@([\\w-]+\\.)+[\\w-]{2,4}$")) {
emailField.setStyle("-fx-border-color: green;");
} else {
emailField.setStyle("-fx-border-color: red;");
}
});
// Zone de texte multi-lignes
TextArea commentArea = new TextArea();
commentArea.setPrefRowCount(5); // Hauteur préférée en nombre de lignes
commentArea.setWrapText(true); // Retour à la ligne automatique
Button
Le Button est un bouton standard qui déclenche une action lorsqu'il est cliqué.
// Bouton simple avec texte
Button submitButton = new Button("Valider");
// Bouton avec icône
Button saveButton = new Button("Enregistrer");
saveButton.setGraphic(new ImageView(new Image("save.png")));
// Bouton avec style personnalisé
Button dangerButton = new Button("Supprimer");
dangerButton.getStyleClass().add("danger-button"); // Classe CSS personnalisée
CheckBox
La CheckBox est une case à cocher permettant de sélectionner/désélectionner une option.
// Case à cocher simple
CheckBox rememberMeCheckbox = new CheckBox("Se souvenir de moi");
// Vérifier l'état
if (rememberMeCheckbox.isSelected()) {
// Action si cochée
}
// Réagir aux changements d'état
rememberMeCheckbox.selectedProperty().addListener((observable, oldValue, newValue) -> {
System.out.println("Case à cocher : " + (newValue ? "cochée" : "décochée"));
});
RadioButton
Le RadioButton est un bouton radio permettant de sélectionner une option parmi un groupe d'options.
// Création d'un groupe pour les boutons radio
ToggleGroup paymentGroup = new ToggleGroup();
// Création des boutons radio
RadioButton creditCardRadio = new RadioButton("Carte de crédit");
RadioButton paypalRadio = new RadioButton("PayPal");
RadioButton bankTransferRadio = new RadioButton("Virement bancaire");
// Ajout des boutons au groupe
creditCardRadio.setToggleGroup(paymentGroup);
paypalRadio.setToggleGroup(paymentGroup);
bankTransferRadio.setToggleGroup(paymentGroup);
// Sélection par défaut
creditCardRadio.setSelected(true);
// Récupérer la sélection
RadioButton selectedRadio = (RadioButton) paymentGroup.getSelectedToggle();
String paymentMethod = selectedRadio.getText();
ComboBox et ChoiceBox
Listes déroulantes permettant de sélectionner une valeur parmi plusieurs options. ComboBox (permet la saisie et la recherche) et ChoiceBox (plus simple, sans saisie).
// ComboBox (permet la saisie et la recherche)
ComboBox countryComboBox = new ComboBox<>();
countryComboBox.getItems().addAll("France", "Allemagne", "Espagne", "Italie", "Royaume-Uni");
countryComboBox.setPromptText("Sélectionnez un pays");
// ChoiceBox (plus simple, sans saisie)
ChoiceBox genderChoice = new ChoiceBox<>();
genderChoice.getItems().addAll("Homme", "Femme", "Non-binaire", "Préfère ne pas préciser");
genderChoice.setValue("Préfère ne pas préciser"); // Valeur par défaut
Slider
Le Slider est un curseur permettant de sélectionner une valeur numérique dans une plage définie.
// Slider simple
Slider volumeSlider = new Slider(0, 100, 50); // min, max, valeur initiale
volumeSlider.setShowTickLabels(true); // Afficher les étiquettes
volumeSlider.setShowTickMarks(true); // Afficher les graduations
volumeSlider.setMajorTickUnit(20); // Graduation principale tous les 20
volumeSlider.setMinorTickCount(4); // 4 graduations mineures entre chaque graduation principale
volumeSlider.setBlockIncrement(10); // Incrément lors des clics sur la piste
DatePicker
Le DatePicker est un contrôle permettant de sélectionner une date dans un calendrier.
// DatePicker simple
DatePicker birthDatePicker = new DatePicker();
birthDatePicker.setPromptText("Date de naissance");
// Avec une date par défaut
DatePicker startDatePicker = new DatePicker(LocalDate.now());
// Récupérer la date sélectionnée
LocalDate selectedDate = startDatePicker.getValue();
Gestionnaires d'événements
JavaFX utilise un système d'événements pour permettre aux contrôles de réagir aux actions de l'utilisateur. Il existe plusieurs façons de gérer ces événements.
setOnAction avec lambda
La méthode la plus simple pour les contrôles qui déclenchent une seule action principale (comme les boutons).
Button submitButton = new Button("Envoyer");
submitButton.setOnAction(event -> {
System.out.println("Formulaire envoyé !");
// Traiter l'envoi du formulaire...
});
TextField usernameField = new TextField();
usernameField.setOnAction(event -> {
// Action quand l'utilisateur appuie sur Entrée dans le champ
System.out.println("Nom d'utilisateur soumis : " + usernameField.getText());
});
addEventHandler avec interface EventHandler
Approche plus détaillée qui permet de gérer différents types d'événements et d'ajouter plusieurs gestionnaires pour le même type d'événement.
Button loginButton = new Button("Connexion");
// Utilisation d'une classe anonyme implémentant EventHandler
loginButton.addEventHandler(ActionEvent.ACTION, new EventHandler() {
@Override
public void handle(ActionEvent event) {
System.out.println("Tentative de connexion");
// Logique de connexion...
}
});
// Version équivalente avec lambda
loginButton.addEventHandler(ActionEvent.ACTION, event -> {
System.out.println("Tentative de connexion");
// Logique de connexion...
});
Différence entre source et target
Dans un événement JavaFX, la source est le contrôle qui a généré l'événement, tandis que la target est le contrôle qui a reçu l'événement (ils peuvent être différents en cas de propagation d'événements).
button.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> {
Node source = (Node) event.getSource(); // Le bouton qui a généré l'événement
Node target = (Node) event.getTarget(); // Peut être le bouton ou un élément à l'intérieur
System.out.println("Source : " + source);
System.out.println("Target : " + target);
// La source et la target peuvent être différentes si le bouton contient d'autres éléments
// comme une icône (ImageView) ou un texte stylisé
});
Exemple complet : champ secret + message
Voici un exemple qui montre un champ de texte "secret" et affiche un message spécial lorsque l'utilisateur tape un mot-clé particulier.
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class SecretFieldExample extends Application {
private static final String SECRET_WORD = "ET";
@Override
public void start(Stage primaryStage) {
// Création des contrôles
Label instructionLabel = new Label("Entrez un message secret :");
TextField secretField = new TextField();
Label resultLabel = new Label("Surveillez cet espace...");
resultLabel.setTextFill(Color.GRAY);
// Gestionnaire d'événements avec lambda
secretField.textProperty().addListener((observable, oldValue, newValue) -> {
if (newValue.toUpperCase().contains(SECRET_WORD)) {
resultLabel.setText("E.T. repéré! Appelez la NASA!");
resultLabel.setTextFill(Color.GREEN);
} else {
resultLabel.setText("Surveillez cet espace...");
resultLabel.setTextFill(Color.GRAY);
}
});
// Mise en page
VBox root = new VBox(10);
root.setPadding(new Insets(20));
root.getChildren().addAll(instructionLabel, secretField, resultLabel);
// Configuration et affichage de la scène
Scene scene = new Scene(root, 350, 150);
primaryStage.setTitle("Détecteur de secrets");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Ce code va dans src/main/java/com/example/javafxdemo/SecretFieldExample.java
Exemple multi-handlers et removeEventHandler
Cet exemple montre comment ajouter et retirer plusieurs gestionnaires d'événements sur un même contrôle.
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class MultiHandlersExample extends Application {
@Override
public void start(Stage primaryStage) {
// Création des contrôles
Button actionButton = new Button("Cliquez-moi");
Label resultLabel = new Label("Résultats des actions:");
CheckBox enableLoggingCheckBox = new CheckBox("Activer la journalisation");
enableLoggingCheckBox.setSelected(true);
// Création des gestionnaires d'événements
EventHandler countClickHandler = event -> {
resultLabel.setText(resultLabel.getText() + "\nBouton cliqué !");
};
EventHandler loggingHandler = event -> {
System.out.println("LOG: Bouton cliqué à " + java.time.LocalTime.now());
};
// Ajout des gestionnaires
actionButton.addEventHandler(ActionEvent.ACTION, countClickHandler);
actionButton.addEventHandler(ActionEvent.ACTION, loggingHandler);
// Gestionnaire pour activer/désactiver la journalisation
enableLoggingCheckBox.selectedProperty().addListener((obs, oldVal, newVal) -> {
if (newVal) {
// Ajouter le gestionnaire de journalisation
actionButton.addEventHandler(ActionEvent.ACTION, loggingHandler);
System.out.println("Journalisation activée");
} else {
// Retirer le gestionnaire de journalisation
actionButton.removeEventHandler(ActionEvent.ACTION, loggingHandler);
System.out.println("Journalisation désactivée");
}
});
// Mise en page
VBox root = new VBox(10);
root.setPadding(new Insets(20));
root.getChildren().addAll(
enableLoggingCheckBox,
actionButton,
resultLabel
);
// Configuration et affichage de la scène
Scene scene = new Scene(root, 400, 300);
primaryStage.setTitle("Exemple de multi-gestionnaires");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Ce code va dans src/main/java/com/example/javafxdemo/MultiHandlersExample.java
Types d'événements courants
Type d'événement | Description | Exemple d'utilisation |
---|---|---|
ActionEvent | Déclenché par un contrôle quand l'action principale est exécutée | Clic sur un bouton, appui sur Entrée dans un TextField |
MouseEvent | Événements liés à la souris | MOUSE_CLICKED, MOUSE_PRESSED, MOUSE_RELEASED, MOUSE_MOVED, MOUSE_ENTERED, MOUSE_EXITED |
KeyEvent | Événements liés au clavier | KEY_PRESSED, KEY_RELEASED, KEY_TYPED |
WindowEvent | Événements liés à la fenêtre | WINDOW_SHOWING, WINDOW_SHOWN, WINDOW_HIDING, WINDOW_HIDDEN, WINDOW_CLOSE_REQUEST |
ScrollEvent | Événements de défilement | SCROLL, SCROLL_STARTED, SCROLL_FINISHED |
DragEvent | Événements de glisser-déposer | DRAG_ENTERED, DRAG_EXITED, DRAG_OVER, DRAG_DROPPED |
Conseils pratiques
- Utiliser les lambdas pour des gestionnaires d'événements courts et lisibles.
- Séparer la logique métier des gestionnaires d'événements pour maintenir le code propre.
- Préférer setOnXXX pour les événements simples et addEventHandler pour les cas plus complexes ou multiples.
- Gérer les exceptions dans les gestionnaires d'événements pour éviter que l'application ne plante.
- Utiliser Platform.runLater() pour mettre à jour l'interface depuis un thread différent du thread JavaFX.
// Exemple d'utilisation de Platform.runLater()
new Thread(() -> {
// Opération longue dans un thread séparé
// ...
// Mise à jour de l'interface dans le thread JavaFX
Platform.runLater(() -> {
label.setText("Opération terminée");
progressBar.setVisible(false);
});
}).start();