Apache Adobe Flex TutorialTutoriaux Adobe Flex & AIR en Français

11juin/114

AIR Mobile – Application Pokémon (5) – Liste des Pokémon depuis la BDD SQLite

Dans les tutoriaux Flex précédents, on a vu comment ouvrir la base de données SQLite et comment lancer notre projet dans l'émulateur:

AIR Mobile – Application Pokémon (3) – Ouverture de la BDD SQLite

AIR Mobile – Application Pokémon (4) – Lancer l'application dans l’émulateur + debugger

On va maintenant travailler sur notre première vue et afficher la liste des pokémons. Pour cela, on va effectuer une requête SQL (SELECT) et afficher le résultat dans un composant List.

Effectuer le traitement au bon moment

Avant d'effectuer notre requête SELECT, il faut savoir à quel moment on va la faire. En effet, si vous avez suivi l'article sur le cycle de vie des View en Flex, vous savez que celle-ci propage des évènements lors de sa création et de sa destruction.

Les évènements qui vont nous intéresser sont:

  • creationComplete : Propagé quand tous les composants de la vue (comme notre List) sont instanciés et accessible. La vue n'est pas encore affichée à l'écran mais vous pouvez la manipuler
  • viewActivate : Propagé après "creationComplete", une fois que la transition entre les vues est terminée.

Alors lequel utiliser? Et bien cela dépend. En effet, si vous effectuez trop de traitement lors du "creationComplete", la transition de la vue va peut-être saccader. Mais en même temps, si vous faîtes votre traitement sur "viewActivate", il sera presque "trop tard" et si votre traitement est d'afficher / masquer des composants, votre vue va légèrement clignoter. A vous donc de voir et de choisir la meilleure solution, c'est à dire la plus adaptée à votre utilisation.

Pour cette première vue, ce n'est pas très important car en fait, la première vue n'arrive pas avec une transition. Que vous soyez sur "creationComplete" ou sur "viewActivate" ne fera donc que très peu de différence. Mais si on était sur une autre vue, sur laquelle on arrive par une transition, on aurait sûrement mis notre SELECT sur l'évènement "viewActivate" car nous effectuons nos requêtes en mode synchrone. Si nous l'avions ouverte en mode asynchrone, on aurait utilisé "creationComplete" plutôt. Voilà le genre de question qu'il faut se poser, souvent résolues par de rapides tests.

Récupérer la connexion SQL (SQLConnection)

Ouvrez donc le fichier "PokemonInfosHomeView.mxml" qui est notre première vue. Comme vous l'avez fait dans la 3eme partie du tutorial, ajouter un écouteur d'évènement sur "creationComplete" que vous allez appeler "onCComplete". De la même manière, laissez-vous guider par Flash Builder:

<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
        xmlns:s="library://ns.adobe.com/flex/spark" title="HomeView"
        creationComplete="onCComplete(event)">
  <fx:Script>
    <![CDATA[
      import mx.events.FlexEvent;

      protected function onCComplete(event:FlexEvent):void
      {

      }

    ]]>
  </fx:Script>
  <fx:Declarations>
    <!-- Place non-visual elements (e.g., services, value objects) here -->
  </fx:Declarations>
</s:View>

Première chose que l'on va faire dans onCComplete, on va récupérer la connexion SQL que l'on avait ouvert dans la partie 3 du tutorial. Notre connexion est conservée au niveau de l'application. Celle ci peut être accédée depuis n'importe quel endroit grâce à la variable static:

FlexGlobals.topLevelApplication

Pour éviter de récupérer à chaque fois la référence vers notre SQLConnection depuis notre application, on va conserver une référence directement dans notre vue:

import mx.core.FlexGlobals;
  import mx.events.FlexEvent;

  private var _sqlConnection:SQLConnection = null;

  protected function onCComplete(event:FlexEvent):void{
	_sqlConnection = FlexGlobals.topLevelApplication.sqlConnection;
  }

