Vous êtes sur la page 1sur 12

Base de connaissance sur

Flex
Table des matières

1. Introduction........................................................................................................................3
2. Empêcher la saisie dans un champ de saisie simple.........................................................3
3. Précaution d’utilisation des dataProvider dans les arbres..................................................3
4. Journalisation des évènements..........................................................................................4
5. Appels de WebService asynchrones.................................................................................4
6. La méthode ValidateNow()................................................................................................6
7. Appliquer un lissage de qualité sur un objet Image............................................................7
8. Comment forcer le Garbage Collecting..............................................................................8
9. Focus sur la barre d’adresse d’Internet Explorer...............................................................9
10. Désactivation de la tabulation standard Flex....................................................................9
11. Contournement du bug de molette dans Flash................................................................9
12. Focus sur le plugin Flash...............................................................................................11
13. Menu contextuel épuré..................................................................................................12
1. Introduction
Ce document regroupe divers astuces collectées pendant les développements de l’application
FMFB qui permettent de faire gagner du temps lors des prochains développements.

2. Empêcher la saisie dans un champ de saisie simple


Dans l’application FMFB, il est parfois nécessaire d’intercepter une touche dans un
champ de saisie et de l’empêcher de s’afficher. Pour cela Flex n’a pas prévu de mécanisme
permettant d’empêcher la remonter d’un évènement clavier dans un TextInput. L’astuce qui va
suivre permet de résoudre cette problématique de manière propre côté interface utilisateur (sans
clignotement ou autre effet visuels dérangeant).
Pour comprendre cette technique il faut connaître trois évènements successifs susceptibles
d’être reçus par les objets UITextField :
 KeyboardEvent.KEY_DOWN : lors de l’enfoncement de la touche
 Event.CHANGE : lors du changement de la valeur du champ
 TextEvent.TEXT_INPUT : lorsque la valeur a été modifiée

Le champ de type UITextField est accessible dans l’objet TextInput par la méthode :
input.mx_internal ::getTextField() dans le champ de type ComboBox par
_combo.mx_internal::getTextInput().mx_internal::getTextField(). Pour
empêcher l’affichage d’une touche saisie il faut donc séquentiellement :
 Précédemment le texte de l’input ainsi que la position du curseur aura été sauvegardé sur
l’évènement TEXT_INPUT.
 Déclencher les traitements sur l’évènement KEY_DOWN (par exemple vidage du champ sur
saisie dans la touche – du pavé numérique). Indiquer par une variable du contrôle que la
touche ne doit pas être affichée.
 Sur l’évènement CHANGE si la touche ne doit pas être affichée on remet le texte précédent
et on repositionne le curseur à la position précédemment sauvegardée
(getTextField().setSelection(savedCaretIndex, savedCaretIndex)).

3. Précaution d’utilisation des dataProvider dans les arbres


Dans Flex 2 il est fortement déconseillé d’utiliser le dataProvider comme référence des
nœuds de l’arbre une fois que celui-ci a été affecté. En effet, l’affectation du champ dataProvider
d’un composant déclenche une cascade de traitement qui démantèle le dataProvider pour le
stoquer en interne sous une autre forme. A la relecture du champ les données XML sont donc
reconstruites et l’accès à un nœud de l’arbre par son nœud XML n’est plus possible. Pour éviter
cet inconvénient, il est conseillé de sauvegarder le XML ayant servi à alimenté le dataProvider
pour s’en servir de référence.
Il est déconseillé de réaffecté le dataProvider trop fréquemment, cette opération pouvant être
couteuse. Il est préférable de manipuler l’objet XML ayant servi de source à l’arbre pour de
simple opération de suppression de nœud ou de déplacement.
4. Journalisation des évènements
Il est possible dans Flex d’intercepter tous les évènements concernant les UIComponent
et d’éventuellement les journaliser. Le code ci-dessous illustre ce mécanisme :

import mx.core.mx_internal;

private static function hookDispatchEvent():Boolean


{
UIComponent.mx_internal::dispatchEventHook = logEventHook;
return true;
}

private static function logEventHook( event:Event, uic:UIComponent ):void


