当鼠标通过滚动或做动画从NStrackingArea退出时,为什么不调用mouseExited/mouseEntered?

我创建这样的代码:

鼠标进出:

-(void)mouseEntered:(NSEvent *)theEvent {
    NSLog(@"Mouse entered");
}

-(void)mouseExited:(NSEvent *)theEvent
{
    NSLog(@"Mouse exited");
}

追踪范围:

-(void)updateTrackingAreas
{ 
    if(trackingArea != nil) {
        [self removeTrackingArea:trackingArea];
        [trackingArea release];
    }

    int opts = (NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways);
    trackingArea = [ [NSTrackingArea alloc] initWithRect:[self bounds]
                                             options:opts
                                               owner:self
                                            userInfo:nil];
    [self addTrackingArea:trackingArea];
}

更多详情:

我已经在NSScrollView的视图中添加了NSViews作为子视图。每个NSView都有自己的跟踪区域,当我滚动我的scrollView并离开跟踪区域时,不调用"mouseExited",但不滚动一切正常。问题是,当我滚动"updateTrackingAreas"被调用,我认为这会产生问题。

* 同样的问题只是NSView而没有将其添加为子视图,所以这不是问题。

有帮助吗?

解决方案

当您在问题的标题中注意到,鼠标移动时只调用mouseEneed和mousexited。要了解为什么是这种情况,让我们首先查看第一次添加nstrackingareas的过程。

作为一个简单的例子,让我们创建一个通常绘制白色背景的视图,但如果用户悬停在视图上,则会绘制红色背景。此示例使用弧形。

@interface ExampleView

- (void) createTrackingArea

@property (nonatomic, retain) backgroundColor;
@property (nonatomic, retain) trackingArea;

@end

@implementation ExampleView

@synthesize backgroundColor;
@synthesize trackingArea

- (id) awakeFromNib
{
    [self setBackgroundColor: [NSColor whiteColor]];
    [self createTrackingArea];
}

- (void) createTrackingArea
{
    int opts = (NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways);
    trackingArea = [ [NSTrackingArea alloc] initWithRect:[self bounds]
                                             options:opts
                                               owner:self
                                            userInfo:nil];
    [self addTrackingArea:trackingArea];
}

- (void) drawRect: (NSRect) rect
{
    [[self backgroundColor] set];
    NSRectFill(rect);
}

- (void) mouseEntered: (NSEvent*) theEvent
{
    [self setBackgroundColor: [NSColor redColor]];
}

- (void) mouseEntered: (NSEvent*) theEvent
{
    [self setBackgroundColor: [NSColor whiteColor]];
}

@end
.

此代码有两个问题。首先,调用-aWakefromnib时,如果鼠标已在视图中,则不会调用-mouseentered。这意味着即使鼠标在视图上,背景仍将是白色的。这实际上在-addtrackingrect的idultInside参数的NSView文档中提到了:Owner:UserData:authutsIne:

如果是,则当光标叶叶时,将生成第一个事件,无论在添加跟踪矩形时是否在内部时都会产生。如果如果光标最初在ATECt中,则在光标叶子时,如果光标在光标最初在外部时,光标进入时,如果光标进入时,则不会生成第一个事件。 在这两种情况下,如果鼠标位于跟踪区域内,则不会在鼠标离开跟踪区域之前生成事件。

因此修复此项,当我们添加跟踪区域时,我们需要查明跟踪区域内的光标是否在。我们的-createtrackingarea方法变得

- (void) createTrackingArea
{
    int opts = (NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways);
    trackingArea = [ [NSTrackingArea alloc] initWithRect:[self bounds]
                                             options:opts
                                               owner:self
                                            userInfo:nil];
    [self addTrackingArea:trackingArea];

    NSPoint mouseLocation = [[self window] mouseLocationOutsideOfEventStream];
    mouseLocation = [self convertPoint: mouseLocation
                              fromView: nil];

    if (NSPointInRect(mouseLocation, [self bounds]))
    {
        [self mouseEntered: nil];
    }
    else
    {
        [self mouseExited: nil];
    }
}
.

第二个问题正在滚动。滚动或移动视图时,我们需要重新计算该视图中的nstrackingareAs。这是通过删除跟踪区域来完成的,然后将它们添加回来完成。当您注明的时,滚动视图时调用-UpdateTrackAxingAis。这是删除和重新添加该区域的地方。

- (void) updateTrackingAreas
{
    [self removeTrackingArea:trackingArea];
    [self createTrackingArea];
    [super updateTrackingAreas]; // Needed, according to the NSView documentation
}
.

并且应该照顾好你的问题。不可否认,需要找到鼠标位置,然后每次添加跟踪区域时将其转换为查看坐标是一个旧的东西,所以我建议在NSView上创建一个自动处理的类别。您将永远不会能够调用[自我mouseEnEntered:nil]或[自我鼠标尖叫:nil],因此您可能希望使该类别接受耦合块。如果鼠标位于nstrackingarea中,则为一个运行,如果不是,则为一个运行。

其他提示

@Michael提供了一个很好的答案,并解决了我的问题。但有一件事,

if (CGRectContainsPoint([self bounds], mouseLocation))
{
    [self mouseEntered: nil];
}
else
{
    [self mouseExited: nil];
}

我发现 CGRectContainsPoint 在我的盒子里工作,而不是 CGPointInRect,

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top