Intercepter l'action d'un binding (ici sur NSTextView et attributedString)
Chacha
Membre
Salut,
J'ai une NSTextView avec un binding "attributedString" activé et fonctionnel: quand je sélectionne un objet dans une tableview, ma NSTextView affiche une chaà®ne relative à cet objet.
Par contre, j'aimerais intercepter le moment où la NSTextView a changé son texte, pour effectuer quelques traitements supplémentaires dans cette NSTextView (coloration syntaxique... en fait c'est ici une sous-classe de NSTextView)
Le plus logique serait d'attendre un textDidChange:, mais celui-ci n'est pas déclenché. J'ai bien essayé de surcharger des tas de méthodes dans ma sous-classe de NSTextView, activer des notifications... mais je n'ai pu trouver comment intercepter cette application de attributedString.
Une idée ?
+
Chacha
[edit]
Résolu : http://www.objective-cocoa.org/forum/index.php/topic,2807.msg27989.html#msg27989
J'ai une NSTextView avec un binding "attributedString" activé et fonctionnel: quand je sélectionne un objet dans une tableview, ma NSTextView affiche une chaà®ne relative à cet objet.
Par contre, j'aimerais intercepter le moment où la NSTextView a changé son texte, pour effectuer quelques traitements supplémentaires dans cette NSTextView (coloration syntaxique... en fait c'est ici une sous-classe de NSTextView)
Le plus logique serait d'attendre un textDidChange:, mais celui-ci n'est pas déclenché. J'ai bien essayé de surcharger des tas de méthodes dans ma sous-classe de NSTextView, activer des notifications... mais je n'ai pu trouver comment intercepter cette application de attributedString.
Une idée ?
+
Chacha
[edit]
Résolu : http://www.objective-cocoa.org/forum/index.php/topic,2807.msg27989.html#msg27989
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
quite peut-être à faire le binding à la main :
- (void)addObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context
NSTextViewDidChangeSelectionNotification ?
Oui, j'avais essayé aussi, mais sans succès. Comme je ne suis pas très fort en Bindings, j'ai préféré ne pas dire que c'était une fausse piste, car j'aurais très bien pu m'y fourvoyer.
Le NSTextViewDidChangeSelectionNotification ne semble pas adapté : ce n'est pas la sélection qui change...
Je crois que mon problème doit pouvoir s'inscrire dans un cadre plus général; comment "intercepter un binding", NSTextView ou pas... Comme toi, je m'attendais à ce que le "addObserver:" à la main fonctionne. Si ce n'est pas le cas, c'est qu'une subtilité nous échappe.
• NSFormatter
• La méthode de NSTextView shouldChangeTextInRange:replacementString:
Sauf quand il n'y a pas de setter... "setAttributedString" n'existe pas dans NSTextView.
Chez moi ça provoque "this class is not key value coding-compliant for the key value" ("value" est bien le nom de ma NSAttributedString) si je coche cette case. C'est bizarre, car par ailleurs, (si je ne coche pas cette case) mon binding marche bien, en lecture/écriture.
Même si ça marchait (ce n'est pas le cas), cela interviendrait avant que la nouvelle chaà®ne ait été placée.
Bref, toujours bloqué :crackboom:-
Je me demande si tu ne peux pas aussi regarder du côté de setKeys:triggerChangeNotificationsForDependentKey: .
L'une ou l'autre des méthodes doit dépendre de la manière dont tu traites la colorisation et aussi si tu recois les méhodes du genre textDidChange: avant ou apres les méthodes qui te préviendront du changement de la clef correspondant au texte colorisé.
As tu essayé le delegate de NSTextStorage ?
Je pense à textStorageDidProcessEditing: qui devrait être appelé quand textStorage a fini d'être modifié.
textStorage stocke la attributedString qui est affichée par NSTextView, et est accessible via la méthode textStorage.
Il faut régler ton text view sur Rich Text pour que que le binding soit en AttributedString, et cela change "value" en quelque chose comme "atributed value"
Cela marcherait tout autant avec une attributedString, le text view réglé sur Rich Text, le binding sur Attributed String :
@interface TextViewController : NSObject {
NSString * textViewValue;
IBOutlet NSTextView * textView;
}
@property (retain) NSString * textViewValue;
@end
@implementation TextViewController
@dynamic textViewValue;
-(NSString *) textViewValue {return textViewValue;}
-(void) setTextViewValue:(NSString *) value
{
[textViewValue release];
textViewValue=[[value uppercaseString] copy];
[textView setString:textViewValue];
}
@end
Ah mais non. Je ne parle pas d'un texte uniformément coloré, mais de coloration syntaxique nécessitant une analyse grammaticale. Je vous ai simplifié le tableau, mais le travail que fait ma sous-classe de NSTextView n'est pas une transformation basique.
Tout comme avec les addObserver, je n'arrive pas mieux à intercepter le binding correspondant à attributedString.
Justement, si une de ces méthodes était appelée quand le binding attribue une nouvelle attributedString à ma NSTextView, je n'aurais pas de souci.
Oui, j'ai essayé. Le souci, c'est que ma coloration syntaxique va elle-même appeler textStorageDidProcessEditing:. Je pourrais briser la récursivité avec un truc un peu crade, mais je trouve que c'est une mauvaise solution, parce que c'est s'insérer au mauvais endroit de la cascade d'événements.
Ma textview est déjà en Rich Text. Je suppose que chez toi, la structure est un peu différente. Ma NSTextView a un binding "attributedString" sur un champ particulier d'un dictionnaire (champ que j'ai labelisé "value", l'autre entrée du dictionnaire étant un "name"), et ce dictionnaire est la "selection" courante d'un NSArrayController (contenant donc plusieurs dictionnaires).
Voir plus haut ce que je détaille à Fouf : j'ai vraiment besoin d'une NSTextView.
Le formatter ne va pas m'aider.
Un formatter maison permet de faire n'importe quelle analyse sur le texte que l'on veut formatter.
Ma NSTextView fonctionne de concert avec une NSRuleView pour compter les lignes, afficher les numéros, ajouter des marqueurs dans les marges, et aussi colorer le texte.... je pense que cela sort un peu du rôle du formatteur
Pourquoi pas la solution du TextViewController ? Tu l'instancie et connecte dans le nib, il joue le rôle d'un textViewSystemFormatter ...
A chaque changement de ton texte, tu as la main par un outlet sur ton textview, ou sur l'ensemble de l'UI pour réagir ...
Tu peux peut-être même profiter de fonctionnalités de la classe NSObjectController
Mauvaise nouvelle, je ne la comprends pas vraiment.
La voici :
Dans ma sous-classe de NSTextView, je surcharge bind:toObject:withKeyPath:options: pour y effectuer un addObserver:forKeyPath:options:context: pour la clef qui m'intéresse. Ainsi, je peux surcharger observeValueForKeyPath:ofObject:change:context.
Mes problèmes :
1)Surcharger bind:toObject:... paraà®t logique pour intercepter la création des bindings déclarés dans IB, mais je ne comprends pas pourquoi le addObserver:... n'est pas implicite dans l'implémentation par défaut de bind:toObject:...
Je suspecte une histoire d'objets proxy du style NSNotyfyingKVO_... que j'ai déjà aperçus dans le debbugger.
2)De plus, pour que ça marche, il semblerait que je ne dois pas appeler [super bind:toObject:...] pour la clef pour laquelle je fais le addObserver: (cela génère des erreurs au run-time). Et ça, ça me paraà®t encore moins logique.
+
Chacha
Tu y as sans doute pensé, mais le problème ne serait-il pas que la méthode recolourCompleteDocument changeant les attributs du texte, le binding est réactivé par un setter correspondant, créant ainsi une boucle infinie ?
Non non, l'erreur qui s'affichait semblait plutôt due à une confusion dans les envois de messages.
Je vois que toi aussi ça te paraà®t bizarre, je ne suis donc pas fou !
Mais en réalité, c'est maintenant corrigé, et la forme qui marche est bien celle-ci :
Apparemment, mon .NIB avait un problème. Des erreurs bizarres m'ont finalement fait remarquer que j'étais dans le cas où InterfaceBuilder sauvegarde les bindings dans un ordre indéterminé (dans des cas d'interdépendances complexes). Parce que en resauvegardant, des fois ça marchait ! http://lists.apple.com/archives/xcode-users/2008/Jul/msg00967.html
Je m'en suis sorti en virant les bindings de IB et en les créant à la main dans le code.
+
Chacha