从Finder拖放到NSTableView怪异

时间:2014-04-11 09:22:33

标签: objective-c cocoa drag-and-drop

我试图了解如何最好地将文件从Finder拖放到NSTableView,随后将列出这些文件。

我已经建立了一个小test application作为试验场。

目前我只有一个NSTableView FileListController作为数据。它基本上是File个对象的NSMutableArray。

我试图找出最佳/正确的方法来实现NSTableView的拖放代码。

我的第一种方法是继承NSTableView并实现所需的方法:

TableViewDropper.h

#import <Cocoa/Cocoa.h>

@interface TableViewDropper : NSTableView

@end

TableViewDropper.m

#import "TableViewDropper.h"

@implementation TableViewDropper {
    BOOL highlight;
}

- (id)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if (self) {
        // Initialization code here.
        NSLog(@"init in initWithCoder in TableViewDropper.h");
        [self registerForDraggedTypes:@[NSFilenamesPboardType]];
    }
    return self;

}

- (BOOL)performDragOperation:(id < NSDraggingInfo >)sender {
    NSLog(@"performDragOperation in TableViewDropper.h");
    return YES;
}


- (BOOL)prepareForDragOperation:(id)sender {
    NSLog(@"prepareForDragOperation called in TableViewDropper.h");
    NSPasteboard *pboard = [sender draggingPasteboard];
    NSArray *filenames = [pboard propertyListForType:NSFilenamesPboardType];
    NSLog(@"%@",filenames);
    return YES;
}

- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
{
    highlight=YES;
    [self setNeedsDisplay: YES];
    NSLog(@"drag entered in TableViewDropper.h");

    return NSDragOperationCopy;
}

- (void)draggingExited:(id)sender
{
    highlight=NO; 
    [self setNeedsDisplay: YES];
    NSLog(@"drag exit in TableViewDropper.h");
}

-(void)drawRect:(NSRect)rect
{
    [super drawRect:rect];

    if ( highlight ) {
        //highlight by overlaying a gray border
        [[NSColor greenColor] set];
        [NSBezierPath setDefaultLineWidth: 18];
         [NSBezierPath strokeRect: rect];
    }
}

@end

draggingEntereddraggingExited方法都会被调用,但prepareForDragOperationperformDragOperation不会被调用。我不明白为什么不呢?

接下来,我想我将继承NSTableView的ClipView的子类。因此,使用与上面相同的代码,只是将头文件中的类类型转换为NSClipView,我发现prepareForDragOperationperformDragOperation现在按预期工作,但ClipView并不突出显示。

如果我将NSScrollView子类化,则调用所有方法并突出显示但不是必需的。它非常薄,正如预期的那样围绕着整个NSTableView而不仅仅是我喜欢的桌面下方的位。

所以我的问题是sublclass是什么是正确的,我需要什么方法,以便当我从Finder执行拖放操作时,ClipView会正确突出显示prepareForDragOperationperformDragOperation调用。

performDragOperation成功时,该方法如何调用FileListController中的方法,告诉它创建一个新的File对象并将其添加到NSMutableArray?

1 个答案:

答案 0 :(得分:5)

回答我自己的问题。

似乎继承NSTableView(不是NSScrollView或NSClipView)是正确的方法。

在子类中包含此方法:

- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender {
return [self draggingEntered:sender];
}

解决了prepareForDragOperationperformDragOperation未被调用的问题。

要允许您在控制器类中调用方法,可以将NSTextView的delagate作为控制器。在这种情况下FileListController

然后在NSTableView子类中的performDragOperation内使用类似:

的内容
NSPasteboard *pboard = [sender draggingPasteboard];
NSArray *filenames = [pboard propertyListForType:NSFilenamesPboardType];

id delegate = [self delegate];

if ([delegate respondsToSelector:@selector(doSomething:)]) {
        [delegate performSelector:@selector(doSomething:) 
                       withObject:filenames];
}

这将调用控制器对象中的doSomething方法。

Updated example project code here.