使用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
相关产品推荐
相关产品推荐

