Пользовательский NSView Drag Destination - PullRequest
11 голосов
/ 12 сентября 2011

Я пытаюсь создать простой NSView, который позволит перетаскивать на него папку из Finder.Путь к папке - это only , которую я хочу, чтобы представление принималось как перетаскиваемый элемент.Я пытался следовать документации Apple , но пока ничего не работает.До сих пор я только пытался заставить представление работать с любым типом файлов, но я даже не могу этого сделать.Вот что у меня есть:

-(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. Что мне нужно сделать, чтобы операция перетаскивания поддерживала только перетаскивание папок?

Обновление

Я обновил свой метод 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 ]

26 голосов
/ 14 сентября 2011

Вот простой маленький вид перетаскивания, соответствующий этим критериям:

MDDragDropView.h * * 1004

@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:.

0 голосов
/ 13 сентября 2011

Я использую NSURLPboardType, чтобы зарегистрироваться для удаления материалов из Finder (когда я перетаскиваю файл или папку в свое приложение, он получает их в виде URL) Попробуйте это.И если это сработает, это решит вашу вторую проблему: просто проверьте, является ли URL-адрес папкой для принятия или отклоните удаление:

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