Ajouter le composant List

Pour avoir un affichage visuel de notre liste de pokémons, on va ajouter un composant List. Pour une liste des composants (non exhaustive) des composants du SDK 4.5, je vous conseille de lire cet article:

AIR Mobile – Les composants et le thème Mobile Flex 4.5

Rendez-vous donc entre la fin du tag fx:Declaration et la fin du tag View puis tapez le caractère "<". Appuyez sur Ctrl+Espace et la liste des composants disponibles va s'afficher. Tapez "List" puis appuyez sur Entrée:

list

Appuyez sur Espace et la liste des propriétés du composant va s'afficher. Vous pouvez commencer à taper le nom des propriétés comme "width" ou "height" et valider par Entrée. Comme exercice, on va fixer les propriétés "width" et "height" à la valeur "100%". Cela signifie que notre liste va prendre toute la place offerte par son conteneur, la vue.

Une fois que vous avez terminé, fermez le tag avec un chevron fermant ">". Le tag XML </s:List> fermant la balise sera automatiquement ajouté:

<s:List width="100%" height="100%">

  </s:List>

Le composant List et la propriété "dataProvider"

Notre composant List est un composant graphique permettant d'afficher de la donnée. Pour définir quelle donnée doit être affichée dans ce composant, on renseigne la propriété "dataProvider". Ce "dataProvider" est de type IList. Comme vous pouvez le voir dans la documentation, dans la partie "Implementors", les classes qui implémentent IList sont ArrayList, AsyncListView, ListCollectionView et les classes qui en héritent.

Remplis sous: Adobe Air, List Lire la suite
31mai/100

Flex MenuBar – Bug lors de l'utilisation de sous-menus multiples ne comportant qu'un enfant

Voici un bug de Flex 3 "quasi" impossible à corriger. Après y avoir passé une après-midi complète, j'ai trouvé une solution de remplacement, pas très belle mais qui fonctionne (sous certaines conditions). J'ai pourtant bien cherché sur le net, il semble que personne ne soit tombé sur ce bug, pourtant facile à reproduire.

Si vous avez une solution plus "propre", n'hésitez pas à la soumettre :) .

Le Bug en question se produit lors de l'utilisation d'un composant MenuBar. Celui-ci prend un dataProvider hiérarchique (XML ou ArrayCollection).

Notez que les classes suivantes ont été créées pour l'exemple. Dans la vraie vie, on fera peut-être plus attention sur certains points.

Dans notre exemple, on va prendre la classe Model suivante:

package {
  import mx.collections.ArrayCollection;

  [Bindable]
  [DefaultProperty("children")]
  public class MenuItem {
    public function MenuItem() {
    }

    public var label:String = null;
    public var type:String = null;
    public var children:ArrayCollection = null;

  }
}

On a ensuite notre application utilisant une MenuBar. Celle-ci est remplie avec des MenuItem, de manière hiérarchique:

  • Menu 1
  • Menu 2
    • Sub Item 1
      • Sub Sub Menu 1
        • Sub Sub Sub Menu 1
  • Menu 3

Dans notre application, on construit donc ce menu:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:local="*"
                viewSourceURL="srcview/index.html">
  <mx:MenuBar>
    <local:MenuItem label="Menu 1"/>
    <local:MenuItem label="Menu 2">
      <mx:ArrayCollection>
        <local:MenuItem label="Sub Menu 1">
          <mx:ArrayCollection>
            <local:MenuItem label="Sub Sub Menu 1">
              <mx:ArrayCollection>
                <local:MenuItem label="Sub Sub Sub Menu 1"/>
              </mx:ArrayCollection>
            </local:MenuItem>
          </mx:ArrayCollection>
        </local:MenuItem>
      </mx:ArrayCollection>
    </local:MenuItem>
    <local:MenuItem label="Menu 3"/>
  </mx:MenuBar>
</mx:Application>

Et voici le résultat:

