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 加上右键菜单》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

Mobilizing Web Sites

Mobilizing Web Sites

Layon, Kristofer / 2011-12 / 266.00元

Everyone has been talking about the mobile web in recent years, and more of us are browsing the web on smartphones and similar devices than ever before. But most of what we are viewing has not yet bee......一起来看看 《Mobilizing Web Sites》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

html转js在线工具
html转js在线工具

html转js在线工具