如何使用 NSStatusItem 作为拖动目的地?

Posted

技术标签:

【中文标题】如何使用 NSStatusItem 作为拖动目的地?【英文标题】:How to use a NSStatusItem as a drag destination? 【发布时间】:2011-08-25 17:17:37 【问题描述】:

我正在尝试构建一个允许用户将文件从 Finder 拖到菜单栏图标进行处理的应用程序。我的旅程取得了进展,但我似乎无法登上这座山峰。我尝试继承 NSView 并实现拖动消息。

@interface CMDroppableView : NSView <NSMenuDelegate>

我不仅希望接受拖动操作,而且希望在用户单击图标时提供 NSMenu。我已经设法让 NSMenu 正确显示,但拖动功能仍然难以捉摸。

据我了解,我需要注册我在这里所做的接受的拖动类型:

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

拖动消息:

-(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;

这里是设置自定义视图的代码:

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

[statusItem setView: statusItemView];   

还是什么都没有。那我哪里做错了?

谢谢!

【问题讨论】:

你实现了 draggingEntered: 和 performDragOperation: 方法吗? 是的,我有。我会更新我的问题以包括它们。 我怀疑你只是无法做到这一点。将对象拖动到菜单不是正常的 UI 行为,我认为NSStatusItem 视图可以具有的交互可能存在系统级限制。如果视图响应的不是 mouseUp/Down,我会感到惊讶。 @Rob,这很有趣。那么,CloudApp 之类的应用程序如何让您将文件拖放到状态栏图标上? @Wevah,你能回答这个问题吗? 【参考方案1】:

通过反复试验,我偶然发现了解决方案。我在 awakeFromNib 消息中注册了可接受的拖动类型(如原始问题所示)。但是,我没有使用 IB 来设置此视图,因此从未调用过此方法。将注册码移至 initFromFrame 消息似乎可以解决问题。

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

【讨论】:

哎呀,我在编辑我的之前没有阅读这个自我答案。你应该接受你的正确的! (投票赞成。)【参考方案2】:

编辑:哦,您在-awakeFromNib 中注册了拖动类型,如果不是从笔尖加载视图,则不会调用该拖动类型。请尝试在 -initWithFrame: 中注册您的拖动类型!

旧答案:

IIRC 你不需要在状态项上设置菜单。我要做的是让我的自定义视图管理一个菜单,然后执行以下操作:

- (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

在我的自定义视图的实现中。这可确保菜单行为与默认行为相同。

【讨论】:

我将 NSMenu 设置为我的自定义视图,而不是 NSStatusItem。更重要的是,您如何处理拖动目的地? 哦,哎呀。我会更新我的答案。不过,目前睡眠不足……

以上是关于如何使用 NSStatusItem 作为拖动目的地?的主要内容,如果未能解决你的问题,请参考以下文章

使用React Native的MapView,我如何确定何时到达最终拖动目的地?

如何在拖动中更改拖放图像?

使用 NSStatusItem 拖放

在 NSStatusItem 中使用 NSProgressIndicator

如何使用movieclip作为AS3中另一个可拖动对象的边界?

jQuery:可拖动以下行:视觉“链接这两件事”指示器