NSTextField et finir la frappe

mac_manumac_manu Membre
18:30 modifié dans API AppKit #1
Bonjour,
Qui peut m'expliquer comment procéder pour, comme les NSComboBox, "deviner" un mot lors de la saisie de texte dans une NSTextField? Si vous avez un pt'it exemple, j'suis preneur. ;)
Merci

Réponses

  • Eddy58Eddy58 Membre
    18:30 modifié #2
    Et bien NSComboBox est une sous-classe de NSTextField...Donc dans ton cas, il faudrait faire aussi une sous-classe, qui comparerait la chaine dans le textfield avec une liste de chaines, pour modifier le contenu du textfield en fonction. Mais pourquoi ne pas utiliser tout simplement NSComboBox ? :)
  • BruBru Membre
    18:30 modifié #3
    dans 1113849364:

    Bonjour,
    Qui peut m'expliquer comment procéder pour, comme les NSComboBox, "deviner" un mot lors de la saisie de texte dans une NSTextField? Si vous avez un pt'it exemple, j'suis preneur. ;)
    Merci


    C'est à  toi de programmer ça.

    NSControl te fournit un delegate tout beau tout chaud pour ça :
    control:textView:completions:forPartialWordRange:indexOfSelectedItem:

    .
  • mac_manumac_manu Membre
    18:30 modifié #4
    Merci les gars pour ces réponses. Je vais de ce pas faire mes essais. Pour répondre à  Eddy58, si je n'utilise pas une NSComboBox, c'est justement pour me donner la possibilité d'apprendre quelques choses de nouveau, car c'est en rencontrant des difficultés que je progresse dans mon aprentissage Cocoa. Je suis un amateur super passionné... et désireux de m'améliorer. Et grâce à  vous, grâce à  ce site, je peux y arriver. Thanks  :p
  • mac_manumac_manu Membre
    18:30 modifié #5
    dans 1114000553:

    dans 1113849364:

    Bonjour,
    Qui peut m'expliquer comment procéder pour, comme les NSComboBox, "deviner" un mot lors de la saisie de texte dans une NSTextField? Si vous avez un pt'it exemple, j'suis preneur. ;)
    Merci


    C'est à  toi de programmer ça.

    NSControl te fournit un delegate tout beau tout chaud pour ça :
    control:textView:completions:forPartialWordRange:indexOfSelectedItem:

    .


    Essayé, pas encore pu! Faut-il sous-classer NSTextView? Quelle action déclenche le processus (pour controlTextAsChange par ex. c'est chaque fois que le texte change, via le delegate) par contre pour ce cas là , je ne vois pas très bien.  :-\\
  • BruBru Membre
    18:30 modifié #6
    Excuse, mais je n'avais pas vraiment compris ton besoin, alors je t'ai aiguillé sur la mauvaise piste.

    Le delegate que je t'ai donné permet de compléter une saisie, mais il faut appuyer sur la touche F5.

    Toi, je crois que tu veux, au cours de la saisie, que cette dernière soit complétée avec ce qui se rapproche le plus dans une liste ?

    Dans ce cas, il faut plutôt passer par un formatter... Je teste ça et je te tiens au courant.

    .
  • mac_manumac_manu Membre
    18:30 modifié #7
    Merci Bru, c'est exactement cela. Comme dans iTunes, lorsque tu introduis les données dans les champs correspondants, dans la fenêtre "info sur le morceau".
  • fouffouf Membre
    18:30 modifié #8
    En fait, je ne vois pas en quoi c'est incompatible. C'est la même chose mais sans taper sur la touche F5. Comme dans XCode.
  • mac_manumac_manu Membre
    18:30 modifié #9
    Je reviens à  la charge: Avec le delegate

    control:textView:completions:forPartialWordRange:indexOfSelectedItem:

    où faut-il l'implémenter? Faut-il subclasser NSTextField? où faut-il appeler la method? Vraiment, pour l'instant, je nage...
  • fouffouf Membre
    18:30 modifié #10
    Dans un de tes controlleurs, tu fais
    [monTextField setDelegate:self];
    


    Ensuite, tu implémentes la méthodes.
  • mac_manumac_manu Membre
    18:30 modifié #11
    OK, je vais essayer. Mais l'implémentation se fait aussi dans mon Controller? Pas besoins d'instancier quoi que ce soit?
  • BruBru Membre
    18:30 modifié #12
    Sans rien faire, tu peux déjà  voir que, en tapant le début d'un mot dans ton NSTextField, puis en appuyant sur F5, le système te fournit une liste de mots approchants (issue du dictionnaire français intégré à  OSX).

    La méthode delegate que je t'ai donné te permet de modifier le contenu de cette liste afin de fournir tes propres propositions.

    Donc, dans IB, tu tires un "trait" entre ton NSTextField et ton contrôleur et tu connectes à  delegate (dans la fenêtre d'Infos). Ensuite, dans XCode, tu implémentes la méthode delegate que je t'ai donné plus haut.

    Par exemple, cette implémentation retourne une liste qui sera constituée de 3 expressions :
    [tt]
    - (NSArray *)control:(NSControl *)control textView:(NSTextView *)textView
                 completions:(NSArray *)words forPartialWordRange:(NSRange)charRange
    indexOfSelectedItem:(int *)index
    {
        return [NSArray arrayWithObjects:@mot 1, @mot 2, @mot 3, nil];
    }
    [/tt]
    A toi de modifier ce NSArray de 3 mots afin de retourner tes propres expressions en fonction de ce que tu veux faire...

    .
  • mac_manumac_manu Membre
    18:30 modifié #13
    OK, ça marche bien. Mais maintenant, j'aimerais que ça fonctionne automatiquement, après chaque frappe clavier, à  la place de devoir presser la touche F5. Est-ce que les méthode de NSTextView- complete: et completionsForPartialWordRange:indexOfSelectedItem: - pourraient faire l'affaire? 2ème, quel Event doit être utilisé pour activer la routine? Faut-il peut-être implémenter- controlTextDidChange:?  :why?:
    Encore mil merci
  • BruBru Membre
    18:30 modifié #14
    dans 1114414521:

    OK, ça marche bien. Mais maintenant, j'aimerais que ça fonctionne automatiquement, après chaque frappe clavier, à  la place de devoir presser la touche F5. Est-ce que les méthode de NSTextView- complete: et completionsForPartialWordRange:indexOfSelectedItem: - pourraient faire l'affaire? 2ème, quel Event doit être utilisé pour activer la routine? Faut-il peut-être implémenter- controlTextDidChange:?  :why?:
    Encore mil merci


    Oui et non.

    En fait, pour pouvoir avoir la liste de proposition au fur et à  mesure de la frappe, je penche sur l'utilisation d'une sous-classe à  NSFormatter.

    J'ai presque terminé l'implémentation de cette classe : je la mettrais ici dès sa finalisation.

    .
  • mac_manumac_manu Membre
    18:30 modifié #15
    Super, j'attends avec... impatience, mais avec beaucoup de... reconnaissance!! 
  • BruBru Membre
    18:30 modifié #16
    Bon.

    J'ai fait un petit truc sans prétention, mais ça marche.

    Il s'agit d'une classe dérivée de NSFormatter (nommé AutoCompleteFormatter) dont le but est de mémoriser une liste d'expression, et ensuite de compléter automatiquement la saisie en cours dans un NSTextField en fonction de ce qui est mémorisée dans la liste.

    Le fonctionnement est simple :
    - le contrôleur dans son awakeFromNib positionne le formatter AutoCompleteFormatter dans le champ NSTextField (que j'ai nommé textField).
    - le contrôleur est delegate du champ NSTextfield afin de récupérer les valeurs saisies dans le champ. Ceci permet de mémoriser dans le formatter (méthode addString:) la saisie.

    fichier controleur.h :
    <br />#import &lt;Cocoa/Cocoa.h&gt;<br /><br />@interface controleur : NSObject<br />{<br />    IBOutlet id textField;<br />}<br />@end<br />
    


    fichier controleur.m :
    <br />#import &quot;controleur.h&quot;<br />#import &quot;AutoCompleteFormatter.h&quot;<br /><br />@implementation controleur<br /><br />- (void)awakeFromNib<br />{<br />	AutoCompleteFormatter *autoCompleteFormatter;<br /><br />	// création d&#39;un formatter et rattachement au textField.<br />	autoCompleteFormatter=[[AutoCompleteFormatter alloc] init];<br />	[textField setFormatter:autoCompleteFormatter];<br />	[autoCompleteFormatter release];<br />}<br /><br />// delegate du textField<br />- (void)controlTextDidEndEditing:(NSNotification *)aNotification<br />{<br />	// à  chaque validation du textField, mémorisation de la saisie dans le formatter.<br />	[[textField formatter] addString:[NSString stringWithString:[textField stringValue]]];<br />}<br /><br />@end<br />
    


    .
  • BruBru Membre
    avril 2005 modifié #17
    fichier AutoCompleteFormatter.h :
    <br />#import &lt;Cocoa/Cocoa.h&gt;<br /><br />@interface AutoCompleteFormatter : NSFormatter<br />{<br />&nbsp; &nbsp; NSMutableArray *_listeString;<br />&nbsp; &nbsp; NSControl *_controle;<br />}<br /><br />- (void)addString:(NSString *)string;<br />- (void)removeAllStrings;<br /><br />@end<br />
    


    fichier AutoCompleteFormatter.m :
    <br />#import &quot;AutoCompleteFormatter.h&quot;<br /><br />// déclaration C<br />static NSString* RetrieveStringBeginningWith(NSArray *liste, NSString *string);<br /><br />@implementation AutoCompleteFormatter<br /><br />// surcharge de la méthode init : allocation du NSArray des chaines.<br />- (id)init<br />{<br />&nbsp; &nbsp; if (!(self=[super init])) return nil;<br />&nbsp; &nbsp; _listeString=[[NSMutableArray alloc] init];<br />&nbsp; &nbsp; return self;<br />}<br /><br />// surcharge de la méthode dealloc : suppression du NSArray des chaines<br />- (void)dealloc<br />{<br />&nbsp; &nbsp; [_listeString release];<br />}<br /><br />// surcharge de la méthode stringForObjectValue (ne fais rien).<br />- (NSString *)stringForObjectValue:(id)anObject<br />{<br />&nbsp; &nbsp; if (![anObject isKindOfClass:[NSString class]]) return nil;<br />&nbsp; &nbsp; return [NSString stringWithString:anObject];<br />}<br /><br />// surcharge de la méthode getObjectValue (ne fais rien).<br />- (BOOL)getObjectValue:(id *)anObject forString:(NSString *)string<br />					&nbsp; &nbsp; errorDescription:(NSString **)error<br />{<br />&nbsp; &nbsp; *anObject=[NSString stringWithString:string];<br />&nbsp; &nbsp; return YES;<br />}<br /><br />// surcharge de la méthode isPartialStringValid<br />// à  chaque modification, recherche de la chaine la plus proche<br />// et mise à  jour du NSTextField.<br />- (BOOL)isPartialStringValid:(NSString **)partialStringPtr<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  proposedSelectedRange:(NSRangePointer)proposedSelRangePtr<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  originalString:(NSString *)origString originalSelectedRange:(NSRange)origSelRange<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  errorDescription:(NSString **)error<br />{<br />&nbsp; &nbsp; NSString *begunString;<br /><br />&nbsp; &nbsp; // on ne fait la recherche que si le curseur ou la sélection<br />&nbsp; &nbsp; // est à  la fin de la saisie.<br />&nbsp; &nbsp; if (origSelRange.location+origSelRange.length==[origString length])<br />&nbsp; &nbsp; {<br />&nbsp; &nbsp; &nbsp; &nbsp; if (begunString=RetrieveStringBeginningWith(_listeString, *partialStringPtr));<br />&nbsp; &nbsp; &nbsp; &nbsp; {<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // une chaine est trouvée : on l&#39;affiche et on met à  jour la sélection.<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; proposedSelRangePtr-&gt;length=[begunString length]-[*partialStringPtr length];<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; *partialStringPtr=begunString;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return NO;<br />&nbsp; &nbsp; &nbsp; &nbsp; }<br />&nbsp; &nbsp; }<br />&nbsp; &nbsp; return YES;<br />}<br /><br />// ajout d&#39;une chaine dans la liste.<br />- (void)addString:(NSString *)string<br />{<br />&nbsp; &nbsp; if (![_listeString containsObject:string])<br />&nbsp; &nbsp; [_listeString addObject:string];<br />}<br /><br />// suppression de toutes les chaines.<br />- (void)removeAllStrings<br />{<br />&nbsp; &nbsp; [_listeString removeAllObjects];<br />}<br /><br />@end<br /><br />// fonction C qui récupère la première chaine dans le NSArray liste<br />// commençant par la NSString string. Renvoie nil si rien trouvé.<br />static NSString* RetrieveStringBeginningWith(NSArray *liste, NSString *string)<br />{<br />&nbsp; &nbsp; NSEnumerator *enumerator;<br />&nbsp; &nbsp; id object;<br />&nbsp; &nbsp; int longueur;<br /><br />&nbsp; &nbsp; longueur=[string length];<br />&nbsp; &nbsp; enumerator=[liste objectEnumerator];<br />&nbsp; &nbsp; while (object=[enumerator nextObject])<br />&nbsp; &nbsp; {<br />&nbsp; &nbsp; &nbsp; &nbsp; if ([(NSString *)object length]&gt;=longueur &amp;&amp; [string isEqualTo:[object substringToIndex:longueur]])<br />&nbsp; &nbsp; &nbsp; &nbsp; {<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return object;<br />&nbsp; &nbsp; &nbsp; &nbsp; }<br />&nbsp; &nbsp; }<br />&nbsp; &nbsp; return nil;<br />}<br />
    


    .
  • mac_manumac_manu Membre
    18:30 modifié #18
    Cela m'a l'air très intéressant. Je vais de ce pas tester sur mon appli. Je te tiens au courant. A+ 
  • mac_manumac_manu Membre
    18:30 modifié #19
    Super, ça marche excellemment bien!! J'ai dû juste faire une petite modification à  ton code, à  savoir:

    if (origSelRange.location+origSelRange.length==[origString length]) && proposedSelRangePtr->location > origSelRange.location)

    pour permettre d'effacer ou de changer la sélection lorsque un texte a été trouvé.

    Mil merci et à  une prochaine, pour d'autres requêtes!!! :kicking:
Connectez-vous ou Inscrivez-vous pour répondre.