Tạo lớp con của NSPopUpButton
và ghi đè các sự kiện mouseDown
/mouseUp
.
Có sự chậm trễ sự kiện mouseDown
trong giây lát trước khi thực hiện triển khai super
và chỉ khi chuột vẫn bị giữ.
Có trường hợp mouseUp
thiết lập selectedMenuItem
để nil
(và do đó selectedMenuItemIndex
sẽ -1
) trước khi bắn của nút target
/action
.
Vấn đề duy nhất khác là xử lý các nhấp chuột nhanh chóng, trong đó thời gian cho một lần nhấp có thể kích hoạt tại thời điểm chuột rơi xuống cho một số nhấp chuột trong tương lai. Thay vì sử dụng NSTimer
và vô hiệu hóa nó, tôi đã chọn để có một truy cập đơn giản cho sự kiện mouseDown
và bảo lãnh nếu bộ đếm đã thay đổi.
Dưới đây là đoạn code tôi đang sử dụng trong phân lớp của tôi:
// 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
Nguồn
2012-12-30 00:18:46
Quá xấu, bạn không thể đặt chiều cao tùy chỉnh cho NSSegmentedControl - Tôi cần menu đó được đính kèm với một nút lớn. – zrxq
Đã hoạt động hoàn hảo! Cảm ơn! – Alex
Bí quyết tuyệt vời, với một chút chơi xung quanh trong IB bạn có thể có được một kiểm soát thực sự thanh lịch như thế này. –