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

25juin/100

Flex AdvancedDataGrid – Supprimer le séparateur dans les headers des colonnes non triables

Il y a souvent des commentaires sur flex-tutorial pour savoir comment contourner certains comportements par défaut de Flex. En voici un sur l'article Flex AdvancedDataGrid – Tri sur plusieurs colonnes (Sort et sortExpertMode):

Niko 

Hello!
Est il possible de supprimer le petit trait sur les colonnes non tri-ables pour permettre l'affichage de l'entête de colonne sur la totalité de la largeur ?
N.

Cela semble tout bête (voire même cela devrait être un comportement par défaut) mais la solution se révèle en fait assez difficile à mettre en œuvre. Etant toujours avide de défi, je me suis penché de plus près sur le problème.

Comment analyser les comportements de Flex

Dans un cas comme cela, ce n'est pas son propre code qu'il faut comprendre mais bien celui du framework Adobe Flex. Si vous savez déjà dans quelle direction chercher, vous pouvez aller chercher dans les livedocs Flex:

Flex 4 Livedocs

Les Livedocs sont honnêtement bien faites et complètes, vous trouverez un maximum d'information sur les classes de Flex.

Pour aller fouiller dans le code de Flex (et oui, c'est là que l'on se rend compte de la puissance du côté Open Source de Flex ;) ), vous pouvez simplement faire Ctrl-Click sur une classe ou un élément MXML dans Flex Builder. Cela va vous emmener directement dans la classe. Pour les fans des raccourcis clavier, appuyer sur F3 et FB vous emmènera dans la classe sur laquelle se trouve le curseur.

go-to-definitionParfois, vous n'aurez pas la classe sous les yeux ou alors son nom se trouvera dans un commentaire ASDoc. Par exemple, je cherchais au départ comment était déterminé l'itemRenderer d'une AdvancedDataGridColumn. Avec Ctrl+O, je trouve un assesseur sur "itemRenderer" donc l'ASDoc est la suivante:

/**
 *  @private
 *  Storage for the itemRenderer property.
 */
 private var _itemRenderer:IFactory;

 [Bindable("itemRendererChanged")]
 [Inspectable(category="Other")]

 /**
 *  The class factory for item renderer instances that display the
 *  data for each item in the column.
 *  You can specify a drop-in item renderer,
 *  an inline item renderer, or a custom item renderer component as the
 *  value of this property.
 *
 *  <p>The default item renderer is the AdvancedDataGridItemRenderer class,
 *  which displays the item data as text. </p>
 *
 *  @see mx.controls.advancedDataGridClasses.AdvancedDataGridItemRenderer
 */
 public function get itemRenderer():IFactory
 {
 return _itemRenderer;
 }

L'ASDoc me dit d'aller voir la classe "AdvancedDataGridItemRenderer". Pour cela, je ne peux pas faire un Navigate To, mais je peux cependant faire un "Open Type" (Ctrl+Shift+T). Contrairement à un "Open Resource" (Ctrl+Shift+R), qui va me montrer tous les fichiers (css, xml, as, mxml, …) présents dans les projets ouverts de mon Workspace, Open Type va me permettre d'ouvrir n'importe quelle classe.
open-type

Notez que vous pouvez utiliser des jokers "*" dans le champ de recherche. Ainsi, en entrant "*DataGrid*Renderer*", vous aurez toutes les classes contenant DataGrid et Renderer, ce peut vous permettre de trouver rapidement des classes dérivées.

Voilà, avec ces quelques raccourcis, vous pouvez aller fouiller rapidement dans le code de Flex.

Revenons à notre problème de header…

Après une 10aine de minutes de recherches, je trouve la classe "AdvancedDataGridHeaderRenderer" qui s'occupe de faire le rendu du header des colonnes uniquement. Notez qu'en utilisant un Open Type avec les bons mots-clés, je l'aurais trouvée directement :P .

On y trouve ainsi:

/**
 *  Specifies a custom sort item renderer.
 *  By default, the AdvancedDataGridHeaderRenderer class uses
 *  AdvancedDataGridSortItemRenderer as the sort item renderer.
 *
 *  <p>Note that the sort item renderer controls the display of the
 *  sort icon and sort sequence number.
 *  A custom header renderer must include code to display the
 *  sort item renderer, regardless of whether it is the default or custom
 *  sort item renderer.</p>
 */
 public function get sortItemRenderer():IFactory
 {
 return _sortItemRenderer;
 }

C'est bien cet itemRenderer, "sortItemRenderer" qui s'occupe de gérer le rendu du coin droit des headers de colonnes. Comme souvent, on va modifier le comportement de cette classe en héritant de cette classe et en surchargeant certaines de ses méthodes, vu qu'on ne va pas changer le code de Flex. On va donc créer une classe CustomHeaderRenderer qui hérite de AdvancedDataGridHeaderRenderer.

Pour commencer, j'ai juste tenté de surcharger le getter et de renvoyer null, dans tous les cas, pour voir ce que cela faisait:

package {
 import mx.controls.advancedDataGridClasses.AdvancedDataGridHeaderRenderer;
 import mx.core.IFactory;

 public class CustomHeaderRenderer extends AdvancedDataGridHeaderRenderer {
   public function CustomHeaderRenderer() {
     super();
   }

   override public function get sortItemRenderer():IFactory {
     return null;
   }

 }
}

