16

我正在寻找一种优雅的方式来检测 NSTableView 标题上的右键单击/ctrl-click。

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

- (NSMenu *)menuForEvent:(NSEvent *)

仅检测表格中的右键单击 - 不在表格的标题中。

谢谢你的帮助。

4

4 回答 4

40

有时一张图片解释了1000个单词。

  1. 您不需要子类化您的表格视图。
  2. 在任何 tableView 上,您都可以选择 TableView 并将菜单插座连接到菜单。 在此处输入图像描述

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

  4. 要找出点击了表格中的哪一行,请使用

[yourTableView clickedRow]

完毕。如同一位老板。

于 2011-04-19T22:36:47.460 回答
19

从 NSTableView 获取 NSTableHeaderView 并设置它的菜单。

[[myTableView headerView] setMenu:aMenu];
于 2010-10-03T14:51:41.820 回答
9

您需要子类化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
于 2014-06-27T07:57:07.217 回答
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
    }
}
于 2017-11-04T06:31:51.440 回答