Вытащите, чтобы удалить элемент - программирование
Подтвердить что ты не робот

Вытащите, чтобы удалить элемент

Вы знаете этот эффект, когда вы перетаскиваете элемент из док-станции и появляется курсор облачного перетаскивания, и когда вы отпускаете его, он исчезает с эффектом пуфа? Аналогично, в Xcode, когда вы перетаскиваете точку останова за пределы канального номера, происходит то же самое.

Я хотел бы реализовать тот же эффект в моем приложении, но не могу найти правильный путь.

У меня есть потомок NSImageView для реализации протоколов NSDraggingSource и NSDraggingDestination. У меня есть несколько примеров этого представления, которые позволяют перетаскивать их содержимое между остальными (операция копирования выполняется в этом сценарии, но это имеет смысл только для того, чтобы показать, что у меня есть drag'n drop, имплантированный и полностью работающий для стандартных задач).

Теперь, когда я перетаскиваю изображение из его вида в любом месте (кроме другого экземпляра представления), я хочу, чтобы операция удаления выполнялась при удалении. Однако операция перетаскивания полностью контролируется целевым представлением. Я мог бы заставить их реагировать так, как я хочу (хотя это будет очень много работы), но он полностью не работает, если я перетаскиваю приложение.

Если бы я мог получить операцию перетаскивания delete, я мог бы легко справиться с этим:

- (void)draggedImage: (NSImage *)image
             endedAt: (NSPoint)screenPoint
           operation: (NSDragOperation)operation
{
    if (operation == NSDragOperationDelete) {
        NSRect rect = [self.window convertRectToScreen: [self convertRect: self.frame fromView: nil]];
        NSShowAnimationEffect(NSAnimationEffectPoof, rect.origin, self.bounds.size, nil, nil, NULL);
    }
}

Я уже пытался установить курсор удаления следующим образом:

- (void)draggingSession: (NSDraggingSession *)session
           movedToPoint: (NSPoint)screenPoint
{
    if (!NSPointInRect(screenPoint, self.window.frame)) {
        [[NSCursor disappearingItemCursor] set];
    }
}

(для простоты это для всего ветра в данный момент). Это работает до тех пор, пока я не попаду на рабочий стол или окно поиска. В начале мерцает, вероятно, потому, что Finder одновременно устанавливает свой собственный указатель перетаскивания. Это абсолютно без эффекта, когда я попадал в док. Это также происходит, когда я определяю свой собственный тип данных картона.

Кроме того, любое другое представление с включенной возможностью переадресации в моем приложении по-прежнему будет принимать мои данные перетаскивания (например, NSTextView), которые я не хочу выполнять (я пишу NSURL для перетаскивания картона с пользовательской схемой).

Update:

Я сделал еще несколько шагов. Как уже указывал Питер, важно обрабатывать draggingSession:sourceOperationmaskForDraggingContext:, который выглядит так в моем коде:

- (NSDragOperation)       draggingSession: (NSDraggingSession *)session
    sourceOperationMaskForDraggingContext: (NSDraggingContext)context;
{
    switch(context) {
        case NSDraggingContextOutsideApplication:
            return NSDragOperationDelete;
            break;

        case NSDraggingContextWithinApplication:
        default:
            return NSDragOperationDelete | NSDragOperationMove;
            break;
    }
}

Это решает 2 проблемы: 1) вне приложения операция перетаскивания вообще не принимается, 2) она не позволяет всем стандартным представлениям принимать эту операцию (потому что NSOutlineView, NSTextView и т.д. не обрабатывают данные операции перетаскивания), Кроме того, я создал собственный тип данных в виде картона, но это не кажется необходимым. Тем не менее, яснее иметь собственный.

К сожалению, отказ от моего потомка NSImageView (как внутри, так и вне приложения) не дает мне NSDragOperationDelete в draggedImage:endedAt:operation: (что я указал выше), но NSDragOperationNone. Кроме того, курсор перетаскивания при перемещении мыши вне приложения является недопустимым, а не исчезающим элементом. Итак, если кто-то может решить эти две вещи, я бы принял это как ответ на мой вопрос.

4b9b3361

Ответ 1

Там может быть менее хакерский способ сделать это, но я могу подумать о одной возможности: после начала перетаскивания создайте прозрачное безграничное окно размером рабочего стола, чтобы стать фиктивным местом назначения. Вам может потребоваться позвонить -setIgnoresMouseEvents: с помощью NO, чтобы он мог получать капли, даже если он прозрачен. Вам также необходимо установить уровень окна над панелью меню (NSMainMenuWindowLevel + 1), чтобы убедиться, что перетаскивание в панель меню или док-станция все еще перехватывается вашим окном.

В качестве места назначения перетаскивания это окно должно будет проверить, находится ли какое-либо из ваших изображений под курсором. Вы можете использовать +[NSWindow windowNumberAtPoint:belowWindowWithWindowNumber:], чтобы найти окно под окном прозрачного оверлея, которое находится под курсором. Затем используйте -[NSApplication windowWithWindowNumber:], чтобы определить, является ли это одним из окон вашего приложения, и если да, вызовите -[NSView hitTest:] в своем представлении содержимого (конвертируя координаты курсора, если это необходимо), чтобы найти представление. Затем вы можете перенаправить методы NSDraggingDestination в это представление.

Ответ 2

Я предполагаю, что NSDragOperationDelete касается только перетаскивания/таргетинга на док-хост, и ничего больше.

NSDragOperationGeneric лучше подходит. Обязательно не смешивайте методы, если вы идете по маршруту 10.7, предпочитайте:

-(void)draggingSession:(NSDraggingSession *)session endedAtPoint:(NSPoint)screenPoint operation:(NSDragOperation)operation

Ответ 3

OS X 10.7 или лучше:

- (void) draggingEnded: (id<NSDraggingInfo>) aInfo {
    /*! Delete the current leaf if it is no longer represented in the subviews. */
    RETURN_IF ( , NSNotFound != [self.visibleLeafs indexOfObject: iSelectedControl.representedObject] );
    iIgnoreLeafsObservation = YES;
    [self.leafs removeObject: iSelectedControl.representedObject];
    iIgnoreLeafsObservation = NO;
}

Это предполагает, что вы уже визуально удалили объект. Вы также можете установить флаг во время draggingEntered: и draggingExited: указать, был ли сеанс перетаскивания последним внутри или вне себя.

В этой программе листья - это фактическая наблюдаемая коллекция, а visibleLeafs - это смоделированная коллекция представленного объекта каждого видимого элемента управления. Другие перегрузки NSDraggingDestination представляют то, что будет происходить визуально, прежде чем это произойдет.

Ответ 4

Вы можете использовать следующую команду, чтобы сделать poof в местоположении мыши:

NSShowAnimationEffect(NSAnimationEffectPoof, [NSEvent mouseLocation], NSZeroSize, NULL, NULL, NULL);

Дополнительную информацию см. в "Справочник по функциям набора приложений" .