Как использовать NSStatusItem в качестве места назначения перетаскивания? - PullRequest
10 голосов
/ 15 мая 2011

Я пытаюсь создать приложение, которое позволяет пользователям перетаскивать файлы из 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];   

Все равно ничего.Так где я ошибся?

Спасибо!

Ответы [ 2 ]

7 голосов
/ 15 мая 2011

Методом проб и ошибок я наткнулся на решение.Я регистрировал свои приемлемые типы перетаскивания в сообщении awakeFromNib (как видно из исходного вопроса).Однако я не использовал IB для настройки этого представления, поэтому этот метод никогда не вызывался.Перемещение регистрационного кода в сообщение initFromFrame, похоже, решило проблему.

- (id)initWithFrame:(NSRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        ...
        [self registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]];
    }
    return self;
}
6 голосов
/ 15 мая 2011

Edit: D'oh, вы регистрируете типы перетаскивания в -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
}

в реализации моего пользовательского вида.Это гарантирует, что поведение меню идентично поведению по умолчанию.

...