- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
当 App Store 有更新时,它会在菜单项中显示一个内联样式元素,如下面的屏幕截图中的“1 new”:
我们可以看到这种菜单的另一个地方是 10.10 Yosemite 的分享菜单。当您安装任何添加新共享扩展的应用时,共享菜单中的“更多”项目将显示“N 新”,就像应用商店菜单一样。
'App Store...' 项目看起来是一个普通的 NSMenuItem
。是否有一种简单的方法来实现它,或者是否有任何 API 支持它而无需为菜单项设置自定义 View ?
最佳答案
“Cocoa”NSMenus 实际上完全构建在 Carbon 上,因此虽然 Cocoa API 没有公开太多功能,但您可以深入 Carbon-land 并获得更多功能。无论如何,这就是 Apple 所做的——Apple 菜单项是 IBCarbonMenuItem
的子类,如下所示:
/System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/Resources/English.lproj/StandardMenus.nib/objects.xib
不幸的是,与 32 位版本相比,64 位 Carbon API 似乎充满了错误和缺失的功能,这使得安装工作绘图处理程序变得更加困难。这是我想出的一个 hacky 版本:
#import <Carbon/Carbon.h>
OSStatus eventHandler(EventHandlerCallRef inHandlerRef, EventRef inEvent, void *inUserData) {
OSStatus ret = 0;
if (GetEventClass(inEvent) == kEventClassMenu) {
if (GetEventKind(inEvent) == kEventMenuDrawItem) {
// draw the standard menu stuff
ret = CallNextEventHandler(inHandlerRef, inEvent);
MenuTrackingData tracking_data;
GetMenuTrackingData(menuRef, &tracking_data);
MenuItemIndex item_index;
GetEventParameter(inEvent, kEventParamMenuItemIndex, typeMenuItemIndex, nil, sizeof(item_index), nil, &item_index);
if (tracking_data.itemSelected == item_index) {
HIRect item_rect;
GetEventParameter(inEvent, kEventParamMenuItemBounds, typeHIRect, nil, sizeof(item_rect), nil, &item_rect);
CGContextRef context;
GetEventParameter(inEvent, kEventParamCGContextRef, typeCGContextRef, nil, sizeof(context), nil, &context);
// first REMOVE a state from the graphics stack, instead of pushing onto the stack
// this is to remove the clipping and translation values that are completely useless without the context height value
extern void *CGContextCopyTopGState(CGContextRef);
void *state = CGContextCopyTopGState(context);
CGContextRestoreGState(context);
// draw our content on top of the menu item
CGContextSetRGBFillColor(context, 0.0, 0.0, 0.0, 0.5);
CGContextFillRect(context, CGRectMake(0, item_rect.origin.y - tracking_data.virtualMenuTop, item_rect.size.width, item_rect.size.height));
// and push a dummy graphics state onto the stack so the calling function can pop it again and be none the wiser
CGContextSaveGState(context);
extern void CGContextReplaceTopGState(CGContextRef, void *);
CGContextReplaceTopGState(context, state);
extern void CGGStateRelease(void *);
CGGStateRelease(state);
}
}
}
}
- (void)beginTracking:(NSNotification *)notification {
// install a Carbon event handler to custom draw in the menu
if (menuRef == nil) {
extern MenuRef _NSGetCarbonMenu(NSMenu *);
extern EventTargetRef GetMenuEventTarget(MenuRef);
menuRef = _NSGetCarbonMenu(menu);
if (menuRef == nil) return;
EventTypeSpec events[1];
events[0].eventClass = kEventClassMenu;
events[0].eventKind = kEventMenuDrawItem;
InstallEventHandler(GetMenuEventTarget(menuRef), NewEventHandlerUPP(&eventHandler), GetEventTypeCount(events), events, nil, nil);
}
if (menuRef != nil) {
// set the kMenuItemAttrCustomDraw attrib on the menu item
// this attribute is needed in order to receive the kMenuEventDrawItem event in the Carbon event handler
extern OSStatus ChangeMenuItemAttributes(MenuRef, MenuItemIndex, MenuItemAttributes, MenuItemAttributes);
ChangeMenuItemAttributes(menuRef, item_index, kMenuItemAttrCustomDraw, 0);
}
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
menu = [[NSMenu alloc] initWithTitle:@""];
// register for the BeginTracking notification so we can install our Carbon event handler as soon as the menu is constructed
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(beginTracking:) name:NSMenuDidBeginTrackingNotification object:menu];
}
首先,它注册了一个 BeginTracking 通知,因为 _NSGetCarbonMenu
仅在构建菜单并在绘制菜单之前调用 BeginTracking 后返回有效句柄。
然后它使用通知回调获取 Carbon MenuRef 并将标准 Carbon 事件处理程序附加到菜单。
通常我们可以简单地获取 kEventParamMenuContextHeight
事件参数并翻转 CGContextRef 并开始绘制,但该参数仅在 32 位模式下可用。 Apple 的文档建议在该值不可用时使用当前端口的高度,但这也仅在 32 位模式下可用。
所以既然给我们的图形状态没用,就把它从栈中弹出,用之前的图形状态。事实证明,这个新状态被转换为菜单的虚拟顶部,可以使用 GetMenuTrackingData.virtualMenuTop
检索。 kEventParamVirtualMenuTop
值在 64 位模式下也不正确,因此它必须使用 GetMenuTrackingData
。
这很古怪和荒谬,但比使用 setView 并重新实现整个菜单项行为要好。 OS X 上的菜单 API 有点一团糟。
关于objective-c - 如何在 NSMenuItem 中绘制内联样式标签(或按钮),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26548393/
我想执行绑定(bind)到 NSMenuItem 的操作,我正在为 osx 应用程序开发一个插件。因此我不知道菜单项的目标方法。 (菜单项的目标返回 nil) 如何以编程方式按下 NSMenuItem
我可以使用商品的标签属性来存储特殊的 key /ID 还是用于其他用途? 预期用途示例: - (void)awakeFromNib { [self.popup addItemWithTit
我正在开发一个基于 Cocoa 文档的应用程序。我的文件菜单中有一个名为“Export Things...”的菜单项。此菜单项连接到第一响应者,并调用MyDocument中的选择器。到目前为止一切顺利
当您在 Mac 上按下 NSMenuItem 键盘快捷键时,菜单本身会突出显示,以指示该菜单中的操作已被激活。 如果您不熟悉该效果,请立即尝试选择一些文本,然后按 CMD-C,观看“编辑”菜单。它将闪
我想在 NSMenuItem 自定义 View 中放置一个动画进度条。这在 Apple 的 MenuItemView 示例中得到了演示,但它没有动画(至少在 10.5 中没有,并且该示例显然来自 10
我正在创建一个状态栏应用程序,它需要在文本字段中输入 URL。文本字段是 NSMenuItem 的 subview 。我面临的问题是,文本字段的值无法更改,只能“间接突出显示”(它不是正常的蓝色突出显
我有对最外层菜单的引用,但我试图获取对嵌套在子菜单中的 NSMenuItem 的引用: NSMenuItem* file_menu = [menu itemWithTitle:@"File]; fil
我有一个 NSMenuItem,我想为其使用等效的 Command-Option-C 键。但是,当我在 IB 中设置等效键时,应用程序实际运行时它不会与菜单项关联。该条目没有可见的等效键,并且该命令不
我试图理解 Cocoa 中的一些东西,但我陷入了一件事。我正在关注Minimalistic Cocoa Programming ,其中有一个 NSMenuItem 负责终止应用程序。现在,我想创建另一
我有一个 NSMenuItem,我需要更新它以显示进度(就像时间机器对其备份所做的那样)。问题是,当我在该 NSMenuItem 上设置新的 title 时,title 没有改变。 当我关闭并重新打开
我见过这样的事情: 在菜单项右侧的 Menulet 中,我不知道该怎么做。 谁能详细说明一下吗?谢谢! 最佳答案 您只能在 Cocoa 中使用 NSMenuItem 的自定义 View 行为来执行此操
我正在我的应用程序上创建一个状态栏,菜单显示正常,但它似乎无法访问我为其设置的操作。 我通过 C 函数添加状态栏: void MyFunction(CefRefPtr browser) { M
我有一个 NSMenuItem,我需要更新它以显示进度(就像时间机器对其备份所做的那样)。问题是,当我在该 NSMenuItem 上设置新的 title 时,title 没有改变。 当我关闭并重新打开
我以编程方式创建一个 NSMenuItem,但它被禁用。如果我重写 validateMenuItem: 方法并为所有项目返回 YES,则菜单项工作正常。 当我告诉菜单 autoEnableItems
我对 NSMenu 进行了子类化,并通过 Interface Builder 连接了一堆 NSMenuItem。我已经通过调试器进行了测试,看看它们确实得到了初始化。 菜单设置为不自动启用项目。尽管如
我在 Swift 1.2 中有一个基于文档的应用程序。我想以编程方式生成对当前 NSDocument 有操作的 NSMenuItem,然后检查该选择。这是我到目前为止所拥有的: AppDelegate
假设我有一个 menuBar 应用,子菜单上有 3 个项目: let delaySubMenu = NSMenu() delaySubMenu.addItem(NSMenuItem(title: "5
我能够使用以下代码以编程方式创建菜单项。 primaryMenu.addItem(NSMenuItem(title: "MenuTitle", action: nil, keyEquivalent:
我目前正在向我的 NSMenu 添加一个 NSMenuItem,并且我能够成功检测并处理点击事件。但是,我想添加第二个选项并检测用户是否在按住 SHIFT 的同时单击了 menuItem let me
我的项目中有一个 NSMenuItem: var statusBar = NSStatusBar.systemStatusBar() var statusItem : NSStatusItem = N
我是一名优秀的程序员,十分优秀!