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!
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With