Chercher dans les données d'un tableau

chaps31chaps31 Membre
17:01 modifié dans API AppKit #1
Hé oui encore moi qui flood avec toutes mes questions... Je vous rassure je cherche avant...

J'ai un tableau qui est le datasource d'une tableview, je veux que lorsque l'utilisateur tape dans une case l'appli "lise" les lettres et fasse un scrollView sur le nom le plus approchant de ce qui est tapé.
Je n'ai pas encore abordé les Notification donc ma question ne pose pas dessus, elle est plus simple.

Je fais des tests, j'initialise une variable NSString et je teste comme si c'était ce qu'avait tapé l'utilisateur. Bon je dois récupérer l'index du tableau et m'en servir dans ma tableview avec mon scrollView.

Pour un nom complet pas de soucis (valueForKey sur le tableau pour viser la bonne colonne et indexOfObject pour récupérer l'index). Là  où ça se corse c'est lorsqu'une partie du nom est tapé, par exemple ma variable de test vaut "DUP" et je voudrais un retour du premier index de la table dont la valueforkey précédente commence par DUP, et là ... je sèche, je pensais mon salut dans indexOfObject:inrange, en pensant justement qu'il ne regarderais que le range spécifié avec un NSMakeRange, impeccable, il suffit alors que la longueur du range soit celle de la variable, départ à  0, et ça roule.... Mais je pense que indexOfObject:inrange ne fait pas ça en fin de compte... car ça ne fonctionne pas il ne trouve rien à  partir d'une partie du nom...

Je m'en remet (encore) à  vous... Merci.

Réponses

  • Philippe49Philippe49 Membre
    17:01 modifié #2
    Une série de méthodes de NSString :
    - (NSRange)rangeOfString:(NSString *)aString


    Il y a aussi une méthode dans NSText
    - (void)scrollRangeToVisible:(NSRange)aRange
  • chaps31chaps31 Membre
    avril 2008 modifié #3
    Merci je vais regarder tout ça, mais il va falloir visiblement le faire "à  la main" en ennumérant les lignes de la table... J'espérais qu'il existe une méthode toute prête  :P

    EDIT : quoique scrollRangeToVisible à  l'air prometteur
  • schlumschlum Membre
    17:01 modifié #4
    Il faut implémenter un algorithme de recherche rapide sur le tableau ; maintenir une version triée et faire une recherche par dichotomie.
  • Philippe49Philippe49 Membre
    17:01 modifié #5
    On pourrait chercher du côté des NSArrayController et du filterPredicate

  • fouffouf Membre
    17:01 modifié #6
    Le problème des algos de tri par dichotomie c'est que le plus souvent, le récursif est necessaire et là , en C, je me demande si ca ne vaut pas plus le coup de faire un tri plus complexe que n*ln(n) (en nombres d'opérations) mais plus simple à  programmer.
    A vrai dire, le pied pour ce genre de choses, c'est le Caml, mais je ne sais pas si on peut appeler du code Caml avec du C.
  • schlumschlum Membre
    17:01 modifié #7
    dans 1207421094:

    Le problème des algos de tri par dichotomie c'est que le plus souvent, le récursif est necessaire et là , en C, je me demande si ca ne vaut pas plus le coup de faire un tri plus complexe que n*ln(n) (en nombres d'opérations) mais plus simple à  programmer.
    A vrai dire, le pied pour ce genre de choses, c'est le Caml, mais je ne sais pas si on peut appeler du code Caml avec du C.


    Pas besoin d'un tri par dichotomie ; une recherche suffit  :P
  • Philippe49Philippe49 Membre
    17:01 modifié #8
    En C, il n'y a pas de problème pour trier un tableau, les fonctions
    qsort , heapsort, mergesort, radixsort....
    sont là  pour le faire, et elles fonctionnent comme sous objective-C (le hasard ?) en définissant une fonction de comparaison
    int compare(const void* ptr1,const void* ptr2);
  • Philippe49Philippe49 Membre
    17:01 modifié #9
    Mais comme le dit Schlum, si on prend garde de mettre à  jour un tableau trié, le problème de la dichotomie n'en est pas un.
    Ceci dit je crois qu'ici l'utilisation d'un NSArrayController est sans doute tout aussi Objective-C-généralisable.
  • schlumschlum Membre
    17:01 modifié #10
    dans 1207422420:

    En C, il n'y a pas de problème pour trier un tableau, les fonctions
    qsort , heapsort, mergesort, radixsort....
    sont là  pour le faire, et elles fonctionnent comme sous objective-C (le hasard ?) en définissant une fonction de comparaison
    int compare(const void* ptr1,const void* ptr2);


    À mon avis, les fonctions de tri Objective-C sont des wrappers sur ces fonctions... Mais j'ai la flemme de vérifier  :P
  • chaps31chaps31 Membre
    17:01 modifié #11
    whaou que de discussion que je ne comprends pas sur ce sujet... ;) Mon tableau est trié car je le rempli à  partir d'une base postgresql et avec les indices de philippe49, ça marche :
    [tt]
    int i;
    NSString *nomRech;
    for(i=0;i<[tableclients count]; i++)
    {
    nomRech=[[tableclients valueForKey:@nom] objectAtIndex:i];
    NSRange rangetest=[nomRech rangeOfString:vartest];
    if(rangetest.location==0 && rangetest.length==[vartest length])
    {
    [tableView scrollRowToVisible:i];
    return;
    }

    }
    }[/tt]

    Maintenant il faut que j'apprenne à  me servir des évènements pour que tout cela se passe à  chaque frappe clavier dasn un nssearchfield... Merci encore
  • Philippe49Philippe49 Membre
    17:01 modifié #12
    Comme tu cherches à  comparer les débuts des chaà®nes,
    - (NSComparisonResult)compare:(NSString *)aString options:(NSStringCompareOptions)mask range:(NSRange)range
    devait être efficace également.
  • chaps31chaps31 Membre
    17:01 modifié #13
    Economie de code, et comment se gère un NScomparaisonresult ?
  • Philippe49Philippe49 Membre
    17:01 modifié #14
    Dans la doc NSString
    --->
    - (NSComparisonResult)compare:(NSString *)aString options:(NSStringCompareOptions)mask range:(NSRange)rang
    --->
    NSComparisonResult est un lien actif vers une énumération de constantes entières.
    typedef enum _NSComparisonResult {
      NSOrderedAscending = -1,
      NSOrderedSame,
      NSOrderedDescending
    } NSComparisonResult;

    Le premier vaut -1, et les autres suivent NSOrderedSame=0 ,  NSOrderedDescending=1.
    Mais bon, Apple peut à  tout moment décider de changer ces valeurs, et puis garder les expressions littérales de ces constantes est à  préférer.

    On peut coder ainsi :
    NSComparisonResult result=[ string1 compare:string2 options:NSLiteralSearch range:tonRange];
    if(result==NSOrderedSame) // ils sont égaux


    ou en plus concis
    if([string1 compare:string2 options:NSLiteralSearch range:tonRange]==NSOrderedSame){
      .......
    }


  • chaps31chaps31 Membre
    17:01 modifié #15
    C'est quand même mieux en effet, merci.
  • chaps31chaps31 Membre
    17:01 modifié #16
    Ca marche impec et encore mieux, je commençais à  me prendre la tête sur les évènements sans bien comprendre quand j'ai testé un truc :

    Ma méthode de recherche est un IBAction
    J'ai une variable Outlet pour chaque NSSearchField
    Ma méthode est lié à  chaque nssearchfield
    J'ai rajouté un message d'alerte pour arrêter la frappe lorsque la chaine tapée est introuvable et ça marche !!! Pas besoin d'event, l'appli repère la frappe fait tourner la recherche à  chaque caractère tapé, incroyable.... OUtlet et IBAction m'épate sur ce coup... Ou est-ce lié au NSSearchField ?

    Juste une autre question de base : comment je fais pour que des nstextfield et nssearchfield soit en majuscule ou capitalized, actuellement je modifient la casse avant l'enregistrement dans la base mais je voudrais que lorsqu l'utilisateur tape un nom il apparaisse en majuscule, merci.
  • AliGatorAliGator Membre, Modérateur
    avril 2008 modifié #17
    dans 1207570690:
    Juste une autre question de base : comment je fais pour que des nstextfield et nssearchfield soit en majuscule ou capitalized, actuellement je modifient la casse avant l'enregistrement dans la base mais je voudrais que lorsqu l'utilisateur tape un nom il apparaisse en majuscule, merci.
    Au hasard... NSFormatter ? http://developer.apple.com/documentation/Cocoa/Conceptual/DataFormatting/Articles/CreatingACustomFormatter.html#//apple_ref/doc/uid/20000196
  • Philippe49Philippe49 Membre
    17:01 modifié #18
    dans 1207570690:


    Juste une autre question de base : comment je fais pour que des nstextfield et nssearchfield soit en majuscule ou capitalized, actuellement je modifient la casse avant l'enregistrement dans la base mais je voudrais que lorsqu l'utilisateur tape un nom il apparaisse en majuscule, merci.


    On attribue un NSFormatter
    Data Formatting Programming Guide for Cocoa

  • Philippe49Philippe49 Membre
    17:01 modifié #19
    Dans IB, il n'y a que des DateFormatter et NumberFormatter

    Il faut donc en faire un perso et utiliser la méthode setFormatter de NSControl ou NSCell lors de awakeFromNib par exemple.
  • chaps31chaps31 Membre
    17:01 modifié #20
    Je vais étudier ça, merci de répondre à  des questions qui doivent vous sembler triviale. A ce propos une petite dernière...  :P

    J'ai lu dans des forums, la doc d'Apple, project Omega... et dans NSFormatter, qu'il faut "overdriver", sans jamais comprendre de quoi il s'agit, généralement il me semble comprendre que c'est lié à  des classes abstraites, qui sont pour moi assez... abstraites  :P

    D'ailleurs si j'ai bien compris ce sont des classes aux méthodes non implémentées... heu quelle utilité de ne pas implémenter des méthodes.. je ne saisi pas la logique...
  • Philippe49Philippe49 Membre
    17:01 modifié #21
    overdriver je ne vois pas ...

    Classes abstraites : Pour moi, cela veut dire qu'on ne peut utiliser que des sous-classes et la classe abstraite donne l'ensemble des méthodes communes, cela permet une unité dans un groupe de classes ... mais il faudrait repotasser cela dans les généralités sur Objective-C.
  • chaps31chaps31 Membre
    17:01 modifié #22
    [tt]To subclass NSFormatter, you must, at the least, override the three primitive methods:

        *

          stringForObjectValue:
        *

          getObjectValue:forString:errorDescription:
        *

          attributedStringForObjectValue:withDefaultAttributes:[/tt]

    Autant pour moi , override... :o
  • schlumschlum Membre
    17:01 modifié #23
    Ah ben c'est pas du tout la même chose  :o :o :o   ;D

    "override" veut dire " surcharger "...

    C'est quand on redéfinit une méthode de la classe mère dans une classe fille


    En Objective-C, c'est simple  :P
    En C++ il y a 3 ou 4 types de surcharges  :o
  • AliGatorAliGator Membre, Modérateur
    17:01 modifié #24
    Overrider = surcharger c'est à  dire comme l'a dit schlum réécrire pour une classe fille du code qui existe déjà  dans la classe mère (écrire une nouvelle implémentation donc). Si tu ne surcharges pas, c'est le code de la classe mère qui sera appelé, si tu surcharges, tu redéfinis du nouveau code pour la classe fille différent de la classe mère donc pour tes objets de type "fille" c'est ce code qui sera appelé et non le code par défaut de la classe mère en l'absence de surcharge (ouf!)
    Pour appeler le code de la classe mère à  partir du code surchargé de la casse fille, on utilise [super nomDeLaMethode].
    Par exemple il est fréquent de surcharger la méthode "dealloc", et d'appeler à  la fin du code de surcharge la méthode "dealloc" de la classe mère avec [super dealloc].

    Une classe abstraite c'est une classe pour laquelle toutes les méthodes ne sont pas implémentées. Il arrive parfois de parler de "surcharge d'une méthode abstraite" ce qui peut être un peu abusif comme langage, puisqu'on ne la surcharge pas vraiment, on l'implémente dans la classe fille alors qu'elle n'était pas implémentée.
    L'intérêt de faire des classes abstraites c'est que ça permet de déclarer plusieurs méthodes communes à  plusieurs objets : ensuite tu dérives cette classe abstraite en plusieurs sous-classes, qui elles vont implémenter les méthodes (et donc ne seront pas des classes abstraites, elles). Par contre on ne peut pas instancier une classe abstraite, puisque jsutement certaines de ses méthodes ne sont pas déclarées : on ne peut qu'instancier une de ses classes filles non abstraite.
    exemple: une classe abstraite "Figure" qui déclare une méthode "getBoundingRect" (non implémentée) et est dérivée en des classes "Rectangle", "Square", "Circle", ... qui chacunes implémentent la méthode getBoundingRect, mais de façon différente

    Ceci dit le terme "classe abstraite" est issu de la POO, mais en Objective-C c'est plutôt appelé des protocoles (cf "@protocol";)
    Par exemple le NSCopyingProtocol déclare la méthode "copyWithZone:" mais ne l'implémente pas. Ce ne sont que les classes filles, implémentant ce protocole, qui vont justement implémenter cette méthode en lui donnant du code, différent selon les classes filles.
    L'intérêt c'est qu'ensuite du moment que tu sais qu'une classe implémente le protocole NSCopyingProtocol, tu n'as pas besoin de savoir de quelle classe il s'agit pour appeler la méthode copyWithZone. Tout comme du moment que tu sais que tu as une Figure, tu n'as pas besoin de savoir de quel type de figure il s'agit pour appeler getBoundingRect.
  • schlumschlum Membre
    17:01 modifié #25
    Il me semble qu'en Cocoa ils simulent aussi les méthodes virtuelles en balançant une exception dans la méthode de la classe mère...
  • chaps31chaps31 Membre
    17:01 modifié #26
    Clair et précis, Merci, la POO c'est tout un monde quand même...
Connectez-vous ou Inscrivez-vous pour répondre.