更改 NSCollectionView 的选择行为
Changing the selection behaviour of NSCollectionView
在我的 Mac 应用程序中,我有一个启用了多个 select 的 NSCollectionView。在我的应用程序中,能够 select 多个项目是常态,并且必须在单击 select 多个项目的同时按 cmd 让一些用户感到沮丧,而且大多数人没有意识到他们可以做到这一点 (我收到很多功能请求要求多 select).
所以,我想改变行为以便:
- 当用户单击第二个项目时,第一个项目保持 selected(无需按住 cmd)
- 当用户点击 selected 项目时,该项目被删除selected
我试过在我自己的 NSCollectionViewItem 子类上覆盖 setSelected,如下所示:
-(void)setSelected:(BOOL)flag
{
[super setSelected:flag];
[(MyView*)[self view] setSelected: flag];
[(MyView*)[self view] setNeedsDisplay:YES];
}
需要调用 super setSelected 以确保集合视图正常运行,但它似乎也是造成默认行为的原因。
我应该怎么做?
您可以尝试使用本地事件监视器拦截所有 鼠标左键按下 事件。在此块中,您将计算出点击是否发生在您的集合视图上。如果是这样,请创建一个新事件来模仿您拦截的事件,但如果它不存在,请添加命令键掩码。然后,在块的末尾 return 你的 事件而不是你拦截的事件。您的集合视图将表现得好像用户按下了命令键,即使他们没有!
我在一个非常简单的演示应用程序中快速完成了这个,它看起来是一个很有前途的方法 - 虽然我希望你必须协商一些 gotchas方式。
- (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
}];
}
编辑(由问题作者):
此解决方案在很大程度上基于原始答案,因此该答案值得信赖(随意编辑)
您还可以通过子classing NSCollectionView class 并像这样覆盖 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
在我的 Mac 应用程序中,我有一个启用了多个 select 的 NSCollectionView。在我的应用程序中,能够 select 多个项目是常态,并且必须在单击 select 多个项目的同时按 cmd 让一些用户感到沮丧,而且大多数人没有意识到他们可以做到这一点 (我收到很多功能请求要求多 select).
所以,我想改变行为以便:
- 当用户单击第二个项目时,第一个项目保持 selected(无需按住 cmd)
- 当用户点击 selected 项目时,该项目被删除selected
我试过在我自己的 NSCollectionViewItem 子类上覆盖 setSelected,如下所示:
-(void)setSelected:(BOOL)flag
{
[super setSelected:flag];
[(MyView*)[self view] setSelected: flag];
[(MyView*)[self view] setNeedsDisplay:YES];
}
需要调用 super setSelected 以确保集合视图正常运行,但它似乎也是造成默认行为的原因。
我应该怎么做?
您可以尝试使用本地事件监视器拦截所有 鼠标左键按下 事件。在此块中,您将计算出点击是否发生在您的集合视图上。如果是这样,请创建一个新事件来模仿您拦截的事件,但如果它不存在,请添加命令键掩码。然后,在块的末尾 return 你的 事件而不是你拦截的事件。您的集合视图将表现得好像用户按下了命令键,即使他们没有!
我在一个非常简单的演示应用程序中快速完成了这个,它看起来是一个很有前途的方法 - 虽然我希望你必须协商一些 gotchas方式。
- (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
}];
}
编辑(由问题作者):
此解决方案在很大程度上基于原始答案,因此该答案值得信赖(随意编辑)
您还可以通过子classing NSCollectionView class 并像这样覆盖 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