Показать контекстное меню по нажатию ctrl / правому клику на заголовке NSTableView - PullRequest
15 голосов
/ 03 октября 2010

Я ищу элегантный способ обнаружения щелчка правой кнопкой мыши / нажатия Ctrl на заголовке NSTableView.

Когда происходит щелчок правой кнопкой мыши, я хочу отобразить контекстное меню.

- (NSMenu *)menuForEvent:(NSEvent *)

обнаруживает только правые щелчки в таблице, но не в заголовке таблицы.

спасибо за вашу помощь.

Ответы [ 4 ]

39 голосов
/ 20 апреля 2011

Иногда картинка объясняет 1000 слов.

  1. Вам не нужно разбивать на подклассы табличное представление.
  2. В любом TableView вы можете выбрать TableView и подключитьвыход меню в меню.enter image description here

  3. Теперь вы можете подключить селектор меню (справа) к своему коду.

  4. Чтобы выяснить, какая строка в таблицебыло нажато использование

[yourTableView clickedRow]

Готово.Как босс.

17 голосов
/ 03 октября 2010

Получите NSTableHeaderView из NSTableView и установите его меню.

[[myTableView headerView] setMenu:aMenu];
4 голосов
/ 27 июня 2014

Вам нужно создать подкласс 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
0 голосов
/ 04 ноября 2017

Спасибо Джейкобу Эггеру за точный ответ.Я придумаю версию Swift этого подхода.Я немного изменил сигнатуру метода делегата, чтобы обеспечить большую гибкость при наличии более одного TableView в ViewController.

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
    }
}
...