Flex Source Code Download: Télécharger le code source complet de l'application

This movie requires Flash Player 11

Vous l'avez peut-être remarqué, on a perdu "Sub Sub Menu 1" en route! Mais voici un deuxième exemple plus troublant. On rajoute un item au même niveau que Sub Sub Menu 1, que l'on va appeler Sub Sub Menu 2:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:local="*"
                viewSourceURL="srcview/index.html">
  <mx:MenuBar>
    <local:MenuItem label="Menu 1"/>
    <local:MenuItem label="Menu 2">
      <mx:ArrayCollection>
        <local:MenuItem label="Sub Menu 1">
          <mx:ArrayCollection>
            <local:MenuItem label="Sub Sub Menu 1">
              <mx:ArrayCollection>
                <local:MenuItem label="Sub Sub Sub Menu 1"/>
              </mx:ArrayCollection>
            </local:MenuItem>
            <local:MenuItem label="Sub Sub Menu 2"/>
          </mx:ArrayCollection>
        </local:MenuItem>
      </mx:ArrayCollection>
    </local:MenuItem>
    <local:MenuItem label="Menu 3"/>
  </mx:MenuBar>
</mx:Application>

Voici le résultat:

Flex Source Code Download: Télécharger le code source complet de l'application

This movie requires Flash Player 11

Notre "Sub Sub Menu 1" est de retour... C'est à partir de ce moment, qu'il faut commencer à s'accrocher car comme vous l'avez vu, on utilise le composant de base de Flex 3 MenuBar. Pour trouver la cause du problème, il va donc falloir aller fouiller dans le code source de Flex à grands coups de point d'arrêt.

10jan/100

Flex Chart – Utilisation des fills, des stroke et des fillFunction dans les Charts

Tutorial écrit par Serge Boujo

Agir sur le choix des couleurs dans les Charts

J’ai eu à agrémenter des résultats de graphiques, pour lesquels je souhaitais utiliser des couleurs autres que celles proposées en standard par Flex.
Du fait d’une lecture incomplète de la documentation, j’ai utilisé une FillFunction sans chercher plus loin : j’arrivais à fixer les couleurs pour le graphe, mais non pour la légende.

Flex Source Code Download: Télécharger le code source complet de l'application

This movie requires Flash Player 11

La démarche à proscrire

J’ai utilisé une fillFunction pour afficher mes secteurs en rouge et en vert.
Lors de la déclaration de la Legend, ayant spécifié mon Chart en tant que dataProvider, j’étais persuadé que les couleurs affichées dans la Legend suivraient.

La lecture du code de la fonction confirme l’inadéquation de la solution : on remarque que le paramètre item n’est pas utilisé, mais surtout que le résultat renvoyé dépend uniquement du rang de la valeur au sein de la série, trahissant l’esprit d’une fillFunction.

Un petit rappel de la doc:

The signature of the fillFunction is as follows:

function_name(element:ChartItem, index:Number):IFill { ... }

The following table describes the arguments:

  • element: The chart item for which the fill is created; type ChartItem.
  • index: The index of the chart item in the series's data provider; type Number.

L’exemple de fillFunction ci-dessus fixe en même temps teinte et alpha de la SolidColor, mais il est tout à fait possible de n’intervenir que sur l’un des deux. Le code deviendrait alors, si l’on ne voulait jouer que sur l’opacité.

private function myFillFunc(item:PieSeriesItem, index:Number) : IFill {
  var coul: SolidColor   = new SolidColor(0xDDDDDD);
  if (index == 0){
    coul.alpha = 1.0
  }else {
    coul.alpha = 0.4;
  }
  return coul;
}

Utilisation correcte des fills, des stroke et des fillFunctions dans les Charts

Les erreurs que j’ai commises et décrites dans mon précédent tuto m’ont incité à creuser la question ; une relecture soigneuse et approfondie de la documentation de Flex m’a permis d’y voir un peu plus clair.

