Des chiffres et des lettres...

MickMick Membre
juillet 2013 modifié dans API AppKit #1

Bonjour à  tous,


Une petite question (simple je pense) à  laquelle je ne sais pas trop répondre. J'ai une tableView dont la dataCell a un numberFormatter. Le soucis est que l'utilisateur doit pouvoir utiliser certains "codes" => par ex Abs, NN (non noté), Disp (dispensé) ... Au niveau du traitement c'est assez facile via la dataSource, mais comment, au niveau de la vue, permettre d'"accepter" certains "codes" ?

Dois-je subclasser NSFormatter ?


Je ne sais pas où je dois customiser..


Réponses

  • AliGatorAliGator Membre, Modérateur
    20:41 modifié #2
    Pour la question de "par où je dois customiser" et par où commencer, la réponse est évidente, comme toujours consulter le Programming Guide associé au thème qui t'intéresse (dont le lien se trouve entre autres en haut des pages de docs des classes associées comme NSFormatter dans ce cas, donc assez simple à  trouver) répondra à  la plupart de tes questions. Tu as même dedans une section dédiée pour créer un custom formatter.

    Maintenant, les NSFormatter sont là  pour formatter des données. Si tu veux valider les données saisies, et refuser la modification si la donnée ne peut être interprétée (par exemple si l'utilisateur rentre "jfkdsmqu" comme valeur), il faut peut-être regarder du côté du Key-Value Validation ?
  • MickMick Membre
    20:41 modifié #3
    Ok, je vais regarder du coté des validations.
    De toutes façons il faut que je bidouille un formatter : je vais assoicier un integer à  un "code" du genre "Abs" = -1 "NN"=-2 etc...
    Merci Ali (je n'ai pas encore mis le nez dans les histoires de validation)
  • MickMick Membre
    20:41 modifié #4
    Bonjur,

    Pour ceux que ça intéresse, j'ai finalement réussi à  bricoler un NSFormatter : j'ai créé une subClass de NSNumberFormatter dans laquelle j'ai overridé :
    <br />- (NSString *)stringForObjectValue:(id)anObject {<br />	if(![anObject isKindOfClass:[NSNumber class]]) return nil;<br />	if([anObject floatValue]==-1.0) return @&quot;Abs&quot;;<br />	if([anObject floatValue]==-2.0) return @&quot;NN&quot;;<br />	return [super stringForObjectValue:anObject];<br />}<br /><br />- (BOOL)getObjectValue:(id *)anObject forString:(NSString *)string errorDescription:(NSString **)error {<br />	BOOL OK=NO;<br />	if([string isEqual:@&quot;Abs&quot;]||[string isEqual:@&quot;abs&quot;]||[string isEqual:@&quot;a&quot;]||[string isEqual:@&quot;A&quot;]) {<br />		*anObject=[NSNumber numberWithFloat:-1.0];<br />		OK=YES;<br />	}<br />	if([string isEqual:@&quot;NN&quot;]||[string isEqual:@&quot;nn&quot;]||[string isEqual:@&quot;n&quot;]||[string isEqual:@&quot;N&quot;]) {<br />		*anObject=[NSNumber numberWithFloat:-2.0];<br />		OK=YES;<br />	}<br />	if(OK==NO) OK=[super getObjectValue:anObject forString:string errorDescription:error];<br />	return OK;<br />}<br /><br />- (NSAttributedString *)attributedStringForObjectValue:(id)anObject withDefaultAttributes:(NSDictionary *)attributes {<br />	return [super attributedStringForObjectValue:anObject withDefaultAttributes:attributes];<br />}<br /><br />
    

    Du coup, maintenant si l'utilisateur entre a, ou nn ou abs... c'est automatiquement corrigé à  l'affichage, et dans le modèle c'est bien la valeur (-1 pour absent et -2 pour non noté) qui convient qui est stockée.

    Impeccable. Il est quand même bien foutu ce framework !
  • Bonjour,


     


    Je remonte ce sujet, car depuis que je suis passé à  ML, j'ai un soucis avec un custom NSFormatter.


    En effet, l'outlet formatter des dataCell d'une tableColumn est connecté à  une instance de mon NSFormatter dont le code est ci-dessous. Cela fonctionne, sauf que lorsque je veux éditer alors que la string est vide @"", c'est impossible. La cell n'est éditable que si la string est non vide .. y a-t-il une astuce ??


     


    - (NSString *)stringForObjectValue:(id)obj {
    NSNumber *number=obj;
    switch ([number intValue]) {
    case 0:
    return @"";
    break;
    case 1:
    return @X;
    break;
    case 2:
    return @Abs;
    break;
    case 3:
    return @Ret;
    break;
    case 4:
    return @Exc;
    break;
    case 5:
    return @Inf;
    break;
    default:
    return @"";
    break;
    }
    }
    - (BOOL)getObjectValue:(id *)obj forString:(NSString *)string errorDescription:(NSString  **)error {
    if ([string isEqualToString:@""]) {
    *obj=[NSNumber numberWithInt:0];
    }
    if ([string isEqualToString:@x]||[string isEqualToString:@X]) {
    *obj=[NSNumber numberWithInt:1];
    }
    if ([string isEqualToString:@A]||
    [string isEqualToString:@a]||
    [string isEqualToString:@ab]||
    [string isEqualToString:@Ab]||
    [string isEqualToString:@AB]||
    [string isEqualToString:@Abs]||
    [string isEqualToString:@ABS]||
    [string isEqualToString:@abs]) {
    *obj=[NSNumber numberWithInt:2];
    }
    if ([string isEqualToString:@R]||
    [string isEqualToString:@r]||
    [string isEqualToString:@Re]||
    [string isEqualToString:@re]||
    [string isEqualToString:@RE]||
    [string isEqualToString:@Ret]||
    [string isEqualToString:@RET]||
    [string isEqualToString:@ret]) {
    *obj=[NSNumber numberWithInt:3];
    }
    if ([string isEqualToString:@E]||
    [string isEqualToString:@e]||
    [string isEqualToString:@Ex]||
    [string isEqualToString:@ex]||
    [string isEqualToString:@EX]||
    [string isEqualToString:@Exc]||
    [string isEqualToString:@EXC]||
    [string isEqualToString:@exc]) {
    *obj=[NSNumber numberWithInt:4];
    }
    if ([string isEqualToString:@I]||
    [string isEqualToString:@i]||
    [string isEqualToString:@In]||
    [string isEqualToString:@in]||
    [string isEqualToString:@IN]||
    [string isEqualToString:@Inf]||
    [string isEqualToString:@INF]||
    [string isEqualToString:@inf]) {
    *obj=[NSNumber numberWithInt:5];
    }
    return YES;
    }
    - (NSAttributedString *)attributedStringForObjectValue:(id)anObject withDefaultAttributes:(NSDictionary *)attributes {
    return [super attributedStringForObjectValue:anObject withDefaultAttributes:attributes];
    }
  • Bonsoir,


    Je regarde ce nombre de lignes de code et je me pose cette question: cela aide-t-il vraiment l'utilisateur de pouvoir entrer I, i, In, in, IN, Inf, INF, inf? et de se souvenir de ne pas entrer iNf? Cette pseudo-souplesse entraà®ne un coût élevé de vérifications qui ne mettent pas l'application à  l'abri d'un code erroné...


     


    Et si tu remplaçais l'entrée texte par un menu déroulant offrant, en clair, les choix possibles? Tu récupères l'article de menu choisi et tu attribues un code dans ton modèle en deux, voire une ligne de code, sans risque d'erreur, par exemple en utilisant le tag de l'article...


     


    Bon, moi je dis ça, c'est une suggestion...


  • Merci de ta réponse. Je vais essayer avec une combo + formatter


     


    En fait, je dois faire un lien entre un NSString et un NSNumber  (sur cet ex, ce n'est pas une obligation, mais sur un autre oui : par exemple, je dois pouvoir dire qu'un élève est "absent" via une tableColumn. Dans le modèle de donnée, il s'agit des "notes", soit un flot, un absent doit se traduire par un "-1" par exemple, mais à  l'affichage il faut "Abs". D'où le formatter perso. Ce qui est très bizarre, c'est qu'avant une string vide était éditable, depuis ML, impossible. Il faut que je mette un espace dans la string pour que les cell soient évitable, ce qui n'est pas propre. J'essaye avec une combo.


  • Tu peux aussi regarder du côté de NSValueTransformer s'il s'agit de "reformatter" une valeur en une valeur quelconque. Mais l'idée est que l'utilisateur, par définition, fera immédiatement la seule chose à  laquelle tu n'auras pas pensé. Au lieu de te pencher sur son épaule et lui dire "Euh... non, ça il faut pas le faire", il convient de limiter ses actions aux seuls cas que tu auras prévus (même si le lambda échappe souvent aux prévisions)  ^_^


     


    D'après le code ci-dessus, si "Abs" veut dire absent, la fonction retourne 2, pas -1...


     


    Vérifie si ta "string vide" est égale à  @"" et pas à  NIL, ce n'est bien sûr pas la même chose...


  • Outre le fait que voir des magic numbers fait bizarre, il doit y a un truc avec regex qui pourrait te simplifier les tests...

    Sinon, une idée toute simple serait de faire NSString stringBis = [string upperCase]; et de limiter ainsi le nombre de tests. Bon, par contre, cela validerait le aBc ce que ne fait pas ton code actuellement...

    Un truc que je n'ai pas compris : ta méthode retourne YES quoi qu'il arrive ?
  • Un truc que je n'ai pas compris : ta méthode retourne YES quoi qu'il arrive ?

    Euh... merci d'avoir soulevé le problème !


     


    Merci pour le uppercase, cela va limiter les tests.


     


    J'ai vu les méthodes isPartialStringValid ... Je vais voir si je peux en faire quelque chose. Merci de vos pistes !


  • Plutôt que le upperCase, y'a aussi compare:options, dans lequel tu peux mettre un NSCaseInsensitiveSearch.

    J'avoue que j'ai pas testé, mais ce sont des trucs que je vois parfois quand j'cherche dans NSString.


  • AliGatorAliGator Membre, Modérateur

    +1 pour "-compare:options:"


Connectez-vous ou Inscrivez-vous pour répondre.