11
votes

Cliquez sur Nsview

J'ai un nsview contenant plusieurs sous-espions. L'une de ces sous-visions est transparente et superposée sur le dessus.

Je dois pouvoir cliquer sur cette affichage dans les sous-espages ci-dessous (de sorte que la vue ci-dessous obtient le statut de premier répondeur), mais tous les événements de la souris sont bloqués sur la vue de dessus (Alpha est 1 , parce que je dessine des choses debout - il ne devrait donc que cliquer sur des zones transparentes).

Je m'attendais à ce que cela fonctionne, car normalement, cela le fait. Qu'est-ce qui ne va pas?


1 commentaires

Les vues -isopaque sont no


5 Réponses :


0
votes

Mettez votre vue transparente dans une fenêtre d'enfant à part entière.


4 commentaires

Étant donné que la résolution des hits par des portions transparentes de Windows est intrinsèque au gestionnaire de fenêtres. Le travail que vous avez fait ci-dessus n'est pas nécessaire.


Oh, je viens de réaliser qu'il y a en fait une méthode -addchildwindow: qui synchronisation des fenêtres! Désolé, je pensais que je devrais faire la synchronisation manuellement alors.


J'ai essayé d'utiliser cette approche, mais il a plus d'inconvénients qui utilisent la solution de contournement -FindnextsiblingBeloweventLocation: , car la fenêtre n'est pas vraiment liée au Nsview et il est donc aussi dessiné quand La vue est invisible et ne fonctionne pas lorsque la vue est par exemple à l'intérieur d'une vue de défilement.


C'est une approche très lourde à un problème trivial



1
votes

J'ai contourné le problème avec cet extrait de code.

- (NSView *)findNextSiblingBelowEventLocation:(NSEvent *)theEvent {
  // Translate the event location to view coordinates
  NSPoint location = [theEvent locationInWindow];
  NSPoint convertedLocation = [self convertPointFromBase:location];

  // Find next view below self
  NSArray *siblings = [[self superview] subviews];
  NSView *viewBelow = nil;
  for (NSView *view in siblings) {
    if (view != self) {
      NSView *hitView = [view hitTest:convertedLocation];
      if (hitView != nil) {
        viewBelow = hitView;
      }
    }
  }
  return viewBelow;
}

- (void)mouseDown:(NSEvent *)theEvent {
  NSView *viewBelow = [self findNextSiblingBelowEventLocation:theEvent];
  if (viewBelow) {
    [[self window] makeFirstResponder:viewBelow];
  }
  [super mouseDown:theEvent];
}


0 commentaires

16
votes

Voici une autre approche. Il ne nécessite pas de créer un nouvel objet de fenêtre et est plus simple (et probablement un peu plus efficace) que la méthode ci-dessus.

- (NSView *)hitTest:(NSPoint)aPoint
{
    // pass-through events that don't hit one of the visible subviews
    for (NSView *subView in [self subviews]) {
        if (![subView isHidden] && [subView hitTest:aPoint])
            return subView;
    }

    return nil;
}


0 commentaires

0
votes

Voici une Swift 5 forte> Version de Réponse de Figelwump :

public override func hitTest(_ point: NSPoint) -> NSView? {
    // pass-through events that don't hit one of the visible subviews
    return subviews.first { subview in
        !subview.isHidden && nil != subview.hitTest(point)
    }
}


0 commentaires

0
votes

Voici un SWIFT 5 STRAND> Version de Réponse d'Erik Aigner :

public override func mouseDown(with event: NSEvent) {
    // Translate the event location to view coordinates
    let convertedLocation = self.convertFromBacking(event.locationInWindow)

    if let viewBelow = self
        .superview?
        .subviews // Find next view below self
        .lazy
        .compactMap({ $0.hitTest(convertedLocation) })
        .first
    {
        self.window?.makeFirstResponder(viewBelow)
    }

    super.mouseDown(with: event)
}


0 commentaires