Utwórz podklasę NSPopUpButton
i nadpisaj zdarzenia mouseDown
/mouseUp
.
Mieć opóźnienie zdarzenia mouseDown
przez chwilę przed wywołaniem implementacji super
i tylko wtedy, gdy mysz jest nadal przytrzymana.
Czy zdarzenie mouseUp
ustawić selectedMenuItem
do nil
(a więc selectedMenuItemIndex
będzie -1
) przed wypalaniem przycisk na target
/action
.
Jedynym innym problemem jest obsługa szybkich kliknięć, w których licznik czasu na jedno kliknięcie może wystrzelić w momencie, gdy mysz nie działa, aby uzyskać kolejne kliknięcie. Zamiast używać NSTimer
i unieważniam go, wybrałem prosty licznik zdarzeń mouseDown
i wycofam, jeśli licznik się zmienił.
Oto kod używam w moim podklasy:
// MyClickAndHoldPopUpButton.h
@interface MyClickAndHoldPopUpButton : NSPopUpButton
@end
// MyClickAndHoldPopUpButton.m
@interface MyClickAndHoldPopUpButton()
@property BOOL mouseIsDown;
@property BOOL menuWasShownForLastMouseDown;
@property int mouseDownUniquenessCounter;
@end
@implementation MyClickAndHoldPopUpButton
// highlight the button immediately but wait a moment before calling the super method (which will show our popup menu) if the mouse comes up
// in that moment, don't tell the super method about the mousedown at all.
- (void)mouseDown:(NSEvent *)theEvent
{
self.mouseIsDown = YES;
self.menuWasShownForLastMouseDown = NO;
self.mouseDownUniquenessCounter++;
int mouseDownUniquenessCounterCopy = self.mouseDownUniquenessCounter;
[self highlight:YES];
float delayInSeconds = [NSEvent doubleClickInterval];
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
if (self.mouseIsDown && mouseDownUniquenessCounterCopy == self.mouseDownUniquenessCounter) {
self.menuWasShownForLastMouseDown = YES;
[super mouseDown:theEvent];
}
});
}
// if the mouse was down for a short enough period to avoid showing a popup menu, fire our target/action with no selected menu item, then
// remove the button highlight.
- (void)mouseUp:(NSEvent *)theEvent
{
self.mouseIsDown = NO;
if (!self.menuWasShownForLastMouseDown) {
[self selectItem:nil];
[self sendAction:self.action to:self.target];
}
[self highlight:NO];
}
@end
Szkoda, że nie można ustawić niestandardowej wysokości dla NSSegmentedControl - Potrzebuję tego menu dołączonego do dużego przycisku. – zrxq
Działa doskonale! Dzięki! – Alex
Przyjemna sztuczka, przy odrobinie zabawy w IB, możesz uzyskać naprawdę elegancką kontrolę. –