2

通过在界面生成器中设置自定义类,我对 NSOutlineView 的单元格进行了子类化。

我已经实现了这个委托方法来配置单元:

- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item

另外,我已经在我的自定义单元类中实现了这个方法:

- (NSUInteger)hitTestForEvent:(NSEvent *)event inRect:(NSRect)cellFrame ofView:(NSView *)controlView 

每次单击单元格时都会调用两次。我想知道为什么不只是一次。事件类型始终为 MouseDown。

我不知道这是否重要,但即使单元格没有父母或孩子,它也会被调用两次。所以它不能是细胞层次结构。

如果单击单元格的特定区域时不能依靠 hitTestForEvent 触发操作,我应该使用哪种方法?

谢谢

4

1 回答 1

2

-hitTestForEvent:inRect:ofView用于触发动作是完全错误的方法。您应该使用-trackMouse:inRect:ofView:untilMouseUp:, -startTrackingAt:inView:, -continueTracking:at:inView:and -stopTracking:at:inView:mouseIsUp:

重要提示:如果您在 中实现自己的鼠标跟踪循环-trackMouse:inRect:ofView:untilMouseUp:您应该在某处记录这一事实,因为一般来说,它会排除其他三种方法的使用。AppKit 框架中的一些NSCell子类会这样做,但没有记录他们已经这样做了(结果你会思考几个小时为什么它-startTrackingAt:inView:永远不会被调用)。

您如何实现自己的跟踪循环?像这样:

- (BOOL)trackMouse:(NSEvent *)theEvent inRect:(NSRect)cellFrame
            ofView:(NSView *)controlView untilMouseUp:(BOOL)untilMouseUp
{
  NSPoint pos = [controlView convertPoint:[theEvent locationInWindow]
                                 fromView:nil];

  if ([theEvent type] == NSLeftMouseDown && NSPointInRect (pos, myClickRect)) {
    NSWindow *window = [controlView window];
    NSEvent *myEvent;
    NSDate *endDate = [NSDate distantFuture];

    while ((myEvent = [window nextEventMatchingMask:(NSLeftMouseDragged
                                                     |NSLeftMouseUp)
                                          untilDate:endDate
                                             inMode:NSEventTrackingRunLoopMode
                                            dequeue:YES])) {
      if ([myEvent type] != NSLeftMouseUp)
        continue;

      pos = [controlView convertPoint:[theEvent locationInWindow]
                             fromView:nil];

      if (NSPointInRect (pos, myClickRect)) {
        // React somehow
      }

      return YES;
    }
  }

  return [super trackMouse:theEvent inRect:cellFrame ofView:controlView
              untilMouseUp:untilMouseUp];
}

(The above code was just typed in here, so the usual caveats apply; it assumes the existence of an NSRect called myClickRect that defines the active area of your cell. You might need to calculate that from cellFrame at the head of the method.)

Obviously you can watch for and handle other events too, if they are relevant to you.

Perhaps I should also add that the three method approach, while conceptually cleaner, tends to be quite a bit slower, which generally leads me to prefer overriding -trackMouse:inRect:ofView:untilMouseUp: as shown above.

于 2012-05-29T17:11:05.407 回答