自定义NSView拖动目标

时间:2011-09-12 08:51:26

标签: macos cocoa drag-and-drop osx-lion

我正在尝试创建一个简单的NSView,它允许将Finder中的文件夹拖到它上面。文件夹路径是我希望视图作为可拖动项目接受的唯一事物。我一直试图遵循Apple documentation,但到目前为止没有任何工作。到目前为止,我只是试图让视图适用于任何文件类型,但我似乎甚至无法做到这一点。这是我到目前为止所做的:

-(id) initWithFrame:(NSRect)frameRect
{
    if (self = [super initWithFrame:frameRect])
    {
        NSLog(@"getting called");
        [self registerForDraggedTypes:[NSArray arrayWithObjects:NSPasteboardTypeString,
                                       NSPasteboardTypePDF,
                                       NSPasteboardTypeTIFF,
                                       NSPasteboardTypePNG,
                                       NSPasteboardTypeRTF,
                                       NSPasteboardTypeRTFD,
                                       NSPasteboardTypeHTML,
                                       NSPasteboardTypeTabularText,
                                       NSPasteboardTypeFont,
                                       NSPasteboardTypeRuler,
                                       NSPasteboardTypeColor,
                                       NSPasteboardTypeSound,
                                       NSPasteboardTypeMultipleTextSelection,
                                       NSPasteboardTypeFindPanelSearchOptions, nil]];
    }
    return self;
}

-(BOOL) prepareForDragOperation: (id<NSDraggingInfo>) sender
{
    NSLog(@"preparing for drag");

    return YES;
}

调用initWithFrame:方法,但是当我尝试拖入视图时,prepareForDragOperation:方法似乎永远不会被调用。我的问题:

  1. 我做错了什么?为什么prepareForDragOperation:没有被调用?
  2. 如何让拖动操作仅支持拖动文件夹?
  3. 更新

    我用我能找到的每种类型更新了我的registerForDraggedTypes:方法。它现在看起来像这样:

    [self registerForDraggedTypes:[NSArray arrayWithObjects:NSPasteboardTypeString,
                                   NSPasteboardTypePDF,
                                   NSPasteboardTypeTIFF,
                                   NSPasteboardTypePNG,
                                   NSPasteboardTypeRTF,
                                   NSPasteboardTypeRTFD,
                                   NSPasteboardTypeHTML,
                                   NSPasteboardTypeTabularText,
                                   NSPasteboardTypeFont,
                                   NSPasteboardTypeRuler,
                                   NSPasteboardTypeColor,
                                   NSPasteboardTypeSound,
                                   NSPasteboardTypeMultipleTextSelection,
                                   NSPasteboardTypeFindPanelSearchOptions,
                                   NSStringPboardType,
                                   NSFilenamesPboardType,
                                   NSPostScriptPboardType,
                                   NSTIFFPboardType,
                                   NSRTFPboardType,
                                   NSTabularTextPboardType,
                                   NSFontPboardType,
                                   NSRulerPboardType,
                                   NSFileContentsPboardType,
                                   NSColorPboardType,
                                   NSRTFDPboardType,
                                   NSHTMLPboardType,
                                   NSURLPboardType,
                                   NSPDFPboardType,
                                   NSVCardPboardType,
                                   NSFilesPromisePboardType,
                                   NSMultipleTextSelectionPboardType, nil]];
    

    我注意到当我将文件夹拖到视图中时,没有调用prepareForDragOperation:方法。我错过了一步吗?

2 个答案:

答案 0 :(得分:26)

这是一个简单的小拖拽删除符合这些标准的视图:

MDDragDropView.h

@interface MDDragDropView : NSView {
    BOOL        isHighlighted;
}

@property (assign, setter=setHighlighted:) BOOL isHighlighted;

@end

MDDragDropView.m

@implementation MDDragDropView

@dynamic isHighlighted;

- (void)awakeFromNib {
    NSLog(@"[%@ %@]", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
    [self registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, nil]];
}

- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender {
    NSLog(@"[%@ %@]", NSStringFromClass([self class]), NSStringFromSelector(_cmd));

    NSPasteboard *pboard = [sender draggingPasteboard];

    if ([[pboard types] containsObject:NSFilenamesPboardType]) {

        NSArray *paths = [pboard propertyListForType:NSFilenamesPboardType];
        for (NSString *path in paths) {
            NSError *error = nil;
            NSString *utiType = [[NSWorkspace sharedWorkspace]
                                       typeOfFile:path error:&error];
            if (![[NSWorkspace sharedWorkspace] 
                      type:utiType conformsToType:(id)kUTTypeFolder]) {

                [self setHighlighted:NO];
                return NSDragOperationNone;
            }
        }
    }
    [self setHighlighted:YES];
    return NSDragOperationEvery;
}

其余的方法:

- (void)draggingExited:(id <NSDraggingInfo>)sender {
    [self setHighlighted:NO];
}


- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender  {
    return YES;
}

- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender {
    [self setHighlighted:NO];
    return YES;
}
- (BOOL)isHighlighted {
    return isHighlighted;
}

- (void)setHighlighted:(BOOL)value {
    isHighlighted = value;
    [self setNeedsDisplay:YES];
}

- (void)drawRect:(NSRect)dirtyRect {
    [super drawRect:dirtyRect];
    if (isHighlighted) {
        [NSBezierPath setDefaultLineWidth:6.0];
        [[NSColor keyboardFocusIndicatorColor] set];
        [NSBezierPath strokeRect:self.frame];
    }
}

@end

未调用prepareForDragOperation:的原因是拖动目标序列遵循一组精确的步骤,如果前面的步骤未实现或已实现但返回“停止拖动操作”答案的类型,从未达到后面的方法。 (在您的情况下,您似乎没有实现draggingEntered:方法,该方法需要返回NSDragOperationNone以外的其他内容才能继续执行。

在发送prepareForDragOperation:之前,视图首先会发送一系列拖动目标消息:

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

根据从该方法返回的NSDragOperation掩码,如果在您的类中实现了以下内容,则会调用以下内容:

多个- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender

根据该方法返回的NSDragOperation掩码,将调用prepareForDragOperation:

答案 1 :(得分:0)

我正在使用NSURLPboardType注册从Finder中删除的内容(当我将文件或文件夹拖到我的应用程序时,它会将其作为网址接收) 试试这个。如果它有效,它将解决您的第二个问题:只检查URL是否是接受或拒绝丢弃的文件夹:

// if item is an NSURL * :
CFURLHasDirectoryPath((CFURLRef)item)
// returns true if item is the URL of a folder.