You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用NSTrackingArea时如何在拖拽事件中跟踪NSView光标位置?

在拖拽事件中跟踪NSView的光标位置

我开发的应用通过调用NSView::addTrackingArea,使用Apple的NSTrackingArea API处理mouseEntered、mouseMoved和mouseExited事件,整体运行良好,但我希望能在拖拽事件中跟踪屏幕上的光标位置。请问是否有办法订阅NSView的事件以确定拖拽事件中的光标位置?

当前代码片段

- (instancetype)initWithCallback:(LocationUpdateCallback)callback
                         andView:(NSView*)nsView {
  if ((self = [super init])) {
    _callback = std::move(callback);
    constexpr NSTrackingAreaOptions kTrackingOptions =
        NSTrackingMouseMoved | NSTrackingMouseEnteredAndExited |
        NSTrackingActiveInKeyWindow | NSTrackingInVisibleRect |
        NSTrackingEnabledDuringMouseDrag;
    NSTrackingArea* trackingArea =
        [[NSTrackingArea alloc] initWithRect:NSZeroRect
                                     options:kTrackingOptions
                                       owner:self
                                    userInfo:nil];
    _trackingArea.reset(trackingArea);
    [nsView addTrackingArea:trackingArea];
  }
  return self;
}

- (void)mouseMoved:(NSEvent*)theEvent {
...
}

- (void)mouseEntered:(NSEvent*)theEvent {
...
}

- (void)mouseExited:(NSEvent*)theEvent {
...
}

解决方案

你已经在kTrackingOptions里添加了NSTrackingEnabledDuringMouseDrag,这个选项本来就应该让mouseMoved事件在拖拽过程中继续触发。如果没收到预期的事件,可以试试以下几种针对性方法:

1. 直接复用mouseMoved事件

在mouseMoved:方法中,通过NSEvent的属性直接获取光标位置,拖拽状态下同样生效:

- (void)mouseMoved:(NSEvent*)theEvent {
    // 获取全局屏幕坐标
    NSPoint screenPoint = [theEvent screenLocation];
    // 或者获取窗口内坐标,再转换为视图本地坐标
    NSPoint windowPoint = [theEvent locationInWindow];
    NSPoint viewPoint = [self.view convertPoint:windowPoint fromView:nil];
    
    // 传递位置到回调
    if (_callback) {
        _callback(screenPoint);
    }
}

2. 实现拖拽阶段的专属方法

如果需要针对拖拽的不同阶段(进入、移动、离开)做精细化处理,可以让你的类遵循NSDraggingDestination协议,重写拖拽相关方法获取光标位置:

// 先让类遵循协议
@interface YourClass () <NSDraggingDestination>
@end

@implementation YourClass

// 拖拽进入视图时触发
- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender {
    NSEvent* dragEvent = [sender draggingLocation];
    NSPoint screenPoint = [dragEvent screenLocation];
    // 更新位置
    if (_callback) {
        _callback(screenPoint);
    }
    return NSDragOperationCopy; // 根据业务需求返回合适的拖拽操作类型
}

// 拖拽过程中光标移动时持续触发
- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender {
    NSEvent* dragEvent = [sender draggingLocation];
    NSPoint screenPoint = [dragEvent screenLocation];
    if (_callback) {
        _callback(screenPoint);
    }
    return NSDragOperationCopy;
}

// 拖拽离开视图时触发
- (void)draggingExited:(id<NSDraggingInfo>)sender {
    // 可在此做收尾处理,比如最后一次位置更新
}

@end

记得初始化时给视图注册支持的拖拽类型:

[nsView registerForDraggedTypes:@[NSFilenamesPboardType]]; // 根据你的拖拽场景调整类型

3. 全局事件监听(可选)

如果需要跟踪跨视图的全局拖拽光标位置,可以使用全局事件监视器:

// 在初始化方法中添加
[NSEvent addGlobalMonitorForEventsMatchingMask:NSMouseMovedMask | NSLeftMouseDraggedMask handler:^(NSEvent *event) {
    NSPoint screenPoint = [event screenLocation];
    if (_callback) {
        _callback(screenPoint);
    }
}];

注意:macOS 10.14+ 下全局监视器需要用户在系统隐私设置中开启“辅助功能”权限,且不会接收本应用内的事件,仅当需要跨应用跟踪时考虑使用。


内容的提问来源于stack exchange,提问作者jaypb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 20:13:13