La démarche correcte consiste en l’abandon de cette fillFunction et en l’utilisation de fills.

Pour ceux qui veulent approfondir, on peut également fixer des stroke différents pour le tour et pour les séparations des pies.

18août/090

Flex AdvancedDataGrid – Appel de validateNow() après avoir setté le dataProvider (sync)

Dans certaines situations, vous allez fixer la valeur de la propriété dataProvider d'un AdvancedDataGrid et immédiatement essayer d'effectuer une action basée sur la valeur du nouveau dataProvider. Cela se produit souvent quand vous fixez la valeur du dataProvider en ActionScript, comme par exemple:

adg.dataProvider = groupedCollection;
adg.expandAll();

Dans cet exemple, l'appel à la méthode expandAll() va échouer car le composant AdvancedDataGrid est en train de fixer la propriété dataProvider, et la méthode expandAll() essaie soit de traiter l'ancienne valeur de dataProvider si elle existant ou ne fait rien.

Dans cette situation, vous devez insérer la méthode validateNow() après avoir setté le dataProvider. La méthode validateNow() va valider et mettre à jour les propriétés et la mise en page du composant et le redessiner si nécessaire. Voici comment le code devra s'écrire:

adg.dataProvider = groupedCollection;
adg.validateNow();
adg.expandAll();

N'insérez pas la méthode validateNow() à chaque fois que vous faîtes un set sur le dataProvider car cela pourrait affecter les performances de votre application. C'est seulement nécessaire dans certaines situations quand vous voulez effectuer une action directement après le set du dataProvider.

2juil/094

Flex Chart – Modifier la donnée en temps réel, changement de dataProvider

En utilisant de l'ActionScript, vous pouvez changer la data d'un Chart à l'exécution (runtime) de plusieurs manières. Vous pouvez changer le dataProvider d'un Chart ou d'une Series.

L'exemple suivant fait une correspondance (Binding) entre la propriété dataProvider et une variable locale. Un bouton permet ensuite de basculer de dataProvider en utilisant cette variable locale.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
	<mx:Script><![CDATA[
		import mx.collections.ArrayCollection;
		[Bindable]
		public var expenses:ArrayCollection = new ArrayCollection([
			{Month:"Jan", Profit:2000, Expenses:1500, Amount:450},
			{Month:"Feb", Profit:1000, Expenses:200, Amount:600},
			{Month:"Mar", Profit:1500, Expenses:500, Amount:300}
		]);
		[Bindable]
		public var expenses2:ArrayCollection = new ArrayCollection([
			{Month:"Jan", Profit:2400, Expenses:1509, Amount:950},
			{Month:"Feb", Profit:3000, Expenses:2200, Amount:400},
			{Month:"Mar", Profit:3500, Expenses:1200, Amount:200}
		]);
		[Bindable]
		public var dp:ArrayCollection = expenses;
		public function changeDataProvider():void {
			if (dp==expenses) {
				dp = expenses2;
			} else {
				dp = expenses;
			}
		}
	]]></mx:Script>

	<mx:Panel title="Line Chart">
		<mx:LineChart id="myChart" dataProvider="{dp}" showDataTips="true">
			<mx:horizontalAxis>
				<mx:CategoryAxis
				dataProvider="{dp}"
				categoryField="Month"
				/>
			</mx:horizontalAxis>
			<mx:series>
				<mx:LineSeries
				yField="Profit"
				displayName="Profit"
				/>
				<mx:LineSeries
				yField="Expenses"
				displayName="Expenses"
				/>
				<mx:LineSeries
				yField="Amount"
				displayName="Amount"
				/>
			</mx:series>
		</mx:LineChart>
		<mx:Legend dataProvider="{myChart}"/>
	</mx:Panel>
	<mx:Button id="b1"
		label="Changer de Data Provider"
		click="changeDataProvider()"
	/>
</mx:Application>

Flex Source Code Download: Télécharger le code source complet de l'application

This movie requires Flash Player 11