Cocoa:给 NSTableView 加上右键菜单

栏目: Objective-C · 发布时间: 6年前

内容简介:Cocoa:给 NSTableView 加上右键菜单

可以说几乎每个应用都需要用到 TableView ,iOS 上如此 macOS 也不例外。因为桌面应用支持鼠标操作,所以当需要操作某一行的内容时,最常见的就是右键弹出菜单,选择需要的操作。开发一个 macOS 应用,这是最基本也是一定会遇到的需求。下图是 Things 3 任务列表的右键菜单。 Cocoa:给 NSTableView 加上右键菜单

但是在我的印象中,加个右键菜单并不容易,这个印象来自 12 年在公司做  doit.im  的 Mac 客户端,当时也是要做 Things 这样的操作菜单。那时候还是 Cocoa 开发萌新,Cocoa 的资料又是出了名的少,各种 Google 和 Stackoverflow,找到了合适的方案来做,一直到最近我在开发一个书签管理应用,我都还是沿用之前的办法,不是很难,但是有点绕。今天下午偶然看了一下 NSMenuDelegate 的 API,说出无数声卧槽后想出了最合适和最简单的方法来加这个菜单。分享给大家面的走弯路,或者也有可能就我走了这个弯路。

先回忆一下旧办法

旧方法核心是继承 NSTableView ,因为 NSView 有方法 - (nullable NSMenu *)menuForEvent:(NSEvent *)event; NSTableViewNSView 的子类,所以我们继承后可以 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 加上右键菜单》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Mastering JavaServer Faces

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》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

SHA 加密
SHA 加密

SHA 加密工具