{
trace(event.toString()+" event dispatched from "+ uic.toString()+ " to
"+event.currentTarget);
}

Les traces générées indiquent le nom de l’évènement, la source de l’évènement et l’éventuel


objet l’interceptant.

5. Appels de WebService asynchrones


Un problème récurent avec les objets WebService est le risque de conflit lors de l’appel
de plusieurs WebService en simultanée. En effet, les réponses n’arrivent pas forcément dans le
même ordre que les questions. Pour palier à ce problème, il existe l’objet AsyncToken qui peut
servir de transporteur d’information entre la question et la réponse. Celui-ci est créé à l’appel du
WebService (retourné par la méthode « send ») et on peut lui ajouté des propriétés qui seront
récupérable dans le ResultEvent, cf exemple ci-dessous :
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Script>
<![CDATA[
import mx.rpc.AsyncToken;
import mx.controls.Alert;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.soap.WebService;

/** Gestion de la réponse du WebService */


private function onSuccess(response:ResultEvent):void
{
// on affiche la réponse du serveur ainsi que la propriété
// passée dans le token
echo.text = String(response.result+" "+response.token.myProperty);
}

/** En cas d'erreur on affiche une pop-up */


private function onFault(fault:FaultEvent):void
{
Alert.show(fault.fault.faultString);
}

/** Sur click du bouton on appelle le web service */


private function shout():void
{
var webService:WebService = new WebService();

webService.loadWSDL("http://localhost/Share/servlet/XFireServlet/FlexViewer?
wsdl");
webService.echo.addEventListener(ResultEvent.RESULT, onSuccess);
webService.echo.addEventListener(FaultEvent.FAULT, onFault);
// on appelle la méthode et on récupère l'AsyncToken
var token:AsyncToken = webService.echo(yell.text);
// on crée une propriété personnalisée qu'on récupérera
// dans la réponse
token.myProperty = new Date().getTime();
}
]]>
</mx:Script>
<mx:Button x="291" y="44" label="Crier" click="shout()"/>
<mx:TextInput x="102" y="29" id="yell"/>
<mx:TextInput x="102" y="59" id="echo"/>
<mx:Text x="10" y="31" text="Saisir l'écho"/>
<mx:Text x="10" y="61" text="Réponse"/>

</mx:Application>
6. La méthode ValidateNow()

Flex est une technologie très optimisée qui est capable d’accumuler les traitements graphique
pour les exécuter de manière fluide, évitant ainsi les clignotements ou autres artefact visuels.
Ceux-ci sont « mis en attente » et exécutez entre 2 traitements interactifs. Il est donc important
de savoir que la modification d’une propriété impactant le visuel d’un UIComponent ne peut être
suivie d’une relecture de la propriété elle-même ou d’autres liées aux composants fils, par
exemple :

<?xml version="1.0" encoding="utf-8"?>


<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Script>
<![CDATA[
import mx.controls.Alert;
// redimensionne et mesure la taille du contenu de l'image sans avoir
fait un validateNow
private function resizeNoValidateNow():void
{
myImage.height = myImage.height / 2;
Alert.show("myImage.height = "+myImage.contentHeight);
}
// redimensionne et mesure la taille du contenu de l'image après avoir
fait un validateNow
private function resizeValidateNow():void
{
myImage.height = myImage.height / 2;
myImage.validateNow();
Alert.show("myImage.height = "+myImage.contentHeight);
}
// remise à zero du test
private function reset():void
{
myImage.height = 432;
}
]]>
</mx:Script>
<mx:Image x="10" y="10" width="585" height="432" autoLoad="true"
scaleContent="true" id="myImage">
<mx:source>file:///C|/Documents and Settings/epa/My
Documents/1610FF0908760A4A3C24EE2B9FFDF0E6ite1458855_~img_p0_w2378_r0.png</mx:
source>
</mx:Image>
<mx:Button x="10" y="459" label="Resize without ValidateNow"
click="resizeNoValidateNow()"/>
<mx:Button x="431" y="459" label="Resize with ValidateNow"
click="resizeValidateNow()"/>
<mx:Button x="270" y="459" label="Reset" click="reset()"/>
</mx:Application>
Dans le détail la fonction appelle sur le composant et tous ses enfants les 6 méthodes
suivantes :
 validateProperties() : Appelle commitProperties
 commitProperties() : Effectue le calcul des propriétés si celle-ci sont interdépendantes
 validateSize() : Calcul les dimensions du composant
 measure() : Calcul les dimensions par défaut du composant
 validateDisplayList() : Ajuste les composants situés à l’intérieur du composant courant
 updateDisplayList() : Dessine le composant et ses enfants

7. Appliquer un lissage de qualité sur un objet Image


L’objet Flex standard pour charger les images s’appelle mx.controls.Image. Il permet des
manipulations simples telles que rotation, redimensionnement, effets. Malheureusement les
effets sont appliqués après les redimensionnements, il est donc très difficile d’appliquer un effet
de lissage à l’image en pleine taille pour optimiser la qualité. Il faut, donc, manipuler le
BitmapData de l’image directement en accédant à la propriété content de l’Image. Ci-dessous
un exemple :

<?xml version="1.0" encoding="utf-8"?>


<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Script>
<![CDATA[
// filtrage du contenu de l'image dans sa taille d'origine, précision
accrue
private function qualityFilter(event:Event = null):void
{
if (event==null)
{
invoice.addEventListener(Event.COMPLETE, qualityFilter);
invoice.load();
invoice.filters = null;
}
else
{
invoice.removeEventListener(Event.COMPLETE, qualityFilter);
var bitmap:Bitmap = Bitmap(invoice.content);
// activation du lissage hardware de Flash si les dimensions sont
multiples de 4 ou 8
bitmap.smoothing = true;
// filtrage de l'image amélioré en plus du smoothing
bitmap.bitmapData.applyFilter(bitmap.bitmapData,
new Rectangle(0, 0, bitmap.bitmapData.width, bitmap.bitmapData.height),
new Point(0,0),
new BlurFilter(1.4, 1.4, BitmapFilterQuality.MEDIUM));
}
}
// filtrage du contenu de l'image réduit, précision faible
private function standardFilter(event:Event = null):void
{
if (event==null)
{
invoice.addEventListener(Event.COMPLETE, standardFilter);
invoice.load();
}
else
{
invoice.removeEventListener(Event.COMPLETE, standardFilter);
var filter:BlurFilter = new BlurFilter(1.4, 1.4,
BitmapFilterQuality.MEDIUM);
invoice.filters = [filter];
}
}
]]>
</mx:Script>
<mx:Image x="0" y="0" width="100%" height="90%" source="../invoice.png"
id="invoice" />
<mx:Button label="Floutage de qualité" bottom="24" left="10"
click="qualityFilter()"/>
<mx:Button label="Floutage standard" bottom="24" left="153" width="130"
click="standardFilter()"/>
</mx:Application>

8. Comment forcer le Garbage Collecting


Lors d’opération manipulant de grosse quantité de mémoire, il peut être utile de forcer le
garbage collecting pour alléger la mémoire du navigateur. Il n’existe malheureusement pas
d’instruction spéciale pour déclencher cette opération. Le code ci-dessous provoque une
réorganisation de la mémoire par effet de bord :

try {
new LocalConnection().connect('foo');
new LocalConnection().connect('foo');
} catch (e:*) {}
9. Focus sur la barre d’adresse d’Internet Explorer
Par défaut le plugin Flash sous Internet Explorer permet de tabuler en dehors d’une
application Flex pour changer l’adresse du site. Malheureusement sur certaine application ce
comportement est plus perturbant que pratique. Pour désactiver ce mécanisme il suffit d’ajouter
le paramètre suivant dans la déclaration du plugin dans la page HTML :

AC_FL_RunContent(
"src", "${swf}",
"width", "${width}",
"height", "${height}",
"align", "middle",
"id", "${application}",
"quality", "high",
"bgcolor", "${bgcolor}",
"name", "${application}",
"SeamlessTabbing","false",
"flashvars",'stamp=' + stamp + '&historyUrl=history.htm%3F&lconid=' +
lc_id + '',
"allowScriptAccess","sameDomain",
"type", "application/x-shockwave-flash",
"pluginspage", "http://www.adobe.com/go/getflashplayer"

L’exemple ci-dessus est repris de la page HTML générée par Flex, « SeamlessTabbing » à
« false » signifie qu’il n’est pas possible de sortir du plugin avec les tabulations, le focus reste
constamment à l’intérieur.

10. Désactivation de la tabulation standard Flex


Pour définir un mécanisme de tabulation personnalisé qui ne tient pas compte des
« taborder » des champs, il est nécessaire de désactiver le comportement standard. Pour cela, il
suffit de mettre la propriété « tabChildren » du DisplayObjectContainer contenant les contrôles à
« false ».

DisplayObjectContainer(getComponent()).tabChildren = false;

11. Contournement du bug de molette dans Flash


Sur certaines machines un logiciel gestionnaire de souris tourne en tâche de fond et
détourne le comportement standard de la molette. C’est notamment le cas des nouvelles
machines Dell. La conséquence sur le plugin Flash et l’impossibilité de recevoir les évènements
MouseEvent.MOUSE_WHEEL. Pour contourner ce problème le code JavaScript ci-dessous
permet d’appeler une méthode ActionScript dans l’application Flex :
/* SWFMouseWheel v1.0 alpha1 <http://oysteinwika.com/swfmousewheel/>
This software is released under the MIT License
<http://www.opensource.org/licenses/mit-license.php>
*/

var jsReady = false;

function isReady()
{
return jsReady;
}

function pageInit()
{
jsReady = true;
}

function getSWF(id)
{
return (navigator.appName.indexOf("Microsoft") != -1) ? window[id] :
document[id];
}

function sendToAS(val)
{
if (val<50 && val>-50)
{
getSWF('WebIndexing').jsdelta(val);
}
}

function handler(delta)
{
if (delta < 0)
{
sendToAS(delta);
}
else
{
sendToAS(delta);
}
}

function wheel(event)
{
var delta = 0;
if (!event) event = window.event;
if (event.wheelDelta)
{
delta = event.wheelDelta/120;
if (window.opera)
{
delta = delta;
}
}
else if (event.detail)
{
delta = -event.detail/3;
}
if (delta)
{
value = Math.round(delta)
handler(value);
}
if (event.preventDefault)
{
event.preventDefault();
}
event.returnValue = false;
}

if (window.addEventListener) window.addEventListener('DOMMouseScroll', wheel,


false);
window.onmousewheel = document.onmousewheel = wheel;

Le code Flex correspondant est le suivant :

ExternalInterface.addCallback("jsdelta",wheelZoom);
public function wheelZoom(delta:Number):void
{
// do something with the delta
}

La fonction Flex « wheelZoom » est appelé à chaque tour de molette quelque soit la
position du curseur de la souris. Il convient donc de tester le positionnement du curseur de la
souris avec la méthode « hitTest » avant tout traitement.

12. Focus sur le plugin Flash


Pour permettre la saisie immédiate dans un champ de formulaire Flex il est nécessaire
de donner le focus au plugin Flash au chargement de la page HTML sinon les touches saisies
sont interprétées par le navigateur et non le plugin. Pour déclencher la prise de focus, il faut que
le plugin soit complètement chargé. La meilleure méthode pour s’assurer que ce soit le cas est
d’appeler la méthode de focus à partir de Flex dans l’initialisation de l’application. Ci-dessous se
trouve un exemple de code :

ExternalInterface.call("focusBrowser");

Côté JavaScript cela donne :

function focusBrowser()
{
document.${application}.focus();
}
Ce mécanisme fonctionne à partir d’Internet Explorer 6 et Firefox 3.

13. Menu contextuel épuré


Par défaut Flex affiche un menu contextuel assez riche sur le click droit de la souris. Ce
menu peut amener les utilisateurs à avoir accès à des actions peu recommandées comme le
zoom qui risque de planter l’application. Pour palier à ce problème il suffit de cacher toutes les
actions facultatives au niveau des deux plus hauts objets dans la hiérarchie d’objets graphiques
de l’application Flex.
Le premier de ces objets est de type mx.core.Application (instance
application). Il est le père de tous les composants Flex, donc en théorie de tous les
composants graphique de l’application. Malheureusement certains composants comportants des
animations échappent à cette hérarchie comme les menus déroulants, les curseurs. On ne
peux, donc, contrôler l’état de tous les menu contextuels directement depuis application.
Pout cela il faut « complèter » en utilisant l’objet de type SystemManager appelé
systemManager qui est le père de tous les objets Flash (ancêtres des objets Flex). Il faut le
transtyper en MovieClip pour pouvoir affecter la propriété contextMenu.
Ces deux objets possèdent une propriété contextMenu qu’il suffit d’affecter comme décrit
ci-dessous :

application.contextMenu = new ContextMenu();


application.contextMenu.hideBuiltInItems();
MovieClip(systemManager).contextMenu = application.contextMenu.clone();