Cocoa:给 NSTableView 加上右键菜单
栏目: Objective-C · 发布时间: 6年前
内容简介:Cocoa:给 NSTableView 加上右键菜单
可以说几乎每个应用都需要用到 TableView
,iOS 上如此 macOS 也不例外。因为桌面应用支持鼠标操作,所以当需要操作某一行的内容时,最常见的就是右键弹出菜单,选择需要的操作。开发一个 macOS 应用,这是最基本也是一定会遇到的需求。下图是 Things 3 任务列表的右键菜单。
但是在我的印象中,加个右键菜单并不容易,这个印象来自 12 年在公司做 doit.im 的 Mac 客户端,当时也是要做 Things 这样的操作菜单。那时候还是 Cocoa 开发萌新,Cocoa 的资料又是出了名的少,各种 Google 和 Stackoverflow,找到了合适的方案来做,一直到最近我在开发一个书签管理应用,我都还是沿用之前的办法,不是很难,但是有点绕。今天下午偶然看了一下 NSMenuDelegate 的 API,说出无数声卧槽后想出了最合适和最简单的方法来加这个菜单。分享给大家面的走弯路,或者也有可能就我走了这个弯路。
先回忆一下旧办法
旧方法核心是继承 NSTableView
,因为 NSView
有方法 - (nullable NSMenu *)menuForEvent:(NSEvent *)event;
NSTableView
是 NSView
的子类,所以我们继承后可以 override 这个方法。里面通过 delegate
方法来问 TableView 的 delegate(一般是 ViewController)要一个 Menu 回来,直接看我 Pinbox 的代码吧,比较古老还是 OC 写的。
- (NSMenu *)menuForEvent:(NSEvent*)event { NSPoint location = [self convertPoint:[event locationInWindow] fromView:nil]; NSInteger row = [self rowAtPoint:location]; if (row < 0 || ([event type] != NSRightMouseDown)) { return [super menuForEvent:event]; } NSIndexSet *rowIndex = [NSIndexSet indexSetWithIndex:row]; [self selectRowIndexes:rowIndex byExtendingSelection:NO]; if ([self.delegate respondsToSelector:@selector(tableView:menuForRows:)]) { return [self.delegate performSelector:@selector(tableView:menuForRows:) withObject:self withObject:rowIndex]; } return [super menuForEvent:event]; }
每一个 Cell 的 Menu 很可能是不一样的,比如书签加星操作,有时是 Star 有时是 Unstar,所以这里 Menu Item 是动态的。代码里通过点击事件的位置知道了点击在哪一行上,然后通过代码选中这一行,最后通过代理方法传过去选中的 index,View Controller 拿到 index 后结合 cell 对应的 Object 来返回对应的 Menu。
更合理的方式
就这么过了几年,我写过的全部应用都是这么实现的,直到今天下午。先看两个 API,事情就很直观了。
// NSResponder open var menu: NSMenu? .. // NSMenuDelegate optional public func menuNeedsUpdate(_ menu: NSMenu)
NSTableView
的继承关系是 NSTableView - NSControl - NSView - NSResponder,所以我们可以直接给 tableView 设置一个 menu 就好了。如果要解决上面说的动态 item 问题,只需要实现 menu 的 delegate,在 menu need update 的时候去更新。怎么知道这时候右键点击的是哪一行呢?直接通过 TableView 的 clickedRow
属性获取,这里容易混淆,TableView 还有一个 selectedRow
注意右键的时候并没有 Select
,UI 上的反馈也是不一样的。这里我也搞混过,代码很简单,就不写 Demo 了。
class ViewController: NSViewController { override func viewDidLoad() { super.viewDidLoad() let menu = NSMenu() menu.delegate = self tableView.menu = menu } } extension ViewController: NSMenuDelegate { func menuNeedsUpdate(_ menu: NSMenu) { menu.removeAllItems() // 在这里动态添加 menu item menu.addItem(NSMenuItem(title: "Delete", action: #selector(handleDeleteClickedRow), keyEquivalent: "")) } }
写这篇文章不仅是个记录,其实是想说固有的认识不一定是正确或者最好的,技术之路需要不断探索和实践。走点弯路也没什么不好,走对后能笑的更开心。
广告
我建了一个付费的小密圈,主要由我分享自己在自由职业、独立开发、远程工作的经验,iOS/macOS 应用产品、技术、运营心得,所见所闻所读的想法。感兴趣的朋友可以关注,圈子链接: http://t.xiaomiquan.com/AuFuBAy
也可以购买我的应用支持我 : ) 访问 seedlab.io
以上所述就是小编给大家介绍的《Cocoa:给 NSTableView 加上右键菜单》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Cocoa:给 NSTableView 加上右键菜单
- 给Elasticsearch加上监控
- 给树莓派小车控制系统加上装甲
- 如何用捷径给 GIF 加上进度条
- 是否有可能,为AI加上安全锁?
- Python 如何给屏幕打印信息加上颜色
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Mastering JavaServer Faces
Bill Dudney、Jonathan Lehr、Bill Willis、LeRoy Mattingly / Wiley / 2004-6-7 / USD 40.00
Harness the power of JavaServer Faces to create your own server-side user interfaces for the Web This innovative book arms you with the tools to utilize JavaServer Faces (JSF), a new standard that wi......一起来看看 《Mastering JavaServer Faces》 这本书的介绍吧!