Et je tente de l'intégrer dans mon application:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" viewSourceURL="srcview/index.html">

  <mx:Script>
    <![CDATA[
      import mx.collections.ArrayCollection;

      [Bindable]
      private var dpADG:ArrayCollection = new ArrayCollection([{Artist: 'Pavement', Album: 'Slanted and Enchanted', Price: 11.99}, {Artist: 'Pavement', Album: 'Brighten the Corners', Price: 11.99}, {Artist: 'Saner',
          Album: 'A Child Once', Price: 11.99}, {Artist: 'Saner', Album: 'Helium Wings', Price: 12.99}, {Artist: 'The Doors', Album: 'The Doors', Price: 10.99}, {Artist: 'The Doors', Album: 'Morrison Hotel',
          Price: 12.99}, {Artist: 'Grateful Dead', Album: 'American Beauty', Price: 11.99}, {Artist: 'Grateful Dead', Album: 'In the Dark', Price: 11.99}, {Artist: 'Grateful Dead', Album: 'Shakedown Street',
          Price: 11.99}, {Artist: 'The Doors', Album: 'Strange Days', Price: 12.99}, {Artist: 'The Doors', Album: 'The Best of the Doors', Price: 10.99}]);
    ]]>
  </mx:Script>
  <mx:ApplicationControlBar dock="true">
    <mx:CheckBox id="sortExpertModeCB" label="sortExpertMode?"/>
  </mx:ApplicationControlBar>
  <mx:AdvancedDataGrid width="100%" height="100%" sortExpertMode="{sortExpertModeCB.selected}"
                       dataProvider="{dpADG}">
    <mx:columns>
      <mx:AdvancedDataGridColumn dataField="Artist" sortable="false"
                                 headerRenderer="CustomHeaderRenderer"/>
      <mx:AdvancedDataGridColumn dataField="Album"/>
      <mx:AdvancedDataGridColumn dataField="Price"/>
    </mx:columns>
  </mx:AdvancedDataGrid>
</mx:Application>

Et voici le résultat:

custom-renerer-1Et voilà, mission accomplie :) . En 15 minutes, pas mal de recherches, un peu de test, on a réussi à "hacker" un comportement par défaut de Flex.

Aller plus loin…

Certains pourraient remarquer que dans ce cas précis, on a pas crée un itemRenderer qui va supprimer la barre horizontale quand la colonne n'est pas "sortable", mais plutôt un renderer qui supprimer la barre horizontale que l'on a assigné sur une colonne pas "sortable". Il serait donc intéressant d'utiliser cet itemRenderer pour toutes les colonnes de la AdvancedDataGrid, et que celui-ci capte si la colonne dont il est en train de faire le rendu est "sortable ou non.

Notez que dans ce cas-là, on va mettre setter la propriété "headerRenderer" sur l'AdvancedDataGrid et pas sur l'AdvancedDataGridColumn.

J'avais commencé à le faire, voici ce que cela donnait:

package {
  import mx.controls.advancedDataGridClasses.AdvancedDataGridColumn;
  import mx.controls.advancedDataGridClasses.AdvancedDataGridHeaderRenderer;
  import mx.core.IFactory;

  public class CustomHeaderRenderer extends AdvancedDataGridHeaderRenderer {
    public function CustomHeaderRenderer() {
      super();
    }

    override public function get sortItemRenderer():IFactory {
      if (data) {
        if (data is AdvancedDataGridColumn) {
          var adgc:AdvancedDataGridColumn = data as AdvancedDataGridColumn;
          if (!adgc.sortable) {
            return null;
          }
        }
      }
      return super.sortItemRenderer;
    }

  }
}

Notez que je n'ai pas sorti ce code avec "data" de mon chapeau, il est issu de la classe AdvancedDataGridHeaderRenderer ;) . Bon après en testant un peu, si vous modifiez l'ordre de colonnes par un Drag & Drop, les itemRenderer seront recyclés et l'indicateur de Sort peut apparaitre à nouveau. Il faudrait surcharger "set data(value:Object):void" et faire un nouveau traitement pour voir sur quelle colonne on se trouve mais je vous laisse le soin de le faire :) .

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" viewSourceURL="srcview/index.html">

<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;

[Bindable]
private var dpADG:ArrayCollection = new ArrayCollection([{Artist: 'Pavement', Album: 'Slanted and Enchanted', Price: 11.99}, {Artist: 'Pavement', Album: 'Brighten the Corners', Price: 11.99}, {Artist: 'Saner',
Album: 'A Child Once', Price: 11.99}, {Artist: 'Saner', Album: 'Helium Wings', Price: 12.99}, {Artist: 'The Doors', Album: 'The Doors', Price: 10.99}, {Artist: 'The Doors', Album: 'Morrison Hotel',
Price: 12.99}, {Artist: 'Grateful Dead', Album: 'American Beauty', Price: 11.99}, {Artist: 'Grateful Dead', Album: 'In the Dark', Price: 11.99}, {Artist: 'Grateful Dead', Album: 'Shakedown Street',
Price: 11.99}, {Artist: 'The Doors', Album: 'Strange Days', Price: 12.99}, {Artist: 'The Doors', Album: 'The Best of the Doors', Price: 10.99}]);
]]>
</mx:Script>
<mx:ApplicationControlBar dock="true">
<mx:CheckBox id="sortExpertModeCB" label="sortExpertMode?"/>
</mx:ApplicationControlBar>
<mx:AdvancedDataGrid width="100%" height="100%" sortExpertMode="{sortExpertModeCB.selected}"
dataProvider="{dpADG}">
<mx:columns>
<mx:AdvancedDataGridColumn dataField="Artist" sortable="false"
headerRenderer="CustomHeaderRenderer"/>
<mx:AdvancedDataGridColumn dataField="Album"/>
<mx:AdvancedDataGridColumn dataField="Price"/>
</mx:columns>
</mx:AdvancedDataGrid>
</mx:Application>

Articles similaires

Commentaires (0) Trackbacks (0)

Aucun commentaire pour l'instant


Leave a comment

(required)

Aucun trackbacks pour l'instant