如何覆盖NSTextField中的拖动接收?

时间:2014-11-02 11:51:34

标签: cocoa drag-and-drop nstextfield

我在Swift中写这个。我有一个NSTextField我在IB中分配了一个由以下内容定义的类:

class MyTextField : NSTextField, NSDraggingDestination {

我已经覆盖了子类中的draggingEntered,draggingUpdated,prepareForDragOperation,performDragOperation,但是这些都没有调用过,系统只是按照自己认为合适的方式将东西放入字段中。我想处理拖动,因为除其他事项外,如果用户将文件拖放到字段中,我不希望将URL粘贴到字段中的默认行为。相反,如果他这样做,我想得到文件的显示名称并改为使用它。

我错过了什么?

1 个答案:

答案 0 :(得分:0)

实现<draggingDestination>协议的任何对象的职责之一是维护一组数据类型,这些数据类型会通知其他人哪种数据会触发您在问题中提到的方法。为了让你的子类处理来自 Finder 或桌面的拖拽,我发现你需要注册三种粘贴板类型。

/* Sorry, not using Swift yet */

// MyNSTextField.m

- (void)awakeFromNib {
    [self registerForDraggedTypes:@[NSPasteboardTypeString,
                                    NSURLPboardType,
                                    NSFilenamesPboardType]];
}

至少在OS X 10.9上,这足以触发draggingEntered方法。如果您在粘贴板上想要的只是文件名,而不是完整的URL或路径,您需要(i)提取名称,(ii)清除粘贴板和(iii)将名称添加回粘贴板:

- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender {

    NSDragOperation operation = NSDragOperationNone;

    NSPasteboard *pBoard = [sender draggingPasteboard];
    NSArray *array = [pBoard readObjectsForClasses:@[[NSURL class], [NSString class]]
                                           options:nil];

    if ([array count] > 0) {
        NSString *filename;
        if ([[array firstObject] isKindOfClass:[NSURL class]]) {
            // Possibly a file dragged from Finder
            NSURL *url = [array firstObject];
            filename = [[url pathComponents] lastObject];

        } else if ([[array firstObject] isKindOfClass:[NSString class]]) {
            // Possibly a file dragged from the desktop
            NSString *path = [array firstObject];
            BOOL isPath = [[NSFileManager defaultManager] fileExistsAtPath:path];
            if (isPath) {
                filename = [path lastPathComponent];
            }
        }

        if (filename) {
            [pBoard clearContents];
            [pBoard setData:[filename dataUsingEncoding:NSUTF8StringEncoding]
                    forType:NSPasteboardTypeString];
            operation = NSDragOperationGeneric;
        }
    }

    return operation;
}

有时拖拽到文本字段会很快发生,上面的方法没有被触发,在这种情况下你会回到同样的问题。解决此问题的一种方法是实现以下文本字段委托方法:

// From NSTextFieldDelegate Protocol
- (void)textDidChange:(NSNotification *)notification

在此方法中,您可以将文本字段的内容与粘贴板的内容进行比较,如果您现在的字段包含有效的系统路径并且此路径与粘贴板的内容匹配,则您需要调整文本字段中的字符串。幸运的是,这似乎发生得如此之快,以至于它看起来就像是正常的粘贴操作。