NSButton subclass that responds to right clicks

后端 未结 3 1218
余生分开走
余生分开走 2021-01-19 01:10

I have an NSButton subclass that I would like to make work with right mouse button clicks. Just overloading -rightMouseDown: won\'t cut it, as I would like the

相关标签:
3条回答
  • 2021-01-19 01:26

    I've turned a left mouse click-and-hold into a fake right mouse down on a path control. I'm not sure this will solve all your problems, but I found that the key difference when I did this was changing the timestamp:

    NSEvent *event = [NSEvent mouseEventWithType:NSLeftMouseDown 
                                        location:[theEvent locationInWindow] 
                                   modifierFlags:[theEvent modifierFlags] 
                                       timestamp:CFAbsoluteGetTimeCurrent()
                                    windowNumber:[theEvent windowNumber] 
                                         context:[theEvent context]
     // I was surprised to find eventNumber didn't seem to need to be faked 
                                     eventNumber:[theEvent eventNumber]   
                                      clickCount:[theEvent clickCount] 
                                        pressure:[theEvent pressure]];
    

    The other thing is that depending on your button type, its state may be the value that is making it appear pushed or not, so you might trying poking at that.

    UPDATE: I think I've figured out why rightMouseUp: never gets called. Per the -[NSControl mouseDown:] docs, the button starts tracking the mouse when it gets a mouseDown event, and it doesn't stop tracking until it gets mouseUp. While it's tracking, it can't do anything else. I just tried, for example, at the end of a custom mouseDown::

    [self performSelector:@selector(mouseUp:) withObject:myFakeMouseUpEvent afterDelay:1.0];
    

    but this gets put off until a normal mouseUp: gets triggered some other way. So, if you've clicked the right mouse button, you can't (with the mouse) send a leftMouseUp, thus the button is still tracking, and won't accept a rightMouseUp event. I still don't know what the solution is, but I figured that would be useful information.

    0 讨论(0)
  • 2021-01-19 01:29

    Not much to add to the answers above, but for those working in Swift, you may have trouble finding the constants for the event mask, buried deep in the documentation, and still more trouble finding a way to combine (OR) them in a way that the compiler accepts, so this may save you some time. Is there a neater way? This goes in your subclass -

    var rightAction: Selector = nil 
      // add a new property, by analogy with action property
    
    override func rightMouseDown(var theEvent: NSEvent!) {
      var newEvent: NSEvent!
    
      let maskUp = NSEventMask.RightMouseUpMask.rawValue
      let maskDragged = NSEventMask.RightMouseDraggedMask.rawValue
      let mask = Int( maskUp | maskDragged ) // cast from UInt
    
      do {
        newEvent = window!.nextEventMatchingMask(mask)
      }
      while newEvent.type == .RightMouseDragged
    

    My loop has become a do..while, as it always has to execute at least once, and I never liked writing while true, and I don't need to do anything with the dragging events.

    I had endless trouble getting meaningful results from convertRect(), perhaps because my controls were embedded in a table view. Thanks to Gustav Larsson above for my ending up with this for the last part -

    let whereUp = newEvent.locationInWindow
    let p = convertPoint(whereUp, fromView: nil)
    let mouseInBounds = NSMouseInRect(p, bounds, flipped) // bounds, not frame
    if mouseInBounds {
      sendAction(rightAction, to: target)
      // assuming rightAction and target have been allocated
      }
    }
    
    0 讨论(0)
  • 2021-01-19 01:38

    NSButton is entering a mouse tracking loop. To change this you will have to subclass NSButton and create your own custom tracking loop. Try this code:

    - (void) rightMouseDown:(NSEvent *)theEvent 
    {
        NSEvent *newEvent = theEvent;
        BOOL mouseInBounds = NO;
    
        while (YES) 
            {
                mouseInBounds = NSPointInRect([newEvent locationInWindow], [self convertRect:[self frame] fromView:nil]);
                [self highlight:mouseInBounds];
    
                newEvent = [[self window] nextEventMatchingMask:NSRightMouseDraggedMask | NSRightMouseUpMask];
    
                if (NSRightMouseUp == [newEvent type])
                {
                    break;
                }
            }
        if (mouseInBounds) [self performClick:nil];
    }
    

    This is how I do it; Hopefully it will work for you.

    0 讨论(0)
提交回复
热议问题