tags:

views:

72

answers:

0

I can get a mouseExited event sent to different NSView than the mouseEntered event

Scrolling with the scroll ball (or wheel) over a collection of subviews within a scrollview I sometimes do not get a mouseExited event sent to the view that the mouseEntered event was sent to.

I'm trying to show a button only when the mouse is over the view. When I scroll slowly I get matched mouseEntered and mouseExited events. Scrolling quickly the mouseExited is sent, but sent to a different view, so I don't hide the button as I do not know that the mouse exited

Notes: I've bound the hidden flag on a button inside the view to the controllers mouseOver property I set a tracking area to the view bounds inset by 2 pixels. on mouseEntered I set the controllers mouseOver to YES on mouseExited I set the controllers mouseOver to NO

Looking at logs after I run and see when child view is out of sync I can easily see that I get a mouseEntered and do get the mouseExited, but the mouseExited is sent to a different child (sub) view.

I have a full working sample to show this and sent to Apple, but thought I'd ask for any ideas, known issues or work-arounds or answers to my problem.

Very simple sample, just alloc and init 45 controllers and add to a NSView parent set as the documentView inside a scrolliew

Thanks

@implementation MouseOverSampleChildViewController
- (BOOL)mouseOver
{
 return m_bMouseOver;
}

- (void)setMouseOver:(BOOL)bMouseOver
{
 m_bMouseOver = bMouseOver;
}

- (int)child
{
 return m_nChild;
}

- (void)setChild:(int)nChild
{ 
 m_nChild = nChild;
}
@end



@implementation MouseOverSampleView
- (void)awakeFromNib
{
 NSString *strLabel = [[NSString alloc] initWithFormat:@"Child View [%d]", [controller child]];
 [textLabel setStringValue:strLabel];
 [strLabel release];
}

- (void)updateTrackingAreas
{
 [super updateTrackingAreas];

 NSRect rectMouseOver = NSInsetRect([self bounds], 0, 2);

 if (m_trackingMouseOverArea == nil || !NSEqualRects(rectMouseOver, m_rectMouseOver))
 {
  // remove old tracking area if we have one to remove
  if (m_trackingMouseOverArea)
  {
   [self removeTrackingArea:m_trackingMouseOverArea];
   [m_trackingMouseOverArea release];
   m_trackingMouseOverArea = nil;
  }

  // Allocate and add new tracking area
  m_trackingMouseOverArea = [[NSTrackingArea alloc] initWithRect:rectMouseOver options:NSTrackingMouseEnteredAndExited | NSTrackingActiveInActiveApp | NSTrackingAssumeInside owner:self userInfo:nil];
  [self addTrackingArea:m_trackingMouseOverArea];

  m_rectMouseOver = rectMouseOver;
 }
}

- (void)mouseEntered:(NSEvent *)theEvent
{
 NSLog(@"mouseEntered child[%d]",[controller child]);
 [controller setMouseOver:YES];
 [super mouseEntered:theEvent];
}

- (void)mouseExited:(NSEvent *)theEvent 
{
 NSLog(@"mouseExited  child[%d]",[controller child]);
 [controller setMouseOver:NO];
 [super mouseExited:theEvent];
}
@end

@implementation MouseOverSampleWindowView
- (void)awakeFromNib
{
 // Add a bunch of child views to the scroll view
 int nChildren = 45;
 float fChildHeight = 37;
 float fChildYOffset = 0;

 NSMutableArray *aChildren = [NSMutableArray arrayWithCapacity:nChildren];

 for (int nChild = 0; nChild < nChildren; nChild++)
 {
  MouseOverSampleChildViewController *controller = [[[MouseOverSampleChildViewController alloc] initWithChild:nChild] autorelease];

  NSRect childRect = NSMakeRect(0, fChildYOffset, 315, fChildHeight);
  [[controller view] setFrame:childRect];

  [aChildren addObject:[controller view]];

  fChildYOffset += fChildHeight;
 }

 NSRect documentRect = NSMakeRect(0, 0, 315, ([aChildren count] * fChildHeight));
 NSView *newDocumentView = [[NSView alloc] initWithFrame:documentRect];
 [newDocumentView setSubviews:aChildren];
 [scrollView setDocumentView:newDocumentView];
 [newDocumentView release];
 newDocumentView = nil;
}
@end