按住 Ctrl 键单击/右键单击 NSTableView 标题时显示上下文菜单

发布于 2024-09-25 21:15:09 字数 198 浏览 7 评论 0原文

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

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

- (NSMenu *)menuForEvent:(NSEvent *)

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

感谢您的帮助。

I'm searching for an elegant way to detect a right-click/ctrl-click on the header of an NSTableView.

When the right click occurs, I want to display an contextual menu.

- (NSMenu *)menuForEvent:(NSEvent *)

detects only right clicks in the table - not in the header of the table.

thanks for your help.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

毁我热情 2024-10-02 21:15:09

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

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

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

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

[您的TableView clickedRow]

完成。像一个老板一样。

Sometimes a picture explains a 1000 words.

  1. You do not need to subclass your table view.
  2. On any tableView you can select the TableView and connect the menu outlet to a menu.
    enter image description here

  3. Now you can wire the selector of the menu (on the right) to your code .

  4. To figure out what row in the table was clicked use

[yourTableView clickedRow]

Done. Like a boss.

萌无敌 2024-10-02 21:15:09

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

[[myTableView headerView] setMenu:aMenu];

Get the NSTableHeaderView from the NSTableView and set it's menu.

[[myTableView headerView] setMenu:aMenu];
作死小能手 2024-10-02 21:15:09

您需要子类化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

You need to subclass NSTableHeaderView. While it is possible to make a menu show up without subclassing, it is not possible to find out which table column was clicked without subclassing (making the context menu useless).

I wrote my own sublcass of the table header view, and added a delegate. In interface builder, find the NSTableHeaderView, assign it your custom subclass, and connect its new delegate outlet. Additionally, create a menu and assign it to the menu outlet.

Then implement the -validateMenu:forTableColumn: method in the delegate. Enable/disable menu items as apropriate (make sure that the menu doesn't autovalidate in IB). Store the clicked column somewhere in an instance variable, so you know which column to act on when the user selects an action.

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
那小子欠揍 2024-10-02 21:15:09

感谢雅各布·艾格的准确回答。
我想出了这种方法的 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
    }
}

Thanks Jakob Egger for his precise answer.
I come up with Swift version of this approach. I changed the delegate method signature a little bit, to give more flexibility in case of more then one TableView in 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;
    }
}

To use this custom class, find NSTableHeaderView in the interface builder and change the class to MenuTableHeaderView

Window where you have to enter custom class name

Example of this approach usage in a 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
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文