简体   繁体   中英

How to use a NSStatusItem as a drag destination?

I'm trying to build an application that allows users to drag files from Finder to the menubar icon for processing. I've made progress in my journey, but I can't seem to summit this hill. I tried subclassing NSView and implementing the drag messages.

@interface CMDroppableView : NSView <NSMenuDelegate>

I wanted to not only accept drag operations, but to provide a NSMenu when the user clicks the icon. I've managed to get the NSMenu to display properly, but the drag functionality remains elusive.

It's my understanding that I needed to register the accepted drag types which I have done here:

-(void)awakeFromNib{
[self registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]];
}

Drag messages:

-(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender{
    NSLog(@"Drag Enter");
    return NSDragOperationCopy;
}

-(NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender{
    return NSDragOperationCopy;
}

-(void)draggingExited:(id <NSDraggingInfo>)sender{
    NSLog(@"Drag Exit");
}

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

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

Here is the code where the custom view is set:

statusItemView = [[CMDroppableView alloc] init];
[statusItemView retain];
[statusItemView setMenu: statusMenu];

[statusItem setView: statusItemView];   

Still nothing. So where have I gone wrong?

Thanks!

Through trial and error I stumbled onto the solution. I was registering my acceptable drag types within the awakeFromNib message (as seen in the original question). However, I was not using IB to set this view up so this method was never called. Moving the registration code to the initFromFrame message seemed to fix the problem.

- (id)initWithFrame:(NSRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        ...
        [self registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]];
    }
    return self;
}

Edit: D'oh, you're registering the drag types in -awakeFromNib , which won't be called if the view isn't being loaded from a nib. Try registering your drag types in -initWithFrame: instead!

Old answer:

IIRC you need to not set the menu on the status item. What I do is have my custom view manage a menu, and do something like this:

- (void)setMenu:(NSMenu *)menu {
    [menu setDelegate:self];
    [super setMenu:menu];
}

- (void)mouseDown:(NSEvent *)event {
    [statusItem popUpStatusItemMenu:[self menu]]; // or another method that returns a menu
}

- (void)menuWillOpen:(NSMenu *)menu {
    highlight = YES;
    [self setNeedsDisplay:YES];
}

- (void)menuDidClose:(NSMenu *)menu {
    highlight = NO;
    [self setNeedsDisplay:YES];
}

- (void)drawRect:(NSRect)rect {
    NSImage *img = highlight ? [alternateImage copy] : [image copy];
    NSRect bounds = [self bounds];
    [statusItem drawStatusBarBackgroundInRect:bounds withHighlight:highlight];

    // rest of drawing code goes here, including drawing img where appropriate
}

in my custom view's implementation. This ensures the menu behavior is identical to the default.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM