Cocoa:给 NSTableView 加上右键菜单

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

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

查看所有标签

猜你喜欢:

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

C程序设计(第四版)

C程序设计(第四版)

谭浩强 / 清华大学出版社 / 2010-6-1 / 33.00元

由谭浩强教授著、清华大学出版社出版的《C程序设计》是一本公认的学习C语言程序设计的经典教材。根据C语言的发展和计算机教学的需要,作者在《C程序设计(第三版)》的基础上进行了修订。 《C程序设计(第4版)》按照C语言的新标准C99进行介绍,所有程序都符合C99的规定,使编写程序更加规范;对C语言和程序设计的基本概念和要点讲解透彻,全面而深入;按照作者提出的“提出问题―解决问题―归纳分析”三部曲......一起来看看 《C程序设计(第四版)》 这本书的介绍吧!

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

在线压缩/解压 HTML 代码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具