Interfaces graphiques - JavaFX
responsable : Wieslaw Zielonka
zielonka@[Link]
[Link]
March 2, 2016
Filtres et handlers
event capturing
event bubbling
Stage
Scene
BorderPane
MenuBar ToolBar
addEventFilter
Pane
ltres
EventHandler
Rectangle
EventHandler
handlers
EventHandler
Rectangle Circle ad
dE
ve
n tH
an
dle EventHandler
r
Construire, enregistrer et désenregistrer EventFilters
E v e n t H a n d l e r <MouseEvent> f i l t r e =
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 ( ) ;
}
};
// e n r e g i s t r e r
node . a d d E v e n t F i l t e r ( MouseEvent . MOUSE CLICKED , f i l t r e );
// d e s e n r e g i s t r e r
node . remove ( MouseEvent . MOUSE CLICKED , f i l t r e );
Construire, enregistrer/désenregistrer EventHandlers
E v e n t H a n d l e r <KeyEvent> h a n d l e r =
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 ( ) ;
}
};
// e n r e g i s t r e r
node . a d d E v e n t H a d l e r ( KeyEvent . KEY TAPED , h a n d l e r ) ;
// d e s e n r e g i s t r e r
node . r e m o v e E v e n t H a d l e r ( KeyEvent . KEY TAPED , h a n d l e r ) ;
Méthodes de commodité pour enregistrer un (seul)
EventHadler
Au lieu d’enregistrer un handler avec
node . a d d E v e n t H a n d l e r ( MouseEvent . MOUSE PRESSED ,
new E v e n t H a n d l e r <MousePressed >(){
p u b l i c v o i d h a n d l e ( MouseEvent e v e n t ) { . . . }
});
on peut utiliser une méthode de commodité :
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 <MousePressed >(){
p u b l i c v o i d h a n d l e ( MouseEvent e v e n t ) { . . . }
});
Les méthodes de commodité ont le nom setOnTypeEvenement.
Propriétés et ChangeListeners
CheckBox
BooleanProperty selected
ChangeListener<Boolean>
changed
checkBox . s e l e c t e d 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 <Boolean >(){
@Override
p u b l i c v o i d ch ang ed (
O b s e r v a b l e V a l u e <? e x t e n d s Boolean > o b s e r v a b l e ,
Boolean o l d v a l ,
Boolean new val ) {
.......
}
});
La liste d’enfant d’un noeud
Si on a un noeud (par exemple Pane) de type Parent on lui ajoute
un enfant avec add appliqué à la liste d’enfants :
pane . g e t C h i l d r e n ( ) . add ( e n f a n t ) ;
ObservableList<Node> getChildren() retourne la liste
d’enfants d’un noeud. 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.
La liste d’enfants
La liste obtenue par l’appel getChidren() est une vraie liste,
toutes les opérations habituelles sur les listes sont disponibles.
Par exemple : supprimer le dernier élément de la liste d’enfants :
L i s t l = pane . g e t C h i l d r e n ( ) ;
l . remove ( l . s i z e ( ) − 1 ) ;
L’ordre d’affichage d’enfants
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.
Systèmes de coordonnées en JavaFX
Trois types de coordonnées :
I locales par rapport au noeud,
I scene - coordonnées par rapport à la scène,
I screen – coordonnées par rapport à l’écran.
Systèmes de coordoonnées
en
x
re
sc
e
en
sc
e
gl
an
ct
Re
e
ld
ca
lo
y
Les systèmes de coordonnées
MouseEvent possède les méthodes
I double getX(), double getY(),
I double getSceneX(), double getSceneY(),
I double getScreenX(), double getScreenY(),
qui donnent les coordonnées de l’évènement dans
I le système de coordonnées locales d’un noeud source de
l’événement,
I par rapport au système de coordonnées de la scène,
I par rapport au système de coordonnées de l’écran.
La classe Node possède les méthodes
localToParent()
localToScene()
localToScreen()
qui permettent d’obtenir les coordonnées dans le système parent,
scène, l’écran à partir de coordonnées locaux d’un point.
Fabriquer un noeud ”draggable”
p r i v a t e Node m a k e Dr ag gab le ( Node node ) {
class T {
do u b l e i n i t i a l T r a n s l a t e X , i n i t i a l T r a n s l a t e Y ,
anchorX , anchorY ;
}
f i n a l T t = new T ( ) ;
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 ) {
t . i n i t i a l T r a n s l a t e X = node . g e t T r a n s l a t e X ( ) ;
t . i n i t i a l T r a n s l a t e Y = node . g e t T r a n s l a t e Y ( ) ;
Point2D p o i n t = node . l o c a l T o P a r e n t ( e v e n t . getX ( ) ,
e v e n t . getY ( ) ) ;
t . anchorX = p o i n t . getX ( ) ;
t . anchorY = p o i n t . getY ( ) ;
}
});
Fabriquer un noeud ”draggable” (suite)
node . setOnMouseDragged ( 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 ) {
Point2D p o i n t = node . l o c a l T o P a r e n t ( e v e n t . getX ( ) ,
e v e n t . getY ( ) ) ;
node . s e t T r a n s l a t e X ( t . i n i t i a l T r a n s l a t e X −
t . anchorX + p o i n t . getX ( ) ) ;
node . s e t T r a n s l a t e Y ( t . i n i t i a l T r a n s l a t e Y −
t . anchorY + p o i n t . getY ( ) ) ;
}
});
r e t u r n node ;
}
Propriété de translation
Propriétés de transltion d’un noeud dans les coordonnées locales :
DoubleProperty translateX , translateY , t r a n s l a t e Z
que son parent utilise pour déterminer où dessiner le noeud.
Utiliser ColorPicker
C o l o r s h a p e C o l o r = C o l o r . BLACK ;
C o l o r P i c k e r p i c k e r = new C o l o r P i c k e r ( s h a p e C o l o r ) ;
p i c k e r . s e t O n A c t i o n ( new E v e n t H a n d l e r <A c t i o n E v e n t >() {
@Override
public void handle ( ActionEvent e ) {
Color c = picker . getValue ( ) ;
i f ( c != n u l l ) {
shapeColor = c ;
}
}
});
Faire un bord autour de Pane
pane . s e t B o r d e r ( new B o r d e r ( new B o r d e r S t r o k e (
C o l o r . RED,
B o r d e r S t r o k e S t y l e . SOLID ,
C o r n e r R a d i i .EMPTY,
new B o r d e r W i d t h s ( 3 ) ) ) ) ;
Clipping région
Un Rectangle mis dans Pane est dessiné même s’il sort de ce Pane
!!!
Solution : définir ”clip” région dans Pane en utilisant la propriété :
O b j e c t P r o p e r t y <Node> c l i p
Par exemple :
pane . s e t P r e f S i z e ( 4 0 0 , 4 0 0 ) ;
R e c t a n g l e c l i p = new R e c t a n g l e ( 4 0 0 , 4 0 0 ) ;
pane . s e t C l i p ( c l i p ) ;
Clipping région (suite)
Problème : on veut que la taille de clipping région soit toujours la
même que la taille de Pane, c’est-à-dire les propriétés height et
width du Rectangle soit toujours égales aux mêmes propriétés de
Pane.
Première solution : utiliser ChangeListener attachés aux propriétés
width et height de Pane et modifie width et height de Rectangle.
Mais on peu bien mieux avec bind:
c l i p . h e i g h t P r o p e r t y ( ) . b i n d ( pane . h e i g h t P r o p e r t y ( ) ) ;
c l i p . w i d t h P r o p e r t y ( ) . b i n d ( pane . w i d t h P r o p e r t y ( ) ) ;
Les changements de propriétés de clip suivent automatiquement les
changements de propriétés de pane.
Créer un Text
Text t = new Text ( ) ;
t . s e t F o n t ( Font . f o n t ( ” Verdana ” , 2 0 ) ) ;
t . s e t F i l l ( s h a p e C o l o r ) ; // c o l o r
t . setX ( cx ) ; t . s e t Y ( c y ) ; // p o s i t i o n
t . setText ( s t r i n g ) ;
pane . g e t C h i l d r e n ( ) . add ( t ) ;
Récupérer KeyEvents
// i n s t a l l e r un f i l t r e ( ou un h a n d l e r )
pane . a d d E v e n t F i l t e r ( KeyEvent . KEY TYPED , k e y F i l t e r ) ;
pane . s e t F o c u s T r a v e r s a b l e ( t r u e ) ;
Le contrôle qui possède un filtre ou handler pour l’évènement
KeyEvent doit posséder le focus pour recevoir ces évènements.
Mais Pane ne peut pas avoir de focus sauf si on le rend ”focus
traversable” par
[Link](true);
Une fois pane est ”focus traversable” on peut demander le focus
avec
[Link]()
Définir un filtre ou handler pour le clavier
E v e n t H a n d l e r <KeyEvent> k e y E v e n t H a n d l e r
= 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 ( f i n a l KeyEvent k e y E v e n t ) {
// r e c u p e r e r l e c a r a c t e r e t a p e s u r l e c l a v i e r
String s = event . getCharacter ( ) ;
i f ( event . isControlDown ( ) ) {
System . e r r . p r i n t l n ( ”CONTROL DOWN” ) ;
}
} };
Si l’évènement est de type [Link] TYPED alors la méthode
[Link]() retourne un String contenant le
caractère tapé par l’utilisateur sur le clavier.
Pour les évènements KEY PRESSED et KEY RELEASED cette
méthode retourne toujours CHAR UNDEFINED, donc elle est inutile
pour ces deux évènements.
La classe KeyEvent possède les méthodes booléennes
isControlDown(), isAltDown(), isShiftDown(),
isMetaDown() qui permettent de tester si on a appuyé sur une de
ces touches.
KeyEvent possède aussi la méthode
KeyCode getCode()
qui retourne le code de la touche tapé par l’utilisateur.
Mais cela ne concerne que les évènements
[Link] PRESSED et [Link] RELEASED. Pour
l’évènement [Link] TYPED cette méthode retourne
toujours [Link].
les effets visuels
I Blend Effect
I Bloom Effect
I Blur Effects
I Drop Shadow Effect
I Inner Shadow Effect
I Reflection
I Lighting Effect
I Perspective Effect
Mis en oeuvre
Text t = new Text ( ) ;
t . s e t T e x t ( ” B l u r r y Text ! ” ) ;
t . s e t F i l l ( C o l o r . RED ) ;
t . s e t F o n t ( Font . f o n t ( ” n u l l ” , FontWeight . BOLD, 3 6 ) ) ;
// p r e p a r e r l ’ e f f e t
B o x B l u r bb = new B o x B l u r ( ) ;
bb . s e t W i d t h ( 5 ) ;
bb . s e t H e i g h t ( 5 ) ;
bb . s e t I t e r a t i o n s ( 3 ) ;
// s e t E f f e c t
t . s e t E f f e c t ( bb ) ;