Drag'n Drop : ajout d'un objet
Mick
Membre
Bonjour à tous,
Voici mon soucis.
J'ai une tableView qui affiche un certain nombre de choses, le contenu étant fournit à l'aide des bindings (/arrayController). J'utilise CoreData.
J'ai une autre tableView, et j'aimerais pouvoir faire un drag d'une ligne de la premiere tableView, la dropper sur l'autre, et que le release du bouton de la souris déclenche l'ajout d'un objet correspondant à celui qui a été draggé. (Un peu comme dans iTunes où glisser un morceau sur une playList l'ajoute à la playList.. non, en fait c'est pas un peu, c'est exactement ça !)
Quel est le point de départ ?
Voici mon soucis.
J'ai une tableView qui affiche un certain nombre de choses, le contenu étant fournit à l'aide des bindings (/arrayController). J'utilise CoreData.
J'ai une autre tableView, et j'aimerais pouvoir faire un drag d'une ligne de la premiere tableView, la dropper sur l'autre, et que le release du bouton de la souris déclenche l'ajout d'un objet correspondant à celui qui a été draggé. (Un peu comme dans iTunes où glisser un morceau sur une playList l'ajoute à la playList.. non, en fait c'est pas un peu, c'est exactement ça !)
Quel est le point de départ ?
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Tu verras qu'il y a un notion de Clipboard dans lequel on place l'objet à glisser. Cet objet dépend de ce que tu veux faire.
Dans ton exemple, il s'agirait d'un pointeur vers une entité Titre, puisqu'ajouter un titre à une playlist consiste à ce que celle-ci référence le titre.
Dans la doc, il semble qu'il faille implémenter des méthodes de la dataSource. Sauf que si je dis à ma table qu'elle a une dataSOurce, elle va vouloir que j'y implémente les tableView:objectForRow :.. blabla. Sauf que les bindings permettent déjà de peupler la table. Est-il possible de garder les bindings tout en implémentant les méthodes nécessaires au drag/drop ?
Je vais essayer des bricoles et je pense que ... je vais avoir d'autres questions !
Il y avait une page très bien sur les bindings sauf qu'elle était hébergée chez Mobile.me et qu'elle n'est donc plus disponible :-(
Cette page disait que c'était possible.
Je ne l'ai jamais fait personnellement, mais je me demande si tu ne confonds pas deux choses: la datasource et la dragging source.
Sinon, autre soucis ; vu que j'utilise coreData, je n'ai pas de sous-classe NSObject conforme au NSCoding protocol. Or, pour fournir les données au pasteBoard, il faut "archiver" : comment faire avec les entités CoreData ? (la console hurle en cherchant encodeWithCoder lors de mon archiveDataWithRootObject !). Lors du drag, la méthode tableView:WriteRows... blabla est bien appelée. Je récupère alors un NSArray correpondant à la selection d'un NSArrayController. Ce NSArray est peuplé de NSManagedObjects. Lorsque je veux encoder le NSArray, aie aie aie : NSManagedObject ne répond pas à encodeWithCoder...
Ca doit quand même être simple non ? Dois-je abandonner coreData et créer mes propres classes model ? Ca me paraà®t bizarre qu'il n'y ait pas une astuce pour archiver rapidos un NSArray contenant des managedObjects !!
EDIT : Je vais pas me faire ch.. je vais chopper les index selectionnés, et retrouver les données à l'arrivée.
L'archivage et la copie sont des opérations très proches. En effet, désarchiver crée une nouvelle instance de l'objet avec des attributs de mêmes valeurs.
Je vais prendre l'exemple d'un objet Rectangle. Celui-ci possède comme attributs: x, y, largeur, hauteur.
Il a aussi une relation couleurDeRemplissage vers un objet Couleur, qui a des attributs r, v et b.
Si on veut copier l'objet Rectangle, il faut aussi copier la Couleur et faire pointer sur cette nouvelle couleur. En effet, si par la suite l'utilisateur modifie la couleur du rectangle original, on ne veut pas que celle de la copie change et vice-versa.
-> Il s'agit d'une copie profonde (deep copy)
Dans un autre cas de figure, au lieu d'avoir une relation couleurDeRemplissage, le Rectangle a une relation style. Là , par contre, le style est partagé par toutes les instances de Rectangles, ainsi quand on modifie la couleur du style, la couleur de tous les rectangles doit changer. Dans ce cas, copier signifie simplement de créer un nouveau Rectangle mais de pointer sur le même style que l'original.
-> Il s'agit d'une copie de surface (shallow copy)
Pour en revenir à la question, je l'ai posée il y a quelques années sur un forum de dev. Et non, il n'y a pas de moyen simple d'archiver un NSManagedObject, il faudrait créer une sous-classe implémentant le protocole NSCoding. Note qu'il n'y a même pas de moyen simple de copier un NSManagedObject, mais c'est à cause du questionnement expliqué plus haut: pour archiver ou copier, jusqu'où, dans l'arbre d'objets, faut-il aller ?
Sur le forum, un ingé d'Apple m'avait répondu que de toute façon les copies profondes étaient rares. Trois ans après, je n'en suis toujours pas convaincu!
Pour finir, passer à un modèle à base de NSObjects ne va pas résoudre ton problème, puisqu'il faudra implémenter NSCoding sur les objets de la même manière.
Toutefois, je dirais que tu n'as pas forcément besoin d'archiver les NSManagedObjects, mais simplement mettre une liste de pointeurs dans le clipboard. ça dépend s'il faut copier les objets ou pas. Dans l'exemple d'une playlist, par exemple, ce n'est pas nécessaire.
En tout cas, cela fonctionne bien, simplement en archivant un indexSet contenant les index des objets sélectionnés.
En vérité, le drag drop est assez simple avec les tableView.
Dernière chose : et si on veut supprimer un objet par un glisser vers l'extérieur de la table, comment s'y prendre ? (Il n'y a pas d'objet qui "réceptionne" dans ce cas ? où c'est la contentView de la fenetre qui le gère ?..)
C'est donc bien ce que je disais, dans ton cas, tu n'as pas besoin d'archiver les objets, juste la liste des pointeurs.
Je ne l'ai jamais implémenté, mais je pense que c'est le premier cas. Aucun objet graphique ne reconnaà®tra le type de l'objet dans le pasteboard (parce que c'est un type interne à ton appli), et ça doit t'être signalé (dans -draggingSessions:endedAtPoint:operation: avec une operation None ?).
je ne vois pas.
quelqu'un a-t-il déjà implémenté un truc du genre ? (drag puis drop dehors)
Comment savoir qu'un drop a été effectué en dehors de la vue ?
Dois-je sous-classer NSTableView afin de capter les messages draggedImage:endedAtPoint: ... ?
Pur l'instant, je me met une actioncell dans la table pour supprimer un objet, mais bon, c'est plus sympa de faire le geste de le "virer" de la table. C'est plus intuitif , plus Apple quoi !
Par ailleurs, la méthode qui consiste à ne sérialiser qu'une référence vers les objets sélectionnés est plus rapide à coder à court terme mais réfléchis bien à tes évolutions futures. Si tu envisages d'implémenter le couper/copier/coller ou le drag and drop pour dupliquer ou même l'export dans un format autre que Core Data, alors tu devrais tout de suite t'attaquer à la serialisation de tes objets car ce code sera ré-utilisable dans tous ces cas là .
En plus, si on ignore les relations, c'est très simple de convertir un NSManagedObject en dictionary et ensuite de serialiser ce dictionary:
Tu as juste à ajouter une clé "class" pour connaà®tre le type d'objet et une clé "objectID" pour retrouver l'objet original en cas de simple déplacement par drag and drop .
Ici tu as un code qui permet de serialiser aussi les relations sous forme de dictionary :
http://vladimir.zardina.org/2010/03/serializing-archivingunarchiving-an-nsmanagedobject-graph/
Sinon, pas de solution au problème : peut-on dragger une ou plusieurs row d'une table en dehors de la table, et en dehors de toute table acceptant le drag, et recevoir un message disant que le drop a été fait ... nul part où il est accepté afin de supprimer l'objet correspondant. ?