LSUIElement在activateIgnoringOtherApps时表现不一致

8

具体来说,它在文本字段焦点上的表现是不一致的。

我有一个LSUIElement弹出状态菜单。在该菜单中,有一个包含文本字段的视图。该文本字段需要可选择 - 不一定是默认选择的,但可以选择任何一个。

当单击状态项时,它会触发

[NSApp activateIgnoringOtherApps:YES];

它能够正常工作,但成功率只有一半。另外一半时间,状态菜单似乎认为自己处于“后台”,即使我点击文本框也无法将焦点放在上面。(我知道状态项目的点击触发器正在运行,因为它上面有一个NSLog。)

这是苹果处理这些状态项目的方式有bug,还是我没有正确使用activateIgnoringOtherApps?

*实际上,它似乎只会在切换到另一个应用程序后第一次失败。之后它就可以正常工作了。

完整代码片段:

-(void)statusItemClicked:(id)sender {
    //show the popup menu associated with the status item.
    [statusItem popUpStatusItemMenu:statusMenu];

    //activate *after* showing the popup menu to obtain focus for the text field.
    [NSApp activateIgnoringOtherApps:YES];

}
2个回答

2

最终我想到了一个解决方法。

在您的点击处理程序中,不要弹出菜单,而是激活应用程序,然后安排一个没有延迟的NSTimer来弹出菜单:

-(void)pop:(NSTimer *)timer {
    [statusItem popUpStatusItemMenu:theMenu];
}

-(void)statusItemClicked:sender {
    [NSApp activateIgnoringOtherApps:YES];
    [NSTimer scheduledTimerWithTimeInterval:0.0 target:self selector:@selector(pop:) userInfo:nil repeats:NO];
}

pop: 在下一帧调用,因此延迟是不可察觉的,但足够长,使 activateIgnoringOtherApps: 在弹出菜单时执行任何防止其按预期工作的操作。


-1

从我的经验来看,你必须在弹出包含文本字段的菜单后调用activateIgnoringOtherApps:。因此,你需要按照以下顺序执行:

- (void)statusItemClicked:sender {
    [statusItem popUpStatusItemMenu:theMenu];
    [NSApp activateIgnoringOtherApps:YES]; // FYI, NSApp is shorthand for [NSApplication sharedApplication]
}

根据您所说的,似乎您的应用程序激活时间太晚了,因此第一次单击该项时它没有被激活,但在随后的单击中已经被激活了。

它肯定激活太晚了,但代码已经按照您的建议进行了结构化。它几乎看起来像是 activate 方法直到状态菜单被解除后才被调用(NSLog 测试似乎证实了这一点)。我不明白为什么会发生这种情况。 - iconmaster
activateIgnoringOtherApps:方法会在popUpStatusItemMenu:方法调用后立即被调用吗,还是说该方法要等到菜单关闭才返回?您可以尝试设置断点,通过调试器运行以查看发生的情况。 - Alex
是的,使用断点调试后,它肯定只会在菜单关闭后才被调用。我将我的代码添加到了第一篇帖子中,尽管它几乎与您的建议完全相同。 - iconmaster
如果你交换这两行代码,它还能正常工作吗?如果你在弹出菜单之前激活应用程序呢?显然,在菜单消失后才激活应用程序对你没有任何好处,我也想不到其他的钩子会在菜单出现时被调用。 - Alex
将它们反转仍然会使文本字段无法选择,而且在菜单被解除后会抛出一些错误。statusItemClicked 是从 awakeFromNib 中设置为 statusMenu 的选择器 -- 这可能是延迟的一部分吗? - iconmaster

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接