在Mac上的可可中是双击还是双击?

问题描述 投票:17回答:5

我有一个自定义的NSView(这是其中的一个,它们都生活在NSCollectionView中-我认为这无关紧要,但谁知道)。单击视图时,希望它更改其选择状态(并相应地重绘其自身);当我双击视图时,我希望它为双击的对象弹出一个较大的预览窗口。

我的第一个样子:

- (void)mouseUp: (NSEvent *)theEvent {
    if ([theEvent clickCount] == 1) [model setIsSelected: ![model isSelected]];
    else if ([theEvent clickCount] == 2) if ([model hasBeenDownloaded]) [mainWindowController showPreviewWindowForPicture:model];
}

大多数情况下效果很好。除外,当我双击视图时,选择状态更改窗口弹出。这不是我想要的。

似乎我有两个选择。我可以在响应双击时恢复选择状态(撤消错误的单击),也可以在响应单击之前添加某种NSTimer解决方案以延迟构建。换句话说,我可以确保在更改选择状态之前不会再次单击。

这似乎更优雅,所以这是我最初采用的方法。我从Google找到的唯一真正的指导是在一个未命名的网站上,该网站的名称中带有连字符。这种方法主要适用于一个大警告。

悬而未决的问题是“我的NSTimer应该等待多长时间?”。未命名的网站建议使用Carbon函数GetDblTime()。除了在64位应用程序中无法使用之外,我能找到的唯一文档还说它正在返回时钟信号。而且我不知道如何将这些转换为NSTimer的秒数。

那么,这里的“正确”答案是什么?摸索GetDblTime()?双击“撤消”选择吗?我想不出可可惯用的方法。

cocoa mouse nsview
5个回答
40
投票

根据我所见,延迟选择状态的更改是这样做的推荐方法。

实现起来非常简单:

- (void)mouseUp:(NSEvent *)theEvent
{
    if([theEvent clickCount] == 1) {
        [model performSelector:@selector(toggleSelectedState) afterDelay:[NSEvent doubleClickInterval]];
    }
    else if([theEvent clickCount] == 2)
    {
        if([model hasBeenDownloaded])
        {
                [NSRunLoop cancelPreviousPerformRequestsWithTarget: model]; 
                [mainWindowController showPreviewWindowForPicture:model];
        }
    }
}

(注意,在10.6中,双击间隔可以作为NSEvent上的类方法进行访问]


7
投票

如果您的单击和双击操作确实是分开且无关的,则需要在第一次单击时使用计时器,并等待以查看是否会发生双击。在任何平台上都是如此。

但是这会导致用户通常不喜欢的单击操作中尴尬的延迟。因此,您不会看到这种方法经常使用。

一种更好的方法是使单击和双击操作相互关联和互补。例如,如果您在Finder中单击一个图标,则该图标被选中(立即),如果您双击了一个图标,则该图标被选中并打开(立即)。这就是您应该针对的行为。

换句话说,单击的后果应与双击命令有关。这样,您就可以处理双击处理程序中的单击效果,而不必诉诸使用计时器。


2
投票

个人,我认为您需要问自己为什么要这种非标准行为。

您能否指向其他将双击中的第一次单击与单击不同的应用程序?我想不到...


2
投票

向自定义视图添加两个属性。

// CustomView.h
@interface CustomView : NSView {
  @protected
    id      m_target;
    SEL     m_doubleAction;
}
@property (readwrite) id target;
@property (readwrite) SEL doubleAction;

@end

在您的自定义视图中覆盖mouseUp:方法。

// CustomView.m
#pragma mark - MouseEvents

- (void)mouseUp:(NSEvent*)event {
    if (event.clickCount == 2) {
        if (m_target && m_doubleAction && [m_target respondsToSelector:m_doubleAction]) {
            [m_target performSelector:m_doubleAction];
        }
    }
}

target将控制器注册为doubleAction

// CustomController.m
- (id)init {
    self = [super init];
    if (self) {
        // Register self for double click events.
        [(CustomView*)m_myView setTarget:self];
        [(CustomView*)m_myView setDoubleAction:@selector(doubleClicked:)];
    }
    return self;
}

执行双击时应执行的操作。

// CustomController.m
- (void)doubleClicked:(id)sender {
  // DO SOMETHING.
}

1
投票

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

var singleClickPoint: CGPoint?

override func mouseDown(with event: NSEvent) {
singleClickPoint = event.location(in: self)
perform(#selector(GameScene.singleClickAction), with: nil, afterDelay: NSEvent.doubleClickInterval)
 if event.clickCount == 2 {
    RunLoop.cancelPreviousPerformRequests(withTarget: self)
    singleClickPoint = nil
//do whatever you want on double-click
}
}

@objc func singleClickAction(){
guard let singleClickPoint = singleClickPoint else {return}
//do whatever you want on single-click
}

我之所以不使用singleClickAction(在点:CGPoint)并用以下方法调用它的原因是:event.location(in:self)是我传递的任何点-包括CGPoint.zero-最终都以(0.0,9.223372036854776e + 18)。我将为此提起诉讼,但就目前而言,绕过执行是必经之路。 (其他对象似乎可以正常工作,但CGPoints不能。)

© www.soinside.com 2019 - 2024. All rights reserved.