Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
2813 connectés 

  FORUM HardWare.fr
  Programmation
  Java

  ListModel, ce n'est pas sale, parlons-en.

 

 

 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

ListModel, ce n'est pas sale, parlons-en.

n°595941
nraynaud
lol
Posté le 23-12-2003 à 09:35:42  profilanswer
 

Je suis dans une application swing, et je suis confronté à des problèmes qui concernent tous ceux qui font du swing, je vais donc partager.
 
Première chose, les listes dont le éléments sont triés;
J'ai actuellement une implémentation fondée sur un TreeMap :

Code :
  1. public class MemberSet extends AbstractListModel {
  2.  private SortedSet model;
  3.  // accessor used for indexed access.
  4.  private Iterator indexedAccessIterator = null;
  5.  /**
  6.   * next aivable index from the iterator.
  7.   */
  8.  private int nextIndex = 0;
  9.  private void reinitIterator() {
  10.   indexedAccessIterator = null;
  11.   nextIndex = 0;
  12.  }
  13.  /**
  14.   * @param membersComparator
  15.   */
  16.  public MemberSet(Comparator membersComparator) {
  17.   model = new TreeSet(membersComparator);
  18.  }
  19.  // ListModel methods
  20.  public int getSize() {
  21.   // Return the model size
  22.   return model.size();
  23.  }
  24.  public Object getElementAt(int index) {
  25.   Object result = null;
  26.   if (indexedAccessIterator == null || nextIndex > index) {
  27.    indexedAccessIterator = model.iterator();
  28.    nextIndex = 0;
  29.   }
  30.   for (; nextIndex <= index; nextIndex++) {
  31.    result = indexedAccessIterator.next();
  32.   }
  33.   return result;
  34.  }
  35.  public boolean add(Member element) {
  36.   boolean added = model.add(element);
  37.   if (added) {
  38.    reinitIterator();
  39.    fireContentsChanged(this, 0, getSize());
  40.   }
  41.   return added;
  42.  }
  43.  public synchronized void clear() {
  44.   model.clear();
  45.   reinitIterator();
  46.   fireContentsChanged(this, 0, getSize());
  47.  }
  48.  public synchronized boolean remove(Member member) {
  49.   boolean removed = model.remove(member);
  50.   if (removed) {
  51.    reinitIterator();
  52.    fireContentsChanged(this, 0, getSize());
  53.   }
  54.   return removed;
  55.  }
  56.  public Iterator iterator() {
  57.   return Collections.unmodifiableSortedSet(model).iterator();
  58.  }
  59. }

