Изменение поведения выбора NSCollectionView

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

Итак, я хочу изменить поведение так, чтобы:

  • когда пользователь щелкает второй элемент, первый элемент остается выбранным (без необходимости удержания cmd)
  • Когда пользователь щелкает выбранный элемент, этот элемент отменяется.

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

-(void)setSelected:(BOOL)flag
{
    [super setSelected:flag];
    [(MyView*)[self view] setSelected: flag];
    [(MyView*)[self view] setNeedsDisplay:YES];
}

Вызов super setSelected необходим, чтобы убедиться, что представление коллекции работает правильно, но, похоже, именно оно отвечает за поведение по умолчанию.

Что мне делать вместо этого?


person Richard Garside    schedule 18.02.2015    source источник
comment
Сейчас немного поздно, но мне интересно: почему вы не поддерживаете выбор с помощью клавиши Shift для расширения выделения, как это работает почти везде (TableViews, Finder)?   -  person Thomas Tempelmann    schedule 15.11.2020


Ответы (1)


Вы можете попытаться перехватить все события нажатие левой кнопки мыши с помощью локального монитора событий. В этом блоке вы затем определите, произошел ли щелчок в представлении вашей коллекции. Если это так, создайте новое событие, которое имитирует перехваченное вами событие, но добавьте маску командной клавиши, если ее еще нет. Затем в конце блока верните ваше событие, а не перехваченное. Ваше представление коллекции будет вести себя так, как если бы пользователь нажал клавишу команды, даже если это не так!

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

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {


    [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskFromType(NSLeftMouseDown) 
            handler:^NSEvent *(NSEvent *originalEvent) {

        // Did this left down event occur on your collection view? 
        // If it did add in the command key

        NSEvent *newEvent =
            [NSEvent
                mouseEventWithType: NSLeftMouseDown
                location: originalEvent.locationInWindow
                modifierFlags: NSCommandKeyMask // I'm assuming it's not already present
                timestamp: originalEvent.timestamp
                windowNumber: originalEvent.windowNumber
                context: originalEvent.context
                eventNumber: originalEvent.eventNumber
                clickCount: originalEvent.clickCount
                pressure:0];

        return newEvent; // or originalEvent if it's nothing to do with your collection view
    }];
}

Изменить (по автору вопроса):

Это решение настолько сильно основано на исходном ответе, что этот ответ заслуживает похвалы (не стесняйтесь редактировать)

Вы также можете перехватить событие мыши, создав подкласс класса NSCollectionView и переопределив mousedown следующим образом:

@implementation MyCollectionView

-(void) mouseDown:(NSEvent *)originalEvent {

    NSEvent *mouseEventWithCmd =
        [NSEvent
            mouseEventWithType: originalEvent.type
            location: originalEvent.locationInWindow
            modifierFlags: NSCommandKeyMask
            timestamp: originalEvent.timestamp
            windowNumber: originalEvent.windowNumber
            context: originalEvent.context
            eventNumber: originalEvent.eventNumber
            clickCount: originalEvent.clickCount
            pressure: originalEvent.pressure];

    [super mouseDown: mouseEventWithCmd];
}

@end
person Paul Patterson    schedule 18.02.2015
comment
Это действительно работает, но, к сожалению, перехват на уровне событий мыши и добавление cmd ко всем щелчкам по NSCollectionView нарушает еще одну важную функцию моего приложения. В моем представлении коллекции есть и другие элементы управления, которые при добавлении cmd к их событию мыши изменяют свое поведение. Я могу только найти способ различать событие мыши на основе его местоположения в пикселях. Это хорошо для общего управления, но я не думаю, что это практично, поскольку вспомогательные элементы управления перемещаются. - person Richard Garside; 19.02.2015
comment
Это решение будет работать для других, у которых нет других элементов управления, требующих событий мыши в их NSCollectionView. - person Richard Garside; 19.02.2015
comment
Получил работу, используя измененную версию того, что вы предложили. Надеюсь, вы не возражаете, но я добавил это к вашему ответу, поскольку вы заслуживаете большей части похвалы. Не стесняйтесь редактировать ответ, чтобы сделать его более кратким и полезным для будущих людей. - person Richard Garside; 19.02.2015
comment
По какой-то причине я никогда не рассматривал возможность настройки событий из стандартного обработчика событий — я буду помнить об этой тактике. - person Paul Patterson; 19.02.2015