在NSTableView的标题上按Ctrl键单击/右键单击以显示上下文菜单

16

我正在寻找一种优雅的方法来检测 NSTableView 表头上的右键单击/ctrl+单击。

当发生右键单击时,我希望显示一个上下文菜单。

- (NSMenu *)menuForEvent:(NSEvent *)

在表格中仅检测右键单击事件,而不是在表头中检测。

感谢您的帮助。

4个回答

40
有时一张图片胜过千言万语。
  1. 不需要为您的表格视图创建子类。
  2. 在任何tableView上,您可以选择TableView并将菜单outlet连接到菜单。 enter image description here

  3. 现在,您可以将菜单的选择器(右侧)与您的代码连接起来。

  4. 要确定单击了表格中的哪一行,请使用

[yourTableView clickedRow]

完成。像老板一样。


1
仅有2年内的18个“赞”。 - Gabe Rainbow
是的,不是很多。但我认为我得到了这个徽章。因为我的回答获得了比被采纳的答案更多的投票。 - John Ballinger
3
我不明白为什么这个问题会得到这么多点赞。这个问题明确询问的是如何在表头获取上下文菜单,但这里只展示了如何在行上获取上下文菜单。 - Jakob Egger
@JakobEgger:这对IB中的“表头视图”也适用。我认为你需要[yourTableView clickedColumn] - Julian F. Weinert
4
当您单击表头时,“clickedColumn”为-1。您需要子类化“NSTableHeaderView”。这个答案是错误的,你的评论也是错的。 - Jakob Egger

19

从NSTableView获取NSTableHeaderView并设置其菜单。

[[myTableView headerView] setMenu:aMenu];

2
如果您在Interface Builder中选择标题,还可以将连接拖动到NIB/XIB中的菜单。 - Dov
1
你如何找出哪一列被右键单击了? - Radu Simionescu

11
您需要创建一个 NSTableHeaderView 的子类。虽然在不创建子类的情况下弹出菜单是可能的,但是找不到哪个表列被点击了,这就使得上下文菜单变得无用。
作者自己写了一个表头视图的子类,并添加了一个代理。在界面编辑器中,找到NSTableHeaderView,将其分配给您的自定义子类,并连接它的新delegate输出口。此外,创建一个菜单并将其分配给menu输出口。
然后在代理中实现-validateMenu:forTableColumn:方法。根据需要启用/禁用菜单项(确保菜单在IB中不会自动验证)。将所点击的列存储在实例变量中,以便在用户选择操作时知道要处理哪一列。 PGETableViewTableHeaderView.h
#import <Cocoa/Cocoa.h>
@protocol PGETableViewTableHeaderViewDelegate <NSObject>
-(void)validateMenu:(NSMenu*)menu forTableColumn:(NSTableColumn*)tableColumn;
@end
@interface PGETableViewTableHeaderView : NSTableHeaderView
@property(weak) IBOutlet id<PGETableViewTableHeaderViewDelegate> delegate;
@end

PGETableViewTableHeaderView.m

#import "PGETableViewTableHeaderView.h"
@implementation PGETableViewTableHeaderView
-(NSMenu *)menuForEvent:(NSEvent *)event {
    NSInteger columnForMenu = [self columnAtPoint:[self convertPoint:event.locationInWindow fromView:nil]];
    NSTableColumn *tableColumn = nil;
    if (columnForMenu >= 0) tableColumn = self.tableView.tableColumns[columnForMenu];
    NSMenu *menu = self.menu;
    [self.delegate validateMenu:menu forTableColumn:tableColumn];
    return menu;
}
@end

这是对问题的最佳答案,因为它 a) 回答了问题并且 b) 处理了如果点击了哪一列的问题。 - James Alvarez
这是完整的答案+1。 - insys

1
感谢Jakob Egger提供精准的答案。 我提供了这种方法的Swift版本。我稍微改变了委托方法的签名,以便在ViewController中有多个TableView的情况下更具灵活性。
protocol IMenuTableHeaderViewDelegate: class {
    func menuForTableHeader(inTableView tableView: NSTableView, forTableColumn tableColumn: NSTableColumn) -> NSMenu?
}

class MenuTableHeaderView: NSTableHeaderView {
    weak var menuDelegate: IMenuTableHeaderViewDelegate?

    override func menu(for event: NSEvent) -> NSMenu? {
        guard tableView != nil else {
            return nil
        }
        let columnForMenu =  column(at: convert(event.locationInWindow, from: nil))
        if columnForMenu >= 0, tableView!.tableColumns.count > columnForMenu {
            if let tableColumn = tableView?.tableColumns[columnForMenu] {
                return menuDelegate?.menuForTableHeader(inTableView: tableView!, forTableColumn: tableColumn)
            }
        }
        return self.menu;
    }
}

要使用这个自定义类,请在界面构建器中找到NSTableHeaderView并将其更改为MenuTableHeaderView

需要输入自定义类名的窗口

在ViewController中使用此方法的示例

class ExampleViewController: NSViewController, IMenuTableHeaderViewDelegate {
    @IBOutlet weak var tableView: NSTableView!
    @IBOutlet var tableHeaderMenu: NSMenu!

    var lastColumnForMenu: HeaderColumnForMenu?

    struct HeaderColumnForMenu {
        let tableView: NSTableView
        let tableColumn: NSTableColumn
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        if let tableHeaderWithMenu = tableView.headerView as? MenuTableHeaderView {
            tableHeaderWithMenu.menuDelegate = self
        }
    }

    func menuForTableHeader(inTableView tableView: NSTableView, forTableColumn tableColumn: NSTableColumn) -> NSMenu? {
        //Save column to wich we are going to show menu
        lastColumnForMenu = HeaderColumnForMenu(tableView: tableView, tableColumn: tableColumn)
        if needShowMenu {
            return tableHeaderMenu
        }
        return nil
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接