NSTableViewのヘッダーの右クリック/Ctrlキーを押しながらクリックを検出するための洗練された方法を探しています。
右クリックが発生したら、コンテキストメニューを表示したい。
- (NSMenu *)menuForEvent:(NSEvent *)
テーブルの右クリックのみを検出します。テーブルのヘッダーでは検出しません。
ご協力いただきありがとうございます。
NSTableViewのヘッダーの右クリック/Ctrlキーを押しながらクリックを検出するための洗練された方法を探しています。
右クリックが発生したら、コンテキストメニューを表示したい。
- (NSMenu *)menuForEvent:(NSEvent *)
テーブルの右クリックのみを検出します。テーブルのヘッダーでは検出しません。
ご協力いただきありがとうございます。
時々絵は1000の言葉を説明します。
任意のtableViewで、TableViewを選択し、メニューアウトレットをメニューに接続できます。
これで、メニューのセレクター(右側)をコードに接続できます。
[yourTableView clickedRow]
終わり。偉ぶって。
NSTableViewからNSTableHeaderViewを取得し、そのメニューを設定します。
[[myTableView headerView] setMenu:aMenu];
サブクラス化する必要がありますNSTableHeaderView
。サブクラス化せずにメニューを表示することはできますが、サブクラス化せずにクリックされたテーブル列を見つけることはできません(コンテキストメニューが役に立たなくなります)。
テーブルヘッダービューの独自のサブクラスを作成し、デリゲートを追加しました。Interface Builderで、を見つけ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
正確な答えをくれたJakobEggerに感謝します。私はこのアプローチの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;
}
}
このカスタムクラスを使用するには、Interface Builderで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
}
}