Dragging Image dans tableView

MickMick Membre
juillet 2014 modifié dans API AppKit #1

Bonjour,


 


J'ai un petit soucis dans la gestion du drag&drop dans une tableView.


En effet, gérer le drag&drop de rows via NSTableViewDataSource ne pose pas de problème. Mon problème vient du fait que je veux pouvoir gérer un drag depuis une imageCell :


Si l'utilisateur drag une image d'une certaine colonne, je dois pouvoir :


=> soit swapper avec une autre image si le drop finit sur une autre row de la même colonne


=> soit "supprimer" la photo si le drop termine hors de la table ou de la colonne.


 


J'ai donc dans un premier temps écrit ceci (subclasse de NSTableView):



- (void)mouseDown:(NSEvent *)theEvent {
    NSInteger row=[self rowAtPoint:[self convertPoint:[theEvent locationInWindow] fromView:nil]];
    NSInteger column=[self columnAtPoint:[self convertPoint:[theEvent locationInWindow] fromView:nil]];
    //Si la colonne n'est pas celle qui contient les images, on ne fait rien.
    if (column==2 && row>=0 && row<[self numberOfRows]) {
        SettingsWindowController *settingsWindowController=(SettingsWindowController*)[self dataSource];
        NSArrayController *arrayControllerTaxos=settingsWindowController.arrayControllerNiveauTaxo;
        NSManagedObject *niveauTaxo=[[arrayControllerTaxos arrangedObjects] objectAtIndex:row];
        NSData *imageData=[niveauTaxo valueForKey:@image];
        NSImage *image=[NSUnarchiver unarchiveObjectWithData:imageData];
        
        if (image!=nil) {
            NSPasteboard *pBoard=[NSPasteboard pasteboardWithName:@suppImagePBoard];
            [pBoard declareTypes:[NSArray arrayWithObject:@myRow] owner:self];
            
            [pBoard setData:[NSArchiver archivedDataWithRootObject:[NSNumber numberWithInteger:row]] forType:@myRow];
            [[self window] dragImage:image at:[theEvent locationInWindow] offset:NSZeroSize event:theEvent pasteboard:pBoard source:self slideBack:NO];
        }
    }
    
    [super mouseDown:theEvent];
}
- (void)draggingSession:(NSDraggingSession *)session endedAtPoint:(NSPoint)screenPoint operation:(NSDragOperation)operation {
    //Si le drop est rejeté par la destination, il faut lancer la suppression,
    //A condition que la souris soit à  l'extérieur de la table
    if (operation==NSDragOperationNone) {
        NSPoint pointVue=[self convertPoint:[[self window] convertScreenToBase:screenPoint] fromView:nil];
        
        if (!NSPointInRect(pointVue, [self bounds])) {
            
            NSPasteboard *pBoard=session.draggingPasteboard;
            if ([pBoard.name isEqualToString:@suppImagePBoard]) {
                NSInteger row=[[NSUnarchiver unarchiveObjectWithData:[pBoard dataForType:@myRow]] integerValue];
                SettingsWindowController *settingsWindowController=(SettingsWindowController*)[self dataSource];
                NSArrayController *arrayControllerTaxos=settingsWindowController.arrayControllerNiveauTaxo;
                NSManagedObject *niveauTaxo=[[arrayControllerTaxos arrangedObjects] objectAtIndex:row];
                
                NSData *imageData=[NSData data];
                [niveauTaxo setValue:imageData forKey:@image];
                NSShowAnimationEffect(NSAnimationEffectPoof, screenPoint, NSZeroSize, nil, nil, nil);
            }
            
        }
        
        
    }
    [super draggingSession:session endedAtPoint:screenPoint operation:operation];
}

Mais cela ne fonctionne pas correctement : à  la fin du drop, tout se passe comme si ... ce n'était pas fini. Du genre, les boutons de la fenêtre (+, - et fermer) ne réagissent pas quand la souris passe dessus, comme si la fenêtre était "figée". Un clic sur la fenêtre remet "tout en place".


 


Sinon, mise à  part le comportement "buggy", cela fonctionne globalement. La bonne image est bien "effacée" accompagné d'un joli "pop".


 


J'ai essayé de subclasser mouseDragged, mais cette méthode n'est jamais appelée...


 


Quelqu'un a-t-il expérimenté ce genre de choses ?

Réponses

  • MickMick Membre
    juillet 2014 modifié #3

    Merci de ton message, mais mon problème n'est pas celui là . En fait tout fonctionne très bien, à  la seule différence que lorsque la subclass de NSTableView reçoit le message draggingSesssion:endedAtPoint:operation:, je traite le problème qui est bien traité, mais tout se passe comme si le drop n'avait pas été terminé. Comme si un objet était sensé recevoir l'info mais ne la recevait pas. Peut-être dois-je passer le message à  un autre objet ? lequel ? 


     


    Je sèche..


     


    PS : Si j'utilise les méthodes de NSTableViewDataSourceProtocol, les rows entières sont enregistrées dans le pasteboard, et l'image draggée est celle de la row. Je ne veux pas que cela se produise si l'utilisateur drag une image située dans la 2e colonne : seule l'image draggée est alors à  traiter, pas la "row".


  • Bon,


     


    j'ai finalement trouvé. Donc pour ceux que cela intéresse : NE PAS SUBCLASSER NSTABLEVIEW. C'est un combat perdu d'avance !


    J'ai donc abandonné l'idée de subclasser NSTableView et d'intercepter mouseDown pour fournir l'image à  dragger. En fait, il faut implémenter les méthodes dataSource. La méthode permettant de customiser l'image draggée est (à  insérer dans tableView:draggingSession:WillBeginAtPoint:ForRowIndexes:) ... 


    session enumerateDraggingItemsWithOptions:NSDraggingItemEnumerationConcurrent forView:tableView classes:[NSArray arrayWithObject:[NSPasteboardItem class]] searchOptions:nil usingBlock:^(NSDraggingItem *draggingItem, NSInteger idx, BOOL *stop)

    C'est dans cette méthode qu'on change les draggingItems : [draggingItem setFrame: ... content:...]


     


    Il fallait la trouver cette méthode pour énumérer les draggingItems !

Connectez-vous ou Inscrivez-vous pour répondre.