2010-10-03 9 views

Antwort

17

Holen Sie sich die NSTableHeaderView aus der NSTableView und stellen Sie ihr Menü ein.

[[myTableView headerView] setMenu:aMenu]; 
+0

funktioniert perfekt MenuTableHeaderView :) danke – tubtub

+2

Wenn Sie die Überschrift in Interface Builder auswählen, können Sie auch eine Verbindung zu einem Menü in Ihrem ziehen NIB/XIB. – Dov

+0

Wie würden Sie herausfinden, auf welche Spalte geklickt wurde? –

38

Manchmal erklärt ein Bild 1000 Wörter.

  1. Sie müssen die Tabellenansicht nicht unterklassifizieren.
  2. In jedem tableView können Sie den TableView auswählen und den Menüausgang mit einem Menü verbinden. enter image description here

  3. Jetzt können Sie den Selektor des Menüs (auf der rechten Seite) mit Ihrem Code verbinden.

  4. Um herauszufinden, welche Zeile in der Tabelle geklickt Verwendung

[yourTableView clickedRow]

Geschehen wurde. Wie ein Chef.

+1

nur 18 'Likes' in 2 Jahren. –

+0

ja nicht so viele. Aber ich habe ein Abzeichen für dieses hier bekommen, denke ich. Mehr Stimmen erhalten als die angenommene Antwort. –

+3

Ich verstehe nicht, warum das so viele Upvotes hat. Die Frage fragt eindeutig nach einem Kontextmenü für die Tabelle HEADER. Dies zeigt nur, wie man ein Kontextmenü in den Zeilen erhält. –

4

Sie müssen die Unterklasse NSTableHeaderView. Obwohl es möglich ist, ein Menü ohne Unterklassen zu erstellen, ist es nicht möglich herauszufinden, auf welche Tabellenspalte ohne Unterklasse geklickt wurde (wodurch das Kontextmenü unbrauchbar wird).

Ich habe meine eigene Untergruppe der Tabellenkopfansicht geschrieben und einen Delegaten hinzugefügt. Suchen Sie im Interface-Generator nach NSTableHeaderView, weisen Sie ihm Ihre benutzerdefinierte Unterklasse zu und verbinden Sie seine neue delegate Steckdose. Erstellen Sie außerdem ein Menü und weisen Sie es der menu Steckdose zu. Geben Sie die -validateMenu:forTableColumn: Methode in den Delegaten ein. Aktivieren/deaktivieren Sie die Menüoptionen entsprechend (stellen Sie sicher, dass das Menü in IB nicht automatisch validiert wird). Speichern Sie die angeklickte Spalte irgendwo in einer Instanzvariablen, damit Sie wissen, auf welche Spalte reagiert werden soll, wenn der Benutzer eine Aktion auswählt.

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

Dies ist die beste Antwort auf die Frage - wie es a) die Frage beantwortet und b) das Problem behandelt, wenn auf welche Spalte geklickt wurde. –

+0

Dies ist die vollständige Antwort +1 – insys

0

Dank Jakob Egger für seine präzise Antwort. Ich komme mit Swift Version dieses Ansatzes. Ich habe die Delegierten-Methodensignatur ein wenig geändert, um mehr Flexibilität bei mehr als einem TableView in ViewController zu geben.

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

Um diese benutzerdefinierte Klasse zu verwenden, NSTableHeaderView im Interface Builder finden und die Klasse ändern

Window where you have to enter custom class name

Beispiel dieses Ansatzes Verwendung in einem 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 
    } 
}