Glisser-Déposer images

muqaddarmuqaddar Administrateur
19:42 modifié dans API AppKit #1
Salut,

Je cherche un article sur le glisser/déposer d'images depuis le finder ds une NSImageView... mais je ne sais plus où je l'ai vu.

ça ne vous dit rien ?  :why?:
«1

Réponses

  • AntilogAntilog Membre
    19:42 modifié #2
    un p'tit coup de Cocoa Dev Central?
    http://cocoadevcentral.com/articles/000056.php
  • muqaddarmuqaddar Administrateur
    19:42 modifié #3
    Super Antilog !
    C'est celuil-là , merci ! ;)
  • ChachaChacha Membre
    19:42 modifié #4
    dans 1119967338:

    Je cherche un article sur le glisser/déposer d'images depuis le finder ds une NSImageView...

    Si je puis me permettre : pour glisser/déposer dans une NSImageView, il n'y a rien à  faire, sinon s'assurer que "enabled" est bien coché dans les propriétés de la NSImageView. Donc pour une classe personnalisée, si on dérive de NSImageView, il n'y a pas plus de choses à  faire.
    L'article de CocoaDevCentral traite de ce problème pour les NSView quelconques, où là , il faut effectivement s'occuper soi-même du drop.

    +
    Chacha
  • muqaddarmuqaddar Administrateur
    juin 2005 modifié #5
    Merci chacha.
    A vrai dire, je m'étais posé la question et j'avais essayé... sans succès.
    En fait, c'est parce que c'est editable qui doit être coché, et non enabled ! ;)

    Bon, bein je passe à  la question suivante.
    Je dois sauvegarder cette image qui se rapporte à  une clé d'un array.
    Pour l'instant, toutes les données de l'array sont ds un plist.

    Comment ça se passe pour les images ds un rep? C'est copié en tant qu'image ? c'est encodé ds un fichier ?
  • ChachaChacha Membre
    19:42 modifié #6
    dans 1119970736:

    En fait, c'est parce que c'est editable qui doit être coché, et non enabled !

    Oups ! Désolé.


    Je dois sauvegarder cette image qui se rapporte à  une clé d'un array.
    Pour l'instant, toutes les données de l'array sont ds un plist.

    heu... déjà  je ne comprends pas très bien. Chaque case contient un objet plist ?
    <br />Dans le propertListForType: de NSPasteboard :<br />A property list is an object of NSArray, NSData, NSDictionary, or NSString objects or any combination thereof.<br />
    



    Comment ça se passe pour les images ds un rep? C'est copié en tant qu'image ? c'est encodé ds un fichier ?

    Pareil, je ne comprends pas bien la question...

    +
    Chacha
  • muqaddarmuqaddar Administrateur
    19:42 modifié #7
    Bein en fait, j'ai un plist avec toutes les propriétés de mes dicos ds un array.
    Il n'y a que du texte ou des nombres.

    Pour sauver une image (celle de la NSImageView glissée), je suppose que je dois la convertir en NSData ?
    Quelle est la marche à  suivre ? Il faut un fichier en plus pour sauvegarder toutes les images ? (pour chaque ligne de mon array, il peut y avoir une image)
  • ChachaChacha Membre
    19:42 modifié #8
    dans 1119972205:

    Bein en fait, j'ai un plist avec toutes les propriétés de mes dicos ds un array.

    Bon, dis-moi si j'ai bien compris: tu as donc un dico par case, chaque dico étant un ensemble de propriétés décrivant un objet à  toi. Ton tableau décrit donc l'ensemble de tes objets.


    Pour sauver une image (celle de la NSImageView glissée), je suppose que je dois la convertir en NSData ?

    A priori, non, car une image respecte le protocole NSCoding, donc elle sait se sauvegarder/charger toute seule, dans le cas où on la sauvegarde en utilisant un NSArchiver.
    Après, peut-être utilises-tu une méthode de sauvegarde particulière aux property list, et tu te demandes si elle saura gérer les NSImages ?

    Note que je n'ai pas encore répondu exactement à  ta question, parce qu'il me manque encore quelques détails pour être sûr de ne pas répondre à  côté.

    +
    Chacha
  • muqaddarmuqaddar Administrateur
    19:42 modifié #9
    Je sauve sous cette forme :

    [tt]
    <array>
    <dict>
    <key>1001</key>
    <string>rouge</string>
    <key>1002</key>
    <string></string>
    <key>1003</key>
    <string>fra</string>
    <key>1004</key>
    <string>bor</string>
    <key>1005</key>
    <integer>1</integer>
    </dict>
    </array>
    [/tt]

    En plus, je dois donc rajouter ma clé image, qui correspondra à  l'image déposée. Comment on enregistre les images ds ce cas ?
    merci !
  • ChachaChacha Membre
    19:42 modifié #10
    dans 1119974428:

    Je sauve sous cette forme :

    En utilisant quelle méthode ?
  • muqaddarmuqaddar Administrateur
    19:42 modifié #11
    dans 1119974484:

    dans 1119974428:

    Je sauve sous cette forme :

    En utilisant quelle méthode ?


    [tt]
    - (BOOL)save
    {
    NSMutableArray *tmpArray;
    NSEnumerator *enumerator;
    id tmpVin;

    tmpArray=[NSMutableArray arrayWithCapacity:[_vins count]];
    enumerator=[_vins objectEnumerator];
    while (tmpVin=[enumerator nextObject]) [tmpArray addObject:[tmpVin dictionaryOfProperties]];
    return [tmpArray writeToFile:[@~/Library/Application Support/Vinitheca/Vins.plist stringByExpandingTildeInPath] atomically:YES];
    }
    [/tt]

    Le dicoOfProperties contient toutes les clés...
  • ChachaChacha Membre
    19:42 modifié #12
    dans 1119975530:

    [tmpArray writeToFile:... atomically:YES];


    D'aaaaaccord.
    Bon, à  ma connaissance, il va effectivement y avoir un problème ici pour sauvegarder les NSImage, car une property list ne peut contenir, comme on l'a vu plus haut, que NSArray, NSDictionary, NSString, NSData ou une combinaison de ces classes.

    Donc :

    1ère solution)
    Avant de sauvegarder, tu remplaces chaque image par un NSData qui la représente (par exemple avec -(NSData*) TIFFRepresentation). De ce fait, la sauvegarde marche car tu as vraiment une propertylist. Et au chargement, tu recrées des NSImage avec initWithData.

    2ème solution)
    Au lieu d'utiliser directement le writeToFile de NSArray, tu utilises un bon vieil NSArchiver. Le NSArchiver "sérialize" des objets répondant au protocole NSCoding. En pratique, on utilise souvent la sous-classe NSKeyedArchiver.

    <br />NSData* dataToSave = [NSKeyedArchiver archivedDataWithRootObject:tonArray];<br />[dataToSave writeToFile:... atomically...];<br />
    


    Ou même encore plus court:
    <br />return [NSKeyedArchiver archiveRootObject:tonArray toFile:...];<br />
    


    Par la magie du NSCoding, (implémenté par la plupart des classes Cocoa) le encodeWithCoder de chaque objet sera bien appelé.
    Dans l'autre sens, pour recharger ces données,
    il faudra faire:
    <br />NSData* data = [NSData dataWithContentsOfFile:...];<br />tonArray = [NSKeyedUnarchiver unarchiveObjectWithData:data];<br />[tonArray retain]; //ou un truc du genre, attention à  l&#39;autorelease<br />
    


    Ou encore plus court:
    <br />tonArray = [[NSKeyedUnarchiver unarchiveObjectWithFile:...] retain];<br />
    


    Inconvénient de cette solution, c'est que ton fichier n'est alors plus un fichier texte property list "humainement lisible". Mais pour sauvegarder une property list, il faut avoir une property list.

    3ème solution) Je n'ai pas vérifié si c'était possible, mais peut-être que du fait que NSImage réponde à  NSCoding, il y a une conversion automatique quand on essaye de la sauvegarder comme une propertyList. ça m'étonnerait, sinon je pense que ce serait écrit dans la doc.

    Voilà , j'espère t'avoir dépanné correctement.

    +
    Chacha
  • muqaddarmuqaddar Administrateur
    juin 2005 modifié #13
    Merci de ta super explication Chacha !  :p

    Pour l'instant, j'ai implémenté le coding, donc la solution 2, et ça marche nikel en remplcament du plist !

    Maintenant je m'attaque à  l'image.
    L'image récupérée ds le fichier codé doit aller là  :

    [(NSImageView *)controlView setImage: value];

    Mais pour obtenir "value", je sèche...
    value = [NSImage... quelle fonction pour récupérer l'image à  partir du code et de sa clé ? ]

    Et pareil dans l'autre sens pour enregistrer la NSImage pour sa clé...

    Merci
  • ChachaChacha Membre
    19:42 modifié #14
    dans 1119986113:

    [(NSImageView *)controlView setImage: value];

    Mais pour obtenir "value", je sèche...
    value = [NSImage... quelle fonction pour récupérer l'image à  partir du code et de sa clé ? ]

    Et pareil dans l'autre sens pour enregistrer la NSImage pour sa clé...


    Ben, j'ai cru comprendre que tu avais un dico dans chaque case. Donc dans une case d'indice " i " contenant déjà  un NSMutableDictionary, tu peux utiliser les méthodes setObject:ForKey: et objectForKey:

    <br />[[leTableau objectAtIndex:i] setObject:monImage forKey:laClef];<br /><br />//ou bien dans l&#39;autre sens<br /><br />NSImage* monImage = [[leTableau objectAtIndex:i] objectForKey:laClef];<br />
    


    Mais bon, je sens que ce n'est pas ça que tu voulais savoir. Je reste à  l'écoute.

    +
    Chacha
  • muqaddarmuqaddar Administrateur
    19:42 modifié #15
    C'est parce que c'est plus compliqué que ça. ;-)

    La clé :
    NSImage *_etiquette; // 1006


    Ensuite 2 fonctions :

    Une qui enregistre la propriété :
    - (void)setProperty:(NSString *)property withValue:(id)value
    {
    if ([property intValue]==1006) [_etiquette setImage:value];
    }

    L'autre qui la lit :
    - (id)valueForProperty:(NSString *)property
    {
    id retval;

    if ([property intValue]==1006) retval=[NSImage fonction:_etiquette];
    }
    => là  je sais pas quoi mettre pour reconstruire l'image !


    Et enfin, l'affichage et l'enregistrement dans 2 autres fct:

    Affichage :
    NSImage* monImage = [vin valueForProperty:[NSString stringWithFormat:@%i, 1006]];
    [(NSImageView *)controlView setImage: value];

    Enregsitrement :
    [vin setProperty:[NSImage ... :@%d,ix] withValue: blabla];

    Voilà ... avec des int et des string, ça passait comme une lettre à  la poste... mais je sèche...
  • ChachaChacha Membre
    19:42 modifié #16
    dans 1119987738:

    C'est parce que c'est plus compliqué que ça.

    Oooh, mais je n'en doutais pas ! ;)


    NSImage *_etiquette; // 1006

    - (void)setProperty:(NSString *)property withValue:(id)value
    {
    if ([property intValue]==1006) [_etiquette setImage:value];
    }

    Déjà , là  c'est bizarre, tu dis que _etiquette est une NSImage et tu lui envoies le message "setImage" ?!
  • muqaddarmuqaddar Administrateur
    19:42 modifié #17
    Bon, j'ai tout repris (avec fouf par iChat).

    Une clé NSData :
    NSData	*_etiquette; // 1006
    


    Pour écrire les données de la clé :
    if ([property intValue]==1006) _etiquette=[NSArchiver archivedDataWithRootObject: value];
    


    Pour lire les données de la clé :
    if ([property intValue]==1006) retval=[NSKeyedUnarchiver unarchiveObjectWithData:_etiquette];
    


    Ensuite, pour afficher l'image :
    value = [vin valueForProperty:[NSString stringWithFormat:@&quot;%i&quot;, 1006]];<br />[(NSImageView *)controlView setImage: value];
    


    Et pour l'enregistrer depuis l'imageView :
    [vin setProperty:[NSString stringWithFormat:@&quot;%d&quot;,ix] withValue:[(NSImageView *) controlView image]];
    



    Voilà  à  quoi j'ai droit quand je lis ou que j'enregistre :
    [tt]2005-06-28 22:30:45.377 MySoft[3654] *** -[NSKeyedUnarchiver initForReadingWithData:]: data is empty; did you forget to send -finishEncoding to the NSKeyedArchiver?[/tt]

    >:D :why?: :-\\ :o
  • ChachaChacha Membre
    19:42 modifié #18
    dans 1119991019:

    if ([property intValue]==1006) _etiquette=[NSArchiver archivedDataWithRootObject: value];
    

    if ([property intValue]==1006) retval=[NSKeyedUnarchiver unarchiveObjectWithData:_etiquette];
    


    Attention, tu archives avec un NSArchiver et tu désarchives avec un NSKeyedUnarchiver. Tu aurais du archiver avec un NSKeyedArchiver.
    De plus, gères-tu bien le retain nécessaire pour conserver les données récupérées par le unarchiveObjectWithData ?

    Sinon, il y a quelque chose que je ne m'explique pas. Je ne connais pas ton code, mais est-ce que par hasard tu ne serais pas en train de réinventer le dictionnaire ? Cette histoire de clef, de setProperty.... ça ressemble quand même furieusement à  du setObject:forKey...

    +
    Chacha
  • muqaddarmuqaddar Administrateur
    19:42 modifié #19
    T'inquiète, je ne réinvente pas le dico... ;-)

    J'ai ajouté le Keyed... tjs le bug.

    Il vient de là  :
    value = [vin valueForProperty:[NSString stringWithFormat:@&quot;%i&quot;, 1006]];<br />[(NSImageView *)controlView setImage: value];
    


    [tt]2005-06-28 22:30:45.377 MySoft[3654] *** -[NSKeyedUnarchiver initForReadingWithData:]: data is empty; did you forget to send -finishEncoding to the NSKeyedArchiver?[/tt]
  • muqaddarmuqaddar Administrateur
    juin 2005 modifié #20
    Et si j'enlève le keyed, ça me dit ceci :
    [tt]End of archive encountered prematurely at 0[/tt]

    Et si je le laisse :
    [tt][NSKeyedUnarchiver initForReadingWithData:]: data is empty; did you forget to send -finishEncoding to the NSKeyedArchiver?[/tt]

    :why?:
  • fouffouf Membre
    19:42 modifié #21
    Comment tu fais pour récupérer _etiquette. Ptet qu'il te sort ca parceque _etiquette est nil ?
  • muqaddarmuqaddar Administrateur
    19:42 modifié #22
    Oui, _etiquette est nil au début...
  • ChachaChacha Membre
    19:42 modifié #23
    Je pense qu'il y a un problème dans ton flux de données.
    Que s'affiche-t-il si tu fais :
    <br />{<br />  NSData        *_etiquette = nil;<br />  //je suppose que tu as une property list &quot;value&quot;<br />&nbsp; NSLog(@&quot;value = %@&quot;, value);<br />  _etiquette = [NSKeyedArchiver archivedDataWithRootObject: value];  <br />  NSLog(@&quot;etiquette = %@&quot;, _etiquette);<br />  id retval = nil;<br />  retval=[NSKeyedUnarchiver unarchiveObjectWithData:_etiquette];<br />  NSLog(@&quot;retval = %@&quot;, retval);<br />}<br />
    
  • muqaddarmuqaddar Administrateur
    juin 2005 modifié #24
    Cela me donne ceci :

    [tt]2005-06-29 10:06:41.064 Vinitheca2[4534] retval = (null)
    2005-06-29 10:06:43.182 Vinitheca2[4534] _etiquette = <62706c69 73743030 d4010203 04050607 0a592461 72636869 76657258 24766572 73696f6e 5424746f 7058246f 626a6563 74735f10 0f4e534b 65796564 41726368 69766572 12000186 a0d10809 54726f6f 748000a1 0b55246e 756c6c08 111b2429 3244494c 51535500 00000000 00010100 00000000 00000c00 00000000 00000000 00000000 00005b>[/tt]

    Donc un null pour l'affichage, et de l'hexa pour l'enregsitrement. (je précise qu'à  ce stade, il n'y a pas d'image)

    Et si je mets une image, ça me donne, un kilo d'hexadécimal ds le run log au moment de l'enregsitrement !
  • muqaddarmuqaddar Administrateur
    19:42 modifié #25
    Tient, maintenant l'enregsitrement a l'air de marcher :

    2005-06-29 10:11:04.681 Vinitheca2[4559] retval = NSImage 0x3d7de0 Size={400, 341} Reps=(
        NSBitmapImageRep 0x3d8670 Size={400, 341} ColorSpace=NSCalibratedRGBColorSpace BPS=8 BPP=32 Pixels=400x341 Alpha=YES Planar=NO Format=2
    )

    Mais toujours pas la lecture (même message de data empty).
  • ChachaChacha Membre
    19:42 modifié #26
    dans 1120032484:

    Cela me donne ceci :

    [tt]2005-06-29 10:06:41.064 Vinitheca2[4534] retval = (null)
    2005-06-29 10:06:43.182 Vinitheca2[4534] _etiquette = <62706c69 73743030 d4010203 04050607 0a592461 72636869 76657258 24766572 73696f6e 5424746f 7058246f 626a6563 74735f10 0f4e534b 65796564 41726368 69766572 12000186 a0d10809 54726f6f 748000a1 0b55246e 756c6c08 111b2429 3244494c 51535500 00000000 00010100 00000000 00000c00 00000000 00000000 00000000 00005b>[/tt]

    ça ne peut pas te donner ça ! Dans le code que je t'ai donné, l'affichage de "retval" devrait se faire après celui de "_etiquette", et où est l'affichage de "value" ?
  • muqaddarmuqaddar Administrateur
    19:42 modifié #27
    Oui, retval et value donnent la même chose :

    2005-06-29 10:33:55.615 Vinitheca2[4881] value = NSImage 0x3143a0 Size={400, 341} Reps=(
        NSBitmapImageRep 0x3d6d00 Size={400, 341} ColorSpace=NSCalibratedRGBColorSpace BPS=8 BPP=32 Pixels=400x341 Alpha=YES Planar=NO Format=3
    )
    2005-06-29 10:33:55.662 Vinitheca2[4881] retval = NSImage 0x3d2c30 Size={400, 341} Reps=(
        NSBitmapImageRep 0x3d17d0 Size={400, 341} ColorSpace=NSCalibratedRGBColorSpace BPS=8 BPP=32 Pixels=400x341 Alpha=YES Planar=NO Format=2
    )


    Je pense que l'enregsitrement a l'air de marcher. Le fichier donné est passé de 8 à  540 ko avec une image.
    Mais la lecture ne marche pas du tout.
  • ChachaChacha Membre
    19:42 modifié #28
    dans 1120034059:

    Je pense que l'enregsitrement a l'air de marcher. Le fichier donné est passé de 8 à  540 ko avec une image.
    Mais la lecture ne marche pas du tout.

    Oké.
    Bon, il faut donc voir quel est ton code de sauvegarde/chargement dans un fichier. Si ça se trouve, tu as fait une faute dans le chargement, donc ça ne lit rien du tout, donc il n'y a rien à  décoder et c'est normal que tu obtiennes nil.
  • muqaddarmuqaddar Administrateur
    19:42 modifié #29
    Mon code de désarchivage de NSData (qui contient l'image) c'est celui là  :

    retval=[NSKeyedUnarchiver unarchiveObjectWithData:_etiquette];
    


    qui donne toujours ça :

    2005-06-29 10:45:14.551 Vinitheca2[4910] *** -[NSKeyedUnarchiver initForReadingWithData:]: data is empty; did you forget to send -finishEncoding to the NSKeyedArchiver?
    2005-06-29 10:45:14.551 Vinitheca2[4910] retval = (null)

    Mon code pour enregistrer :

    NSData* dataToSave = [NSKeyedArchiver archivedDataWithRootObject: tmpArray];<br />	[dataToSave writeToFile:[@&quot;~/Library/Application Support/Vinitheca/Vins&quot; stringByExpandingTildeInPath] atomically:YES];
    



    Et celui pour lire le fichier :
    <br />		NSData* data = [NSData dataWithContentsOfFile:[filePath stringByExpandingTildeInPath]];<br />		tmpVins = [NSKeyedUnarchiver unarchiveObjectWithData:data];
    
  • ChachaChacha Membre
    19:42 modifié #30
    Comme toujours, on va voir ce qu'un peu d'affichage peut nous apporter...

    <br />NSData* dataToSave = [NSKeyedArchiver archivedDataWithRootObject: tmpArray];<br />NSString* filePathToSave = :[@&quot;~/Library/Application Support/Vinitheca/Vins&quot; stringByExpandingTildeInPath];<br />NSLog(@&quot;filePathToSave = %@&quot;, filePathToSave);<br />BOOL ok = [dataToSave writeToFile: filePathToSave atomically:YES];<br />NSLog(@&quot;ok = %d&quot;, ok);<br /><br />
    


    <br />NSString* filePathToLoad = [filePath stringByExpandingTildeInPath];<br />NSLog(@&quot;filePathToLoad = %@&quot;, filePathToLoad);<br />NSData* data = [NSData dataWithContentsOfFile: filePathToLoad];<br />NSLog(@&quot;data = %@&quot;, data);<br />tmpVins = [NSKeyedUnarchiver unarchiveObjectWithData:data];<br />
    
  • muqaddarmuqaddar Administrateur
    19:42 modifié #31
    Alors Ok me renvoie 1 :
    2005-06-29 11:10:50.355 Vinitheca2[5039] ok = 1

    Et data me renvoie un paquet d'hexa...
    2005-06-29 11:12:02.945 Vinitheca2[5061] data = <62706c69 73743030 d4000100 02000300 04000500 ... etc
Connectez-vous ou Inscrivez-vous pour répondre.