7
votes

Sous-classement NSSLIDER: Besoin d'une solution de contournement pour des événements de souris manquants (Cocoa OSX)

J'essaie de sous-classe Nsslider pour créer un contrôle appelé numéro de jogging. Fondamentalement, ce dont j'ai besoin, c'est un curseur qui commence toujours au milieu et quand il est déplacé vers la gauche ou la droite, il enverra des notifications de temps en temps (déterminées par un attribut on peut définir) informer son conteneur de sa valeur actuelle, puis lorsque vous Laissez-vous aller du bouton, il retournera au milieu. J'espérais implémenter la fonctionnalité pour renvoyer le curseur au milieu et arrêter l'envoi de notifications dans l'événement MouseUp du curseur, mais il semble que, pour une raison quelconque, Apple désactive l'événement de MouseUp après un événement MouseDown sur le curseur et gère toute la fonctionnalité du curseur. à un niveau inférieur. Est-ce que là-bas, je peux récupérer l'événement de la machine? Si quelqu'un ne peut-il pas suggérer une solution de contournement raisonnable?


0 commentaires

8 Réponses :


7
votes

Il y a une astuce que j'utilise (mais n'a pas inventé) pour de telles situations. Tout d'abord, dans IB, désignez le curseur comme «continu», de sorte que vous obtenez des messages d'action car le curseur est déplacé. Ensuite, dans la méthode d'action, procédez comme suit:

[NSObject cancelPreviousPerformRequestsWithTarget: self
  selector: @selector(finishTrack) object: nil ];
[self performSelector: @selector(finishTrack) withObject: nil
  afterDelay: 0.0];


0 commentaires

8
votes

Chaque fois que vous remarquez que la mise en œuvre d'une superclasse de Mousedragged: ou MouseUp: n'est pas appelé, il est probablement parce que la mise en œuvre de la classe de Mousedown: entre une boucle de suivi. Ceci est certainement vrai de plusieurs sous-classes nscontrol , y compris nsslider .

Un meilleur moyen de détecter une souris est de sous-classer la cellule et de remplacer la méthode de suivi appropriée. Dans ce cas, vous voulez probablement - (vide) stoptracking: (nspoint) stoppoint At: (nsview *) ControlView Mouseisup: (BOOL) Drapeau , mais le StartTracking : et continuetracking: Les variantes peuvent s'avérer utiles pour ce que vous essayez de faire.


0 commentaires

3
votes

Il semble que l'idée de Kperryua fournisse la solution la plus propre, donc je vais marquer cela comme la réponse acceptée, mais j'ai fini par utiliser un peu de hack qui a travaillé pour ma situation spécifique, donc je pensais que je pouvais aussi partager cela.

L'application que je dois faire une plate-forme transversale afin que j'utilise Cocotron (un projet open source qui implémente une grande partie de l'API de cacao sous Windows) pour atteindre cet objectif et Cocotron ne prend pas en charge la méthode StopTracking: ... mentionné ci-dessus.

Heureusement, tout en jouant avec un petit programme de test, nous avons fait découvrir que si vous remplacez la méthode MOUSEDOWN du NSSlider et appelez le super de cette méthode, elle ne revient pas tant que le bouton de la souris n'est pas libéré. Peut simplement mettre le code doit être dans MouseUp à l'intérieur de la méthode MouseDown après l'appel à Super. C'est un peu un hachoir sale, mais il semble être la seule solution qui fonctionnera dans notre cas, nous allons donc devoir y aller.


0 commentaires

7
votes

Cela fonctionne pour moi (et est plus facile que le sous-classement NSSlider):

- (IBAction)sizeSliderValueChanged:(id)sender {
    NSEvent *event = [[NSApplication sharedApplication] currentEvent];
    BOOL startingDrag = event.type == NSLeftMouseDown;
    BOOL endingDrag = event.type == NSLeftMouseUp;
    BOOL dragging = event.type == NSLeftMouseDragged;

    NSAssert(startingDrag || endingDrag || dragging, @"unexpected event type caused slider change: %@", event);

    if (startingDrag) {
        NSLog(@"slider value started changing");
        // do whatever needs to be done when the slider starts changing
    }

    // do whatever needs to be done for "uncommitted" changes
    NSLog(@"slider value: %f", [sender doubleValue]);

    if (endingDrag) {
        NSLog(@"slider value stopped changing");
        // do whatever needs to be done when the slider stops changing
    }
}


1 commentaires

Cela ne fonctionne pas dans tous les cas (commencez à faire glisser et à passer au menu, vous n'enregistrerez jamais la mise en scène)



0
votes

Ceci ne peut être effectué que par sous-classement (méthodes telles que de @mprudhom ne fonctionnera pas 100% pour connaître la version)

Pour le début de la traînée, vous devez attraper devisesfirstreresponder code> (pour Ceci vous devez également fournir également PaniectPaneltObecomekey CODE>) P>

Pour la fin de glisser, vous devez sousclure MouseDown: code> (son appelé MouseDown, mais elle est appelée Lorsque le bouton est sorti) P>

Remarque: cette approche rendra votre curseur le premier répondeur, annulant tout autre premier répondeur actuel P>

Remarque: Approche de Mprudhom P>

@implementation CustomSlider

- (void)mouseDown:(NSEvent *)theEvent {
    [super mouseDown:theEvent];
    NSLog(@"OK");
}

- (BOOL)needsPanelToBecomeKey {
    [super needsPanelToBecomeKey];
    return YES;
}

- (BOOL)becomeFirstResponder {
    [super becomeFirstResponder];
    NSLog(@"Became first responder.");
    return YES;
}

@end


0 commentaires

3
votes

Juste au cas où quelqu'un se demande comment y parvenir à Swift 3 avec un état Nsslider qui est défini sur Continu: XXX


0 commentaires

0
votes

J'avais un besoin similaire, mais pour un curseur sur une barre Nstouch. J'ai utilisé une approche similaire «rapide» comme Marc Prud'hommes et Martin Majewski, juste des événements légèrement différents pour inspecter. Voici le code SWIFT qui vous permet de suivre à la fois la valeur continue et la valeur finale du curseur sur une barre tactile.

func sliderValueChanged(_ sender: NSSlider) {
    let doubleValue = sender.doubleValue

    Swift.print("Continuous value: \(doubleValue)")

    // find out if touch event has ended
    let event = NSApplication.shared().currentEvent
    if event?.type == NSEventType.directTouch {
        if let endedTouches = event?.touches(matching: .ended, in: nil) {
            if (endedTouches.count > 0) {
                Swift.print("The final value was: \(doubleValue)")
            }
        }
    }
}


0 commentaires

0
votes

Je pense qu'il est préférable de sous-classer le nsslider que d'ajouter du code supplémentaire dans la cible.

Cette méthode transfère les événements complets MouseUp et MouseDown (peut être utile pour obtenir des modificateurs clés) et est prêt à faire face à d'autres Type d'événements si nécessaire.

Ce curseur stocke la valeur initiale sur la souris vers le bas, nous pouvons donc obtenir les valeurs initiales et finales de la souris. Ceci est très utile pour des actions ondulables. xxx


1 commentaires

Cette solution n'atteigna pas les événements de MouseDown si iscontinuous est défini sur false sur le nslider . La solution pour ce cas consiste à appeler le Mousedownosvre dans MouseDown (avec:) avant d'appeler Super.mousedown (avec:) et appelez le < Code> Mousepcyclosure Dans Sendaction (_: à:) .