4

我已经为此工作了几个小时,不知道出了什么问题。我想要一个按钮的自定义光标,它是 NSTextView 的子视图,我添加了一个跟踪区域并在鼠标输入按钮时发送 cursorUpdate 消息。

每次鼠标进入跟踪区域时,确实会调用 cursorUpdate 方法。但光标停留在 IBeamCursor。

有任何想法吗?

Apple Docs 参考:管理光标更新事件

- (void)cursorUpdate:(NSEvent *)event {
    [[NSCursor arrowCursor] set];
}

- (void)myAddTrackingArea {
    [self myRemoveTrackingArea];

    NSTrackingAreaOptions trackingOptions = NSTrackingCursorUpdate | NSTrackingMouseEnteredAndExited | NSTrackingActiveInKeyWindow;
    _trackingArea = [[NSTrackingArea alloc] initWithRect: [self bounds] options: trackingOptions owner: self userInfo: nil];
    [self addTrackingArea: _trackingArea];
}

- (void)myRemoveTrackingArea {
    if (_trackingArea)
    {
        [self removeTrackingArea: _trackingArea];
        _trackingArea = nil;
    }
}
4

3 回答 3

5

我遇到了同样的问题。

问题是,NSTextView每次收到mouseMoved:事件时都会更新其光标。该事件由 的自我更新触发NSTrackingArea,它始终跟踪 .内部的NSTextView可见部分。所以我能想到的可能有两种解决方案。NSTextViewNSScrollView

  1. 覆盖updateTrackingAreas删除 Cocoa 提供的跟踪区域,并确保您始终创建一个新的而不是排除按钮的跟踪区域。(我不会这样做!)

  2. 覆盖mouseMoved:并确保当光标在按钮上时它不会调用 super 。

    - (void)mouseMoved:(NSEvent *)theEvent {
        NSPoint windowPt = [theEvent locationInWindow];
        NSPoint superViewPt = [[self superview]
              convertPoint: windowPt  fromView: nil];
        if ([self hitTest: superViewPt] == self) {
            [super mouseMoved:theEvent];
        }
    }
    
于 2014-02-11T16:46:11.673 回答
1

我遇到了同样的问题,但是使用了一个简单NSView的子类,它是窗口的子类,contentView并且不位于NScrollView.

cursorUpdate标志的文档NSTrackingArea听起来好像您只需要处理鼠标进入跟踪区域矩形。但是,我必须手动检查鼠标位置,因为cursorUpdate(event:)当鼠标进入跟踪区域的矩形离开跟踪矩形时都会调用该方法。因此,如果cursorUpdate(event:)实现只设置光标而不检查它是否位于跟踪区域矩形内,则在进入和离开矩形时都会设置它。

状态的文档cursorUpdate(event:)

覆盖此方法以设置光标图像。如果光标矩形当前有效,则默认实现使用光标矩形。如果不是,它会调用 super 将消息发送到响应者链。

如果响应者实现了这个方法,但决定不处理特定事件,它应该调用这个方法的超类实现

override func cursorUpdate(with event: NSEvent) {
    // Convert mouse location to the view coordinates
    let mouseLocation = convert(event.locationInWindow, from: nil)

    // Check if the mouse location lies within the rect being tracked
    if trackingRect.contains(mouseLocation) {
        // Set the custom cursor
        NSCursor.openHand.set()
    } else {
        // Reset the cursor
        super.cursorUpdate(with: event)
    }
}
于 2020-09-14T21:58:29.943 回答
0

我刚刚通过谷歌搜索遇到了这个问题,所以我想我会发布我的解决方案。

  1. 子类化 NSTextView/NSTextField。
  2. 按照文档中的步骤创建一个 NSTrackingArea。应该如下所示。把这段代码放在子类的init方法中(同时添加updateTrackingAreas方法):

    NSTrackingArea *trackingArea = [[NSTrackingArea alloc] initWithRect:self.bounds options:(NSTrackingMouseMoved | NSTrackingActiveInKeyWindow) owner:self userInfo:nil];
    [self addTrackingArea:trackingArea];
    self.trackingArea = trackingArea;
    
  3. 现在您需要将mouseMoved:方法添加到子类:

    - (void)mouseMoved:(NSEvent *)theEvent {
        NSPoint point = [self convertPoint:theEvent.locationInWindow fromView:nil];
        if (NSPointInRect(point, self.popUpButton.frame)) {
            [[NSCursor arrowCursor] set];
        } else {
            [[NSCursor IBeamCursor] set];
        }
    }
    

注意:self.popUpButton按钮是 NSTextView/NSTextField 的子视图。

而已!它最终不会太难 - 只需要使用mouseMoved:而不是cursorUpdate:. 我花了几个小时才弄清楚这一点,希望有人可以使用它。

于 2014-06-24T00:13:11.363 回答