objective-c - Cocoa AppKit - 关闭模式窗口(即弹出窗口或上下文菜单)并按下当前悬停在上方的按钮

标签 objective-c cocoa menu appkit nsmenu

基本上我想创建系统菜单栏中提供的效果。用户按下其中一个菜单标题,当他在不同的标题上移动时,菜单会自动打开。

问题是,如果我打开按钮的弹出菜单,用户必须再次单击才能关闭它。整个运行循环被搁置,因为我相信弹出菜单是模态的。当用户移动到下一个按钮时,如何才能发送 [somePopUpMenu cancelTracking]?

这是我目前正在 NSWindow 子类中尝试的代码。重点是,一旦鼠标退出一个按钮,鼠标会自动点击(leftdown/leftup)下一个按钮,定时器失效,弹出菜单取消。

假设弹出菜单打开并且鼠标存在,则 leftdown/leftup 事件被触发(我知道这是有效的,因为我将它们记录在 NSLog 中的 mouseDown 和 mouseUp 中),计时器无效,但弹出菜单仍然存在显示,而假事件“单击”的另一个按钮没有显示任何内容。此外,整个事情进入了一个循环,并且由于某种原因发送了疯狂的 mouseDown/mouseUp 。

值得注意的是,弹出菜单是在另一个对象中创建的,尽管 hookToMenu 有对其的正确引用(我通过调试/单步执行确认)。

不知道我是否在破坏事件跟踪计时器或以错误的方式进行。我也通过窗口 Controller 尝试过,但得到了相同的结果。

对此的任何帮助将不胜感激。

-(void)stopTimer
{
    [timer invalidate];
    [hookToMenu cancelTracking]; //hookToMenu is NSMenu*
}

-startFireDateTimer
{
    NSDate *fireDate = [NSDate dateWithTimeIntervalSinceNow:0];
    timer = [[NSTimer alloc] initWithFireDate:nil interval:0 target:self selector:@selector(targetMethod)      userInfo:nil  repeats:YES];

    NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
    [runLoop addTimer:timer forMode:NSEventTrackingRunLoopMode];
    [timer release];
}

-(void)targetMethod
{
    NSEvent *newEvent;

    newEvent=[NSApp nextEventMatchingMask:NSMouseExitedMask untilDate:[NSDate distantFuture] inMode:NSEventTrackingRunLoopMode dequeue:NO];

    if ([newEvent type]==NSMouseExited)
    {
        NSPoint mouseLoc;

        mouseLoc=[newEvent locationInWindow];

        int type=NSLeftMouseDown;
        int type2=NSLeftMouseUp;
        int windowNumber=[self windowNumber];

        id fakeMouseUpEvent=[NSEvent mouseEventWithType:type
                                               location:mouseLoc
                                          modifierFlags:nil 
                                              timestamp:[NSDate timeIntervalSinceReferenceDate]
                                           windowNumber:windowNumber 
                                                context:nil
                                            eventNumber:nil 
                                             clickCount:1 
                                               pressure:1];

        id fakeMouseUpEvent2=[NSEvent mouseEventWithType:type2
                                                location:mouseLoc
                                           modifierFlags:nil 
                                               timestamp:[NSDate timeIntervalSinceReferenceDate]
                                            windowNumber:windowNumber 
                                                 context:nil
                                             eventNumber:nil 
                                              clickCount:1 
                                                pressure:1];

        [NSApp sendEvent:fakeMouseUpEvent];
        [NSApp sendEvent:fakeMouseUpEvent2];

        [self stopTimer];
    }
}

-(void)mouseDown:(NSEvent *)theEvent
{    
    [self startFireDateTimer];

    NSLog(@"WINDOW: mouse down in window!");

    [super mouseDown:theEvent];
}

-(void)mouseUp:(NSEvent *)theEvent
{    
    NSLog(@"WINDOW: mouse up in window!");

    [super mouseUp:theEvent];
}

最佳答案

How do I go about being able to send a [somePopUpMenu cancelTracking] when the user moves to the next button?

就这么做吧。 NSMenu responds to a cancelTracking message自 Mac OS X 10.5 起。

关于objective-c - Cocoa AppKit - 关闭模式窗口(即弹出窗口或上下文菜单)并按下当前悬停在上方的按钮,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2495044/

相关文章:

使用 Swift 读取文本文件的 Pythonic 方式

编辑主菜单后,Xcode 5 在保存时崩溃

c++ - Windows 对话框主菜单的自定义位置

html - CSS-如何在左侧创建子菜单

css superfish 菜单,没有正确排列

iphone - UITableView cellForRowAtIndexPath 导致滚动缓慢

ios - 为什么 UIImage 在 Slider 中裁剪后变得模糊?

ios - 当 UIAlertController 显示时,inputAccessoryView 被关闭

objective-c - 在 Objective-C 中解析嵌套的 JSON 对象

objective-c - 如何使用 Cocoa 在 PDF 中生成网格?