Elle est spécialisée pour des "Member" mais bon vous avez compris le principe.
La vue (ListUI) accède aux éléments, par leur indice, avec mon TreeSet dans une main et mon int dans l'autre, il faut convertir, la solution la plus simple consiste à parcourir un itérateur du set en comptant, quand on arrive au rang voulu, on renvoie la valeur de l'itérateur. Pour faire baisser un poil la complexité, et comme je sais que les indice sont accédés par plage contigües (j'ai testé) dans l'ordre croissant, je garde l'itérateur pour pas repartir de zéro à chaque requête.
si vous avez une idée pour l'améliorer, dites.
Il est possible d'avoir une complexité encore plus faible, mais ça nécessite de refaire toute la classe TreeSet pour y rajouter l'indexation, si quelqu'un de compétent en algo et en qualité veut bien faire ça en open-source, nous lui en serions tous reconnaissants.
 
Dans un esprit de partage, vous qu'avez-vous comme ListModel avec des services intéressant ?
 
 
Voiloù, j'aimerais qu'on arrive un peu à partager sur ce point (et peut-être des points connexes, tel les TableModels).
 
edit : enlevage d'une connerie, comme quoi se laver les dents c'est utile : ça fait réfléchir.


Message édité par nraynaud le 23-12-2003 à 09:44:52

---------------
trainoo.com, c'est fini
mood
Publicité
Posté le 23-12-2003 à 09:35:42  profilanswer
 

n°595978
verdoux
And I'm still waiting
Posté le 23-12-2003 à 11:05:13  profilanswer
 

Ca a pas l'air très utile comme truc.
Le fait que ce soit trié n'apporte pas grand chose alors que si on avait un accès aléatoire à temps constant on pourrait faire de la recherche dichotomique.

n°596047
yo c spi
Yo !
Posté le 23-12-2003 à 13:51:24  profilanswer
 

J'ai été confronté au meme problème avec TableModel.
J'ai été obligé de faire une methode getObjectAtIndex(int i) dans ma liste d'objets faites sur un TreeSet. Cette méthode est complétement inutile en dehors de son contexte et est complétement absurde ais c'est la seule facon que j'ai trouvé.
Je fais aussi un parcours avec un Iterator mais c'est crade.
 
C'est le moyen le plus simple d'utiliser sans avoir a faire sa propre classe de liste ou tree et refaire tous les algo de parcours et de tris.

n°596071
nraynaud
lol
Posté le 23-12-2003 à 14:20:27  profilanswer
 

Supprimé, fausse bonne-idée.
 
 
Le ListModel ne doit être mis-à-jour *que* dans la tâche de répartition des événements de swing.


Message édité par nraynaud le 24-12-2003 à 23:32:58

---------------
trainoo.com, c'est fini
n°596223
veryfree
Posté le 23-12-2003 à 18:31:45  profilanswer
 

moi j'avait fait ca pour trié les elements :
 
 

Code :
  1. /**
  2. * A Model that sorts its elements
  3. */
  4.     class SortedModel extends DefaultListModel {
  5.      private boolean added;
  6.    
  7.         public synchronized void addElement(Object obj) {
  8.          int result;
  9.          added=false;
  10.          String element = obj.toString();
  11.             for (int i = 0; i < size(); i++) {
  12.              result=collator.compare(((UserItem)elementAt(i)).getNick(),element);
  13.              if ( result > 0) {
  14.               insertElementAt(obj,i);
  15.               added=true;
  16.               break;
  17.              }else if(result==0){ //on a un doublons
  18.               added=true;
  19.               break;
  20.              }
  21.             }
  22.             if(!added)
  23.              super.addElement(obj);         
  24.         }
  25.     }

n°597076
yo c spi
Yo !
Posté le 26-12-2003 à 02:35:02  profilanswer
 

nraynaud a écrit :

Supprimé, fausse bonne-idée.
 
 
Le ListModel ne doit être mis-à-jour *que* dans la tâche de répartition des événements de swing.


Peux tu développer stp, je ne comprends pas très bien.
L'accès n'est pas une mise a jour  :heink:

n°597081
nraynaud
lol
Posté le 26-12-2003 à 07:47:45  profilanswer
 

yo c spi a écrit :


Peux tu développer stp, je ne comprends pas très bien.
L'accès n'est pas une mise a jour  :heink:  

Imaginons qu'il y a une tâche qui met et enlève des éléments aléatoirement en permanence, une belle adaptation pour retarder les évènements dans la tâche de répartition des événements swing comme j'avais fait avant de comprendre que c'est peine perdue.
Pour peindre la liste, le ListUI fait la chose suivante (par défaut) :  
 - parcourir le ListModel pour chercher la plage de valeurs visibles (si on a pas mis de prototype)
 - pour chaque valeur de la plage visible, obtenir un renderer et le peindre.
 
le parcourt se fait de la manière suivante :
 - lire le nombre de valeurs dans le ListModel
 - parcourir avec un int ces valeur (avec getElementAt())
 
Bien entendu, rien de tout ça ne "bloque" (avec synchronized) le ListModel, ce qui veut dire que si la tâche de mise-à-jour retire une valeur avant la fin du parcourt de la tâche de dessin, un ArrayOutOfBoundException va se lever, exactement ce qui m'est arrivé quand je me croyais malin avec mon ListModel synchronisé pour la notification des événements de mise-à-jour, mais pas des autres (tel un déplacement de la scrollbar, redimentionnement de la fenêtre etc.).


---------------
trainoo.com, c'est fini
n°600252
nraynaud
lol
Posté le 01-01-2004 à 15:31:14  profilanswer
 

Code :
  1. /**
  2.  *  
  3.  * @author nraynaud
  4.  *
  5.  * This is the channel members collection, it losely implements Set interface.
  6.  * The model is based on a TreeSet.
  7.  * Aiming at performance, consecutive in-order accesses are cached by an iterator.
  8.  *  
  9.  */
  10. public class MemberListModel extends AbstractListModel {
  11.  /**
  12.   * the set, for sorted access to members.  
  13.   */
  14.  private TreeSet model;
  15.  private Comparator comparator;
  16.  /**
  17.   * iterator used for indexed access.
  18.   */
  19.  private Iterator indexedAccessIterator = null;
  20.  /**
  21.   * next aivable index from the iterator.
  22.   */
  23.  private int nextIndex = 0;
  24.  /**
  25.   * last iterated object.
  26.   */
  27.  private Object previousMember = null;
  28.  private int indexAccess = 0;
  29.  private int missedIterator = 0;
  30.  private int avoidedReset = 0;
  31.  private void reinitIterator() {
  32.   previousMember = null;
  33.   indexedAccessIterator = null;
  34.   nextIndex = 0;
  35.  }
  36.  /**
  37.   * @param membersComparator
  38.   */
  39.  public MemberListModel(Comparator membersComparator) {
  40.   comparator = membersComparator;
  41.   model = new TreeSet(membersComparator);
  42.  }
  43.  // ListModel methods
  44.  public int getSize() {
  45.   return model.size();
  46.  }
  47.  public Object getElementAt(int index) {
  48.   assert SwingUtilities.isEventDispatchThread();
  49.   indexAccess++;
  50.   Object result = null;
  51.   //unlikely to araise but avoids iterator reset when reading twice the same index.
  52.   if (index == nextIndex - 1 && previousMember != null) {
  53.    result = previousMember;
  54.    avoidedReset++;
  55.   } else {
  56.    //see if reading is in-order
  57.    if (indexedAccessIterator == null || nextIndex > index) {
  58.     indexedAccessIterator = model.iterator();
  59.     nextIndex = 0;
  60.     missedIterator++;
  61.    }
  62.    //go to the requested index.
  63.    for (; nextIndex <= index; nextIndex++)
  64.     result = indexedAccessIterator.next();
  65.   }
  66.   // asserting that the result is the same than the obvious one.
  67.   assert result == model.toArray()[index];
  68.   previousMember = result;
  69.   System.out.println(
  70.    "missed :"
  71.     + missedIterator
  72.     + "/"
  73.     + indexAccess
  74.     + " avoided resets : "
  75.     + avoidedReset);
  76.   return result;
  77.  }
  78.  /**
  79.   * Inserts the given collection into the members collection.
  80.   * @param collection the collection to add.
  81.   * @throws NullPointerException if an element of the given colection is null
  82.   * @throws ClassCastException if an element of th passed collection is not instance of Member.  
  83.   */
  84.  public void addAll(Collection collection) {
  85.   assert SwingUtilities.isEventDispatchThread();
  86.   for (Iterator i = collection.iterator(); i.hasNext();) {
  87.    Member member = (Member)i.next();
  88.    model.add(member);
  89.   }
  90.   reinitIterator();
  91.   fireContentsChanged(this, 0, getSize());
  92.  }
  93.  /**
  94.   * adds the given member to the collection.
  95.   *  
  96.   * @param element the member to add to the collection
  97.   * @return true if the member was added.
  98.   * @throws NullPointerException if element is null.
  99.   */
  100.  public boolean add(Member member) {
  101.   assert SwingUtilities.isEventDispatchThread();
  102.   boolean added = model.add(member);
  103.   if (added) {
  104.    int min = 0;
  105.    if (previousMember != null
  106.     && comparator.compare(member, previousMember) >= 0)
  107.     min = nextIndex - 1;
  108.    reinitIterator();
  109.    assert min == 0
  110.     || comparator.compare(model.toArray()[min], member) <= 0;
  111.    fireContentsChanged(this, min, getSize());
  112.   }
  113.   return added;
  114.  }
  115.  /**
  116.   * Clears the collection.
  117.   *
  118.   */
  119.  public void clear() {
  120.   assert SwingUtilities.isEventDispatchThread();
  121.   model.clear();
  122.   reinitIterator();
  123.   fireContentsChanged(this, 0, getSize());
  124.  }
  125.  /**
  126.   * Removes the given member.
  127.   * @param member the member to remove
  128.   * @return true if member was removed, false otherwise
  129.   */
  130.  public boolean remove(Member member) {
  131.   assert SwingUtilities.isEventDispatchThread();
  132.   boolean removed = model.remove(member);
  133.   if (removed) {
  134.    int min = 0;
  135.    if (previousMember != null
  136.     && comparator.compare(member, previousMember) >= 0)
  137.     min = nextIndex - 1;
  138.    reinitIterator();
  139.    assert min == 0
  140.     || comparator.compare(model.toArray()[min], member) <= 0;
  141.    fireContentsChanged(this, min, getSize());
  142.   }
  143.   return removed;
  144.  }
  145. }


 
Le même avec une légère amélioration et des chiffres :
missed :255/28820 avoided resets : 183
 
il y a eu 28820 appels à getElementAt(), 255 ont donné lieu à un reset de l'iterateur (insertion/retrait d'éléments ou accès dans le désordre) et 183 reset ont été évités par le cache de la dernière valeur tirée de l'itérateur (c'est utile lorsqu'on scrolle vers le bas de la liste).
 
Je pense que c'est plutôt pas mal.


---------------
trainoo.com, c'est fini

Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  Java

  ListModel, ce n'est pas sale, parlons-en.

 

Sujets relatifs
[ MySQL ] optimisation, parlons-en ( newbee inside )Parlons sérieusement : ASP.NET versus PHP versus J2E
Plus de sujets relatifs à : ListModel, ce n'est pas sale, parlons-en.


Copyright © 1997-2025 Groupe LDLC (Signaler un contenu illicite / Données personnelles)