Transparents du cours.
Transcription
Transparents du cours.
Interfaces graphiques - JavaFX responsable : Wieslaw Zielonka [email protected] http://liafa.univ-paris-diderot.fr/∼zielonka February 24, 2016 propriétés −→ listeners évènements −→ handlers Propriétés (beans de javafx) Une propriété d’un objet (dans le sens de javafx) est une variable privée d’instance de l’objet qui satisfait les conditions suivantes : I le type de cette variable est un des types défini dans le package javafx.beans.property : BooleanProperty, DoubleProperty, IntegerProperty, ObjectProperty, StringProperty etc. Évidemment BooleanProperty permet de stocker une valeur booléenne, DoubleProperty une valeur double etc. Définir une propriété I pour chaque propriété la classe définit trois méthodes. Supposons par exemple que la classe possède une variable d’instance private DoubleProperty hauteurMaison = new S i m p l e D o u b l e P r o p e r t y ( ) ; Dans ce cas la classe doit définir les méthodes : p u b l i c f i n a l double getHauteurMaison (){ return hauteurMaison . get ( ) ; } public f i n a l void s e t H a u t e u r M a i s o n ( double v ) { h a u t e u r M a i s o n . s e t ( v ) ; } public DoubleProperty hauteurMaisonProperty (){ return hauteurMaison ;} Notez la correspondance entre le nom de la propriété et les noms des méthodes. Autre exemple p u b l i c c l a s s Model { // L e s d o n n e e s s o n t c o n s t i t u e e s d ’ un s e u l e n t i e r . private IntegerProperty entier ; Model ( i n t v a l ) { e n t i e r = new S i m p l e I n t e g e r P r o p e r t y ( v a l ) ; } Model ( ) { t h i s ( 0 ) ; } public f i n a l int getEntier (){ return e n t i e r . get ( ) ; } public f i n a l IntegerProperty entierProperty (){ return e n t i e r ; } p u b l i c f i n a l void s e t E n t i e r ( i n t v a l ){ entier . set ( val ); } } Définir ChangeListeners Pour chaque propriété nous pouvons définir un listener ChangeListener qui sera activé quand la valeur de la propriété change. Par exemple un listener pour la propriété du modèle de la page précédente : C h a n g e L i s t e n e r <Number> m o d e l L i s t e n e r = new C h a n g e L i s t e n e r <Number >() { @Override p u b l i c v o i d c h a ng ed ( O b s e r v a b l e V a l u e <? e x t e n d s Number> o b s e r v a b l e , Number o l d v a l , Number n e w v a l ) { // m e t t r e a j o u r s l e s v i e w s quand l a p r o p r i e t e // du modele c h a n g e f o r ( UpdatableView view : views ){ v i e w . u p d a t e ( model . g e t E n t i e r ( ) ) ; // v i e w . u p d a t e ( n e w v a l . i n t V a l u e ( ) ) ; } } }; Enregistrer ChangeListener pour la propriété du modèle model . e n t i e r P r o p e r t y ( ) . a d d L i s t e n e r ( m o d e l L i s t e n e r ) ; Notez que ChangeListener était paramétré par un type qui dépend de type de la propriété. Propriété de contrôles Les contrôles sont des beans de javafx, par exemple : CheckBox ChoiceBox Slider etc BooleanProperty selected ObjectProperty<T> value DoubleProperty value Ces trois contrôles possèdent aussi d’autres propriétés et tous les contrôles possèdent de propriétés auxquelles on peut attacher ChangeListeners. ChoiceBoxView avec un ChangeListener p u b l i c c l a s s Ch oi ceBoxView e x t e n d s ChoiceBox<I n t e g e r > { p r i v a t e Model model ; // i n t L i s t s e r t a s t o c k e r l e s d o n n e e s de C h o i c e B o x O b s e r v a b l e L i s t <I n t e g e r > i n t L i s t ; { I n t e g e r [ ] i n t a = new I n t e g e r [ 1 6 ] ; int k = 1; f o r ( i n t i = 0 ; i < i n t a . l e n g t h ; i ++) { i n t a [ i ] = new I n t e g e r ( k ) ; k <<= 1 ; } i n t L i s t = FXCollections . observableArrayList ( inta ); } ChoiceBoxView avec un ChangeListener (suite) // c o n s t r u c t e u r p u b l i c Ch oi ceB oxV iew ( Model model ) { t h i s . model = model ; setItems ( intList ); // a t t a c h e r un C h a n g e L i s t e n e r v a l u e P r o p e r t y ( ) . a d d L i s t e n e r ( new C h a n g e L i s t e n e r <O b j e c t >() { @Override p u b l i c v o i d c h a n g ed ( O b s e r v a b l e V a l u e <? e x t e n d s O b j e c t > ov , Object o l d v a l , Object new val ) { model . s e t E n t i e r ( ( ( I n t e g e r ) n e w v a l ) . i n t V a l u e ( ) ) ; } }); Le modèle de ChoiceBox possède aussi la propriété selectedIndex, donc une autre possibilité consiste à attacher un ChangeListener au modèle (voir le tutorial sur ChoiceBox) : getSelectionModel ( ) . selectedIndexProperty () . a d d L i s t e n e r ( new C h a n g e L i s t e n e r <Number >() { @Override p u b l i c v o i d c h ang ed ( O b s e r v a b l e V a l u e <? e x t e n d s Number> ov , Number o l d v a l , Number n e w v a l ) { model . s e t E n t i e r ( i n t L i s t . get ( new val . intValue ( ) ) . intValue ( ) ) ; } }); Gestion d’evenements Évènement correspond souvent à une action de l’utilisateur : click de souris, taper sur le clavier, un geste sur l’écran tactile. Un évènement est une instance de javafx.event.Event. Les types évènements sont regroupés dans de classes d’évènements, dans chaque classe il y a plusieurs types d’évènements. Exemple : la classe KeyEvent contient les types : KEY_PRESSED, KEY_RELEASED, KEY_TYPED. Hiérarchie (partielle) d’évènements KeyEvent.KEY_PRESSED KeyEvent.KEY_RELEASED KeyEvent.KEY_TYPED | KeyEvent.ANY | |InputEvent.ANY| MouseEvent.ANY MouseEvent.MOUSE_PRESSED | MouseEvent.MOUSE_RELEASED Event.ANY -| MouseEvent.MOUSE_DRAGGED | [ActionEvent.ACTION | |WindowEvent.ANY----|WindowEvent.WINDOW_SHOWING |WindowEvent.WINDOW_SHOWN Propagation d’évènements Click sur un rectangle : Stage → Scene → BorderPane → Pane → Rectangle L’évènement se propage d’abord depuis Stage jusqu’au Rectangle (Event Capturing Phase) et ensuite dans le sens inverse depuis Rectangle jusqu’à Stage (Event Bubbling Phase). A chaque noeud (Node) nous pouvons associé des EventFilters et des EventHandlers appelés pour traiter l’évènement. Quelle est la différence entre un EventFilter et un EventHandler ? Un EventFilter est exécuté pendant Event Capturing Phase. Un EventHandler est exécuté pendant Event Bubbling Phase. Un noeud peut enregistrer plusieurs filtres, l’ordre d’exécution est basé sur la hiérarchie d’évènement, d’abord les filtres plus spécifiques ensuite plus généraux (MouseEvent.MOUSE_PRESSED avant MouseEvent.ANY). Un noeud peut enregistrer plusieurs handlers, l’ordre d’exécution est basé sur la hiérarchie d’évènement, d’abord les filtres plus spécifiques ensuite plus généraux (KeyEvent.KEY_TAPED avant KeyEvent.ANY). Arrêter la propagation d’un évènement La propagation d’un évènement peut-être arrêtée en exécutant la méthode event.consume() Un évènement consumé par un EventFilter ne passe pas dans la classe enfant, un évènement consumé par un EventHandler ne passe pas dans la classe parent. Si un noeud possède plusieurs EventFilters qui correspondent à un évènement alors même si cet évènement est consumé par un EventFilter tous les filtres seront quand même exécutés. Même chose pour EventHandlers. Construire et enregistrer EventFilters node . a d d E v e n t F i l t e r ( MouseEvent . MOUSE CLICKED , new E v e n t H a n d l e r <MouseEvent >(){ p u b l i c v o i d h a n d l e ( MouseEvent e v e n t ) { // i m p l e m e n t e r l e f i l t r e // e v e n t . consume ( ) ; } }); Noter que addEventFilter a deux paramètres : I un EventType et I un EventHandler. Construire et enregistrer EventHandlers node . a d d E v e n t H a d l e r ( KeyEvent . KEY TAPED , new E v e n t H a n d l e r <KeyEvent >(){ p u b l i c v o i d h a n d l e ( KeyEvent e v e n t ) { // i m p l e m e n t e r l e f i l t r e // e v e n t . consume ( ) ; } }); Noter que addEventHandler a les mêmes paramètres que addEventFilter. Enregistrer un seul EventHandler La classe Node (donc toutes les classes dérivées de Node) fournit des méthodes setOnNomHandler de commodité qui permettent d’enregistrer un seul handler, par exemple node . s e t O n M o u s e P r e s s e d ( new E v e n t H a n d l e r <MouseEvent >() { @Override p u b l i c v o i d h a n d l e ( f i n a l MouseEvent e v e n t ) { } }); Ces méthodes correspondent aux propriétés de la classe Node (par exemple MousePressedProperty, MouseDraggedProperty etc.). L’avantage de ces méthodes par rapport à ma méthode addEventHandler() c’est la simplicité, un seul argument à la place de deux arguments. Si vous voulez supprimer un EventHandler installé par une de méthodes setOn il suffit de passer l’argument null. La liste d’enfant d’un noeud Si on a un noeud (par exemple Pane) de type Parent on lui ajoute un enfant par pane . g e t C h i l d r e n ( ) . add ( e n f a n t ) ; Chaque parent possède une liste des enfants et getChildren() retourne cette liste. La méthode add() ajoute enfant à la fin de la liste. Quand le parent est rendu sur l’écran les enfants sont rendus dans l’ordre de leur apparition sur la liste des enfants, le premier celui en tête de la liste jusqu’au dernier, celui à la fin de la liste.