当滚动时鼠标离开trackingArea时,mouseExited不会被调用 [英] mouseExited isn't called when mouse leaves trackingArea while scrolling

查看:230
本文介绍了当滚动时鼠标离开trackingArea时,mouseExited不会被调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Why mouseExited/mouseEntered isn't called when mouse exits from NStrackingArea by scrolling or doing animation?

我创建的代码如下:

鼠标进入并退出:

-(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被调用,我认为这造成问题。

I have added NSViews as subviews in NSScrollView's view. Each NSView have his own tracking area and when I scroll my scrollView and leave tracking area "mouseExited" isn't called but without scrolling everything works fine. Problem is that when I scroll "updateTrackingAreas" is called and I think this makes problems.

*

推荐答案

正如你在问题的标题中指出的,mouseEntered和mouseExited仅在鼠标移动。为了看看为什么会这样,让我们​​先看看第一次添加NSTrackingAreas的过程。

As you noted in the title of the question, mouseEntered and mouseExited are only called when the mouse moves. To see why this is the case, let's first look at the process of adding NSTrackingAreas for the first time.

作为一个简单的例子,让我们创建一个视图,白色背景,但如果用户悬停在视图上,它绘制红色背景。这个例子使用ARC。

As a simple example, let's create a view that normally draws a white background, but if the user hovers over the view, it draws a red background. This example uses ARC.

@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。这意味着背景将仍然是白色的,即使鼠标在视图上。这在NSView文档中为-addTrackingRect的assumeInside参数提到:owner:userData:assumeInside:

There are two problems with this code. First, when -awakeFromNib is called, if the mouse is already inside the view, -mouseEntered is not called. This means that the background will still be white, even though the mouse is over the view. This is actually mentioned in the NSView documentation for the assumeInside parameter of -addTrackingRect:owner:userData:assumeInside:


如果是YES,将在光标离开aRect时生成,无论在添加跟踪矩形时光标是否位于aRect内。如果否,则当光标离开aRect时,如果光标最初位于aRect内,或者当光标最初位于aRect之外时,如果光标进入aRect,则会生成第一个事件。

If YES, the first event will be generated when the cursor leaves aRect, regardless if the cursor is inside aRect when the tracking rectangle is added. If NO the first event will be generated when the cursor leaves aRect if the cursor is initially inside aRect, or when the cursor enters aRect if the cursor is initially outside aRect.

在这两种情况下,如果鼠标在跟踪区域内,则在鼠标离开跟踪区域之前不会生成事件。

In both cases, if the mouse is inside the tracking area, no events will be generated until the mouse leaves the tracking area.

要解决这个问题,当我们添加跟踪区域时,我们需要找出光标是否在跟踪区域内。因此,-createTrackingArea方法变成了

So to fix this, when we add the tracking area, we need to find out if the cursor is within in the tracking area. Our -createTrackingArea method thus becomes

- (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。这是通过删除跟踪区域,然后将其添加回来。如您所知,-updateTrackingAreas在您滚动视图时调用。这是删除和重新添加区域的地方。

The second problem is scrolling. When scrolling or moving a view, we need to recalculate the NSTrackingAreas in that view. This is done by removing the tracking areas and then adding them back in. As you noted, -updateTrackingAreas is called when you scroll the view. This is the place to remove and re-add the area.

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

这应该照顾你的问题。不可否认,需要找到鼠标位置,然后将其转换为查看坐标,每次添加一个跟踪区域是快速老,所以我建议在NSView上创建一个类别,自动处理这个。你不会总是能够调用[self mouseEntered:nil]或[self mouseExited:nil],所以你可能想让类别接受几个块。一个运行,如果鼠标是在NSTrackingArea,一个运行,如果不是。

And that should take care of your problem. Admittedly, needing to find the mouse location and then convert it to view coordinates every time you add a tracking area is something that gets old quickly, so I would recommend creating a category on NSView that handles this automatically. You won't always be able to call [self mouseEntered: nil] or [self mouseExited: nil], so you might want to make the category accept a couple blocks. One to run if the mouse is in the NSTrackingArea, and one to run if it is not.

这篇关于当滚动时鼠标离开trackingArea时,mouseExited不会被调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