NSTreeController
Philippe49
Membre
Bonjour à tous
Peu de documentation sur les NSTreeController, et j'essaie d'ouvrir cette boà®te noire qui n'a pas l'air de fonctionner aussi bien qu'on pourrait l'espérer.
Le premier pas est résumé dans le pdf joint, avec le code source associé.
Qu'en pensez-vous ?
[Fichier joint supprimé par l'administrateur]
Peu de documentation sur les NSTreeController, et j'essaie d'ouvrir cette boà®te noire qui n'a pas l'air de fonctionner aussi bien qu'on pourrait l'espérer.
Le premier pas est résumé dans le pdf joint, avec le code source associé.
Qu'en pensez-vous ?
[Fichier joint supprimé par l'administrateur]
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Cela se poursuit par une brève étude de NSIndexPath
[Fichier joint supprimé par l'administrateur]
[Fichier joint supprimé par l'administrateur]
Moi je ne reproche qu'une chose à NSTreeController, c'est qu'il ne soit pas mieux accompagné.
On ne sait pas ce qui se passe à l'intérieur, contrairement à NSArrayController dont on peut observer les éléments associés avec le KVO ou avec les accesseurs indexés.
Ici, on sait qu'il faut lui donner des noeuds mais on ne peut pas obtenir d'infos plus fines sur la façon dont les noeuds changent.
Je rève d'une classe NSTreeNode qui soit KVO compliant. On pourrait, après avoir modifié l'arbre, obtenir le NSIndexPath affecté par le changement dans le change dictionnary, comme pour un NSMutableArray.
D'aileurs, plutôt que de rêver, j'ai commencé à écrire cette classe NSTreeNode. C'est loin d'être fini mais si ça intéresse, je peux poster mon code en l'état pour susciter des idées.
Ne rêvons plus ...
poste en l'état , c'est un service public naturellement !
Attention, il ne s'agit que d'une possibilité, utilisée dans un certain contexte (mon noeud est destiné à représenter un NSCompoundPredicate), donc ce n'est peut-être pas valable dans tous les cas.
En gros, ça se passe comme ça:
A chaque fois qu'un noeud est créé, il observe ses enfants. Quand un enfant s'insère ou se barre, le parent en informe une instance qui a été créée à l'initialisation (_observer).
De ce fait, on récupère les infos sur les enfants et leurs indexes relatifs dans une classe externe. C'est pour respecter le MVC.
A faire: - au lieu des indexes relatifs, récupérer les NSIndexPath relatifs au rootNode. Et aussi, tant qu'à faire récupérer les niveaux d'imbrication.
Last but not least: un genre de classe dans ce gout là existera dans leopard, comme quoi ça manquait vraiment.
Voici:
Header:
Une remarque :
La méthode isLeaf écrite ainsi ne risque-t-elle pas l'incompatibilité avec une gestion par NSTreeController. En effet pour ajouter un noeud par l'interface graphique, NSTreeController demande d'abord si il à faire à une feuille. Si on crée un NSTreeNode (suffixe NS réservé à Apple) sans fils, on ne pourra jamais ajouter de feuille par l'interface.
Une question que je me pose :
Tu as mis beaucoup de méthodes du style accessor ou KVO. Je me demande toujours dans quelle mesure il faut préciser ces méthodes si leur comportement est standard, du style
-(void) setChamp:(int) aChamp { champ=aChamp;}
Je suis prêt à changer mon fusil d'épaule, mais pour moi, il me semble qu'il faut laisser les mécanismes Cocoa agir, sauf si on a une bonne raison d'intervenir.
J'ai l'impression que tu supposes que ma classe doit être utilisée avec NSTreeController comme controller et NSOutlineView comme View (en reprenant le paradigme Model-View-Controller).
En fait, c'est pas tout à fait ça. Cette classe POURRAIT être utilisée avec NSTreeController (pas testé néanmoins) en spécifiant setObjectClass:[NSTreeNode class]. Mais on est pas obligé, tout comme on est pas obligé d'utiliser NSArrayController pour bénéficier des avantages de la KVO-compliance de NSMutableArray.
Je ne crois pas que j'ai répondu à ta question mais c'est parce qu'on ne parle pas de la même utilisation.
Si on veut insérer ou supprimer des éléments à la main dans la collection observée, on est bien obligé d'appeler ces accesseurs, donc de les avoir dans le code.
C'est si on passe par un NSArrayController qu'on en a pas besoin.
Je suis bien conscient que mon code peut paraitre mélanger plusieurs choses. En fait c'est parce que dans le cas d'un arbre, il faut que chaque noeud "controlle" ses enfants. Donc chaque noeud est à la fois le "model" de son parent et le "controller" de ses enfants. D'où la rupture de la séparation MVC. Je vois pas comment faire autrement.
Oui, j'ai bien compris que tu as fait une classe pour gérer une arborescence profitant du KVO, mais sans pour cela que ce soit forcément lié avec des bidings.
Cela fait déjà quelques temps que je réfléchis sur les structures arborescentes et j'ai écrit des versions sans bindings et là j'essaie avec. Ce qui me semble ressortir de ton expérience et de la mienne c'est qu'il est difficile de faire une classe qui réponde aux deux modèles de fonctionnement sans quelques aménagements. C'est un peu comme si il y avait là deux modèles de structures, difficiles à rendre compatibles. Mais ce n'est peut-être pas impossible ...
Une preuve, c'est que toi comme moi, on met "naturellement" return [children count]; pour la méthode isLeaf. En binding cela coince, en version naturelle c'est logique.
Pour cette question, il me semble que cela vient de la surcharge de cette notion. isLeaf peut signifier l'état d'être sans descendance mais également le fait de ne pas en vouloir. La différence entre stérile et sans enfant.
Cocoa prévoit d'autres mécanismes, comme valueForKey: par exemple.
Ce que je n'ai pas compris dans la doc d'Apple c'est le KVO compliant. Si on lit, on a l'impression qu'il faut mettre ces méthodes, et si on essaie sans, cela marche quand même.
Les erreurs du type "this class is not KVO compliant" que j'ai rencontrées sont en général des erreurs de code, ou des non-définitions de variables, et non des erreurs dues à l'absence de ces méthodes. J'en ai déduit peut-être trop rapidement qu'il y avait deux stratégies :
+ mettre systématiquement toutes ces méthodes (j'ai d'ailleurs fait un programme C pour cela)
+ soit ne les mettre que si leur réaction différait d'une réaction automatique.
Mon expérience est trop courte, je n'ai pas de réponse. Peut-être me trompjes ?
Si tu as du temps, tu peux détailler cela ?
Merci pour ton code, cela m'a permis de confronter mes idées avec les tiennes.
@+
Je vois ce que tu veux dire. Mais tout dépend de ce qu'on veut faire: utiliser normalement NSTreeController avec une classe perso. Ou bien essayer de refaire le mécanisme interne de NSTreeController ( ou ce que je suppose qu'il est) comme dans mon cas.
Je voudrais pas embrouiller encore plus l'affaire mais si on essaie de savoir comment NSTreeController et NSOutlineView discutent ensemble, on peut regarder ceci:
http://www.blueboxmoon.com/wiki/?page=Binding Tree
Effectivement, les accesseurs KVO ne sont en général utiles que s'ils modifient le comportement habituel. Sauf que: si l'on veut modifier des éléments d'une collection à la main (donc pas automatique) et que l'on veut que l'observer de la collection soit prévenu, il faut appeller ces méthodes explicitement. Donc les implémenter dans l'observer.
En fait le problème n'est pas vraiment la "réaction" au changement mais plutôt de savoir si ce changement sera observé ou pas.
Heu ... détailler pourquoi il est plus logique que le parent controlle ses enfants ? Parce que dans une collection "plate", les éléments sont organisés de façon absolue donc on peut les contrôler depuis l'extérieur. Alors que dans une collection en arbre, les enfants sont organisés avec des indexes relatifs à leur parent, donc il parait plus logique que ce soit leur parent qui les contrôle. On peut peut-être faire autrement mais moi j'ai pas trouvé
Tout le plaisir est pour moi. D'ailleurs je n'ai toujours pas trouvé LA solution définitive. Il existe des exemples de classe NSBranche en circulation (assez peu j'ai l'impression) et chacune aborde le problème d'une façon différente.
Voici une autre source qui montre des en-têtes Apple (sur un site perso néammoins)
http://edeltraut.muellner.de/9Pad/trunk/NSTreeController_Extensions.m