zrs*_*slv 12
使用NSSegmentedControl.
通过发送setMenu:forSegment:到控件添加菜单(将任何内容连接到menuIB中的插座将不起作用).有一个动作连接到控件(这很重要).
应该完全按照你的描述工作.
创建一个子类NSPopUpButton并覆盖mouseDown/ mouseUpevents.
mouseDown在调用super实现之前将事件延迟片刻,并且仅在鼠标仍处于按下状态时才会延迟.
有mouseUp事件设置selectedMenuItem到nil(并因此selectedMenuItemIndex将-1发射按钮的前)target/ action.
唯一的另一个问题是处理快速点击,其中一次点击的计时器可能会在鼠标停止以供将来点击时触发.NSTimer我没有使用和使其无效,而是选择了一个简单的mouseDown事件计数器,并在计数器发生变化时进行纾困.
这是我在我的子类中使用的代码:
// 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
Run Code Online (Sandbox Code Playgroud)
如果仍然有人需要它,这是我基于简单NSButton而不是分段控件的解决方案。
子类化NSButton并实现一个自定义mouseDown,该自定义在当前运行循环内启动计时器。在中mouseUp,检查计时器是否未启动。在这种情况下,请取消它并执行默认操作。
这是一种非常简单的方法,可与您可以在IB中使用的任何NSButton一起使用。
代码如下:
- (void)mouseDown:(NSEvent *)theEvent {
[self setHighlighted:YES];
[self setNeedsDisplay:YES];
_menuShown = NO;
_timer = [NSTimer scheduledTimerWithTimeInterval:0.3 target:self selector:@selector(showContextMenu:) userInfo:nil repeats:NO];
[[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSDefaultRunLoopMode];
}
- (void)mouseUp:(NSEvent *)theEvent {
[self setHighlighted:NO];
[self setNeedsDisplay:YES];
[_timer invalidate];
_timer = nil;
if(!_menuShown) {
[NSApp sendAction:[self action] to:[self target] from:self];
}
_menuShown = NO;
}
- (void)showContextMenu:(NSTimer*)timer {
if(!_timer) {
return;
}
_timer = nil;
_menuShown = YES;
NSMenu *theMenu = [[NSMenu alloc] initWithTitle:@"Contextual Menu"];
[[theMenu addItemWithTitle:@"Beep" action:@selector(beep:) keyEquivalent:@""] setTarget:self];
[[theMenu addItemWithTitle:@"Honk" action:@selector(honk:) keyEquivalent:@""] setTarget:self];
[theMenu popUpMenuPositioningItem:nil atLocation:NSMakePoint(self.bounds.size.width-8, self.bounds.size.height-1) inView:self];
NSWindow* window = [self window];
NSEvent* fakeMouseUp = [NSEvent mouseEventWithType:NSLeftMouseUp
location:self.bounds.origin
modifierFlags:0
timestamp:[NSDate timeIntervalSinceReferenceDate]
windowNumber:[window windowNumber]
context:[NSGraphicsContext currentContext]
eventNumber:0
clickCount:1
pressure:0.0];
[window postEvent:fakeMouseUp atStart:YES];
[self setState:NSOnState];
}
Run Code Online (Sandbox Code Playgroud)
我已经在GitHub上发布了一个工作示例。
| 归档时间: |
|
| 查看次数: |
2114 次 |
| 最近记录: |