mousexitato non viene chiamato al momento del mouse lascia il trackingarea durante lo scorrimento

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

Domanda

Perché mousexited / Mouseenered non viene chiamato quando il mouse si esibisce da Nstrackingarea scorrendo o facendo animazione?

Creo codice come questo:

Mouse inserito ed uscito:

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

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

Area di monitoraggio:

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

Più dettagli:

Ho aggiunto NSWeys come sottoviews nella vista NSScrollView.Ogni NSView ha la propria area di tracciamento e quando lo strollò il mio scrollview e lascio la zona di tracciamento "Mouseexited" non viene chiamato ma senza scorrere tutto funziona bene.Il problema è che quando scorgo "updatetrackingareas" è chiamato e penso che questo faccia problemi.

* stesso problema con solo nsview senza aggiungerlo come sottoview in modo che non sia un problema.

È stato utile?

Soluzione

Come hai notato nel titolo della domanda, mousenered e mousexitato vengono chiamati solo quando il mouse si sposta. Per vedere perché questo è il caso, cerchiamo per la prima volta il processo di aggiungere Nstrackingareas per la prima volta.

Come esempio semplice, creiamo una vista che normalmente disegna uno sfondo bianco, ma se l'utente aleggia sopra la vista, disegna uno sfondo rosso. Questo esempio utilizza 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
.

Ci sono due problemi con questo codice. Innanzitutto, quando si chiama -wakefromnib è chiamato, se il mouse è già all'interno della vista, -Mouseenered non viene chiamato. Ciò significa che lo sfondo sarà ancora bianco, anche se il mouse è sopra la vista. Questo è effettivamente menzionato nella documentazione NSVIEW per il parametro Assumeinside di -Addtrackingrect: Proprietario: UserData: Assumeinside:

.

Se sì, il primo evento verrà generato quando il cursore lascia arezionare, indipendentemente dal momento che il cursore è all'interno dell'arezione quando viene aggiunto il rettangolo di tracciamento. Se no il primo evento verrà generato quando il cursore lascia arezionare se il cursore inizialmente è all'interno di ARECT, o quando il cursore entra in atto se il cursore è inizialmente esterno.

In entrambi i casi, se il mouse è all'interno dell'area di tracciamento, non verrà generato eventi fino a quando il mouse lascia l'area di tracciamento.

Per così per risolvere questo, quando aggiungiamo l'area di tracciamento, dobbiamo scoprire se il cursore è all'interno dell'area di tracciamento. Il nostro metodo -CreateTrackingarea diventa così

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

Il secondo problema è lo scorrimento. Durante lo scorrimento o lo spostamento di una vista, abbiamo bisogno di ricalcolare le nstrackingareas in quella vista. Questo viene fatto rimuovendo le aree di tracciamento e quindi aggiungendole. Come hai notato, -Updatetrackingareas viene chiamato quando si scorre la vista. Questo è il posto dove rimuovere e riaggiungere l'area.

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

E questo dovrebbe prendersi cura del tuo problema. Cercissimo, ho bisogno di trovare la posizione del mouse e quindi convertirlo per visualizzare le coordinate ogni volta che si aggiunge un'area di tracciamento è qualcosa che invecchia rapidamente, quindi consiglierei di creare una categoria su NSView che gestisce automaticamente questo. Non sarai sempre in grado di chiamare [auto mousenered: Nil] o [auto mousexitato: Nil], quindi potresti voler rendere la categoria accettare un paio di blocchi. Uno da eseguire se il mouse è nella nstrackingarea, e uno da eseguire se non lo è.

Altri suggerimenti

@Michael offers a great answer, and solved my problem. But there is one thing,

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

I found CGRectContainsPoint works in my box, not CGPointInRect,

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top