マウスがスクロールしながらマウスが追跡領域を残したときにMouseExtedは呼び出されません

StackOverflow https://stackoverflow.com/questions/8979639

質問

マウスがスクロールするかアニメーションをスクロールすることによって、マウスがNstrackingAreaから出るときにMountexted / 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];
}
.

詳細:

NSVIEWSをNSSCROLLVIEWのビューのサブビューとして追加しました。各NSViewには自分の追跡領域があり、スクロールビューをスクロールして追跡領域を残すと「MouseExited」が呼ばれていませんが、すべてがうまく機能しません。問題は、「UpdateTrackingAreas」をスクロールすると、これが問題になると思います。

* サブビューとして追加せずにNSViewだけの問題は問題ありません。

役に立ちましたか?

解決

質問のタイトルに記載されているように、マウスが移動したときにのみマウスエンジンとMOUSEEXETが呼び出されます。これがなぜなのかを確認するには、最初にNStrackingAreasを初めて追加するプロセスを見てみましょう。

簡単な例として、通常は白い背景を描画するビューを作成しましょうが、ユーザーがビューを覆っている場合は赤い背景を描画します。この例では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
.

このコードには2つの問題があります。まず、-awakeFromNibが呼び出された場合、マウスがすでにビューの内側にある場合、-mouseEnteredは呼び出されません。これは、マウスがビューの上にあるにもかかわらず、背景がまだ白くなることを意味します。これは、実際には、-addtrackingRectのアシッピングインサイドパラメータのNSViewドキュメントに記載されています。所有者:UserData:assumeInside:

YESの場合、追跡矩形が追加されたときにカーソルが内側にあるかどうかにかかわらず、カーソルがアークすると、最初のイベントが発生します。カーソルが最初にARECTの内側にある場合、またはカーソルが最初にアレインの外側にある場合にカーソルが発生した場合、またはカーソルが発生した場合、またはカーソルが発生したときに最初のイベントが発生する場合、またはカーソルが発生したとき。

両方の場合では、マウスがトラッキングエリア内にある場合、マウスがトラッキングエリアを離れるまでイベントは発生しません。

それを修正するために、追跡領域を追加すると、カーソルがトラッキングエリア内にあるかどうかを調べる必要があります。私たちの-CreathetrackingArea法はになります

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

2番目の問題はスクロールしています。ビューをスクロールまたは移動するときは、そのビューでNstrackingAreasを再計算する必要があります。これはトラッキングエリアを削除してから追加することによって行われます。あなたが指摘したように、あなたがビューをスクロールすると-updateTrackingAreasが呼び出されます。これが領域を削除して再追加する場所です。

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

そしてそれはあなたの問題の世話をするべきです。確かに、マウスの場所を見つけてから、追跡領域を追加するたびに座標を表示する必要があります。あなたは常に[Self MouseEntered:NIL]または[Self MouseExtated:NIL]を呼び出すことができますので、カテゴリにカップルブロックを受け入れることをお勧めします。マウスがNstrackingAreaにある場合は1つずつ実行すると、1つがそうでない場合は1つが実行されます。

他のヒント

@michaelは素晴らしい答えを提供し、私の問題を解決しました。しかし、一つのことがあります、

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

CGRectContainsPointが見つかりました、CGPointInRect

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top