【问题标题】:Show contextual menu on ctrl-click/right-click on header of NSTableView在 NSTableView 的标题上按 ctrl-click/右键单击显示上下文菜单
【发布时间】:2010-10-03 12:34:05
【问题描述】:

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

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

- (NSMenu *)menuForEvent:(NSEvent *)

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

感谢您的帮助。

【问题讨论】:

    标签: objective-c cocoa nstableview right-click


    【解决方案1】:

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

    1. 您不需要对表格视图进行子类化。
    2. 在任何 tableView 上,您都可以选择 TableView 并将菜单出口连接到菜单。

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

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

    [yourTableView clickedRow]

    完成。像老板一样。

    【讨论】:

    • 2 年内只有 18 个“赞”。
    • 是的,没那么多。但我确实得到了这个我认为的徽章。获得比接受的答案更多的选票。
    • 我不明白为什么会有这么多的赞成票。该问题清楚地询问表 HEADER 的上下文菜单。这只是展示了如何在行上获取上下文菜单。
    • @JakobEgger:这也适用于 IB 中的 Table Header View。我想你需要[yourTableView clickedColumn]
    • 当您单击标题时,@Julian clickedColumn 为 -1。你需要继承NSTableHeaderView。这个答案是错误的,你的评论是错误的。
    【解决方案2】:

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

    [[myTableView headerView] setMenu:aMenu];
    

    【讨论】:

    • 如果您在 Interface Builder 中选择标题,您还可以将连接拖到您的 NIB/XIB 中的菜单。
    • 你怎么知道哪一列被右键点击了?
    【解决方案3】:

    您需要继承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) 处理了单击哪一列时的问题。
    • 这是完整的答案+1
    【解决方案4】:

    感谢 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

    Window where you have to enter custom class name

    这种方法在 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
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2020-03-17
      • 1970-01-01
      • 1970-01-01
      • 2019-05-08
      • 2010-09-21
      • 1970-01-01
      • 2016-02-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多