游标更新已调用,但游标未更新



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

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

有什么想法吗?

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

- (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;
    }
}

我遇到了同样的问题。

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

  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];
        }
    }
    

我遇到了同样的问题,但使用了一个简单的NSView子类,它是窗口contentView的子类,并且不驻留在NScrollView内。

NSTrackingAreacursorUpdate标志的文档听起来像您只需要处理鼠标进入跟踪区域即可。但是,我必须手动检查鼠标位置,因为当鼠标进入跟踪区域的矩形离开跟踪矩形时都会调用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)
    }
}

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

  1. Subclass the 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:。我花了几个小时才弄清楚这一点,希望有人可以使用它。

最新更新