基于NSTableViewCell上下文菜单(context menu based on NSTab

2019-08-17 07:08发布

我想下一个上下文菜单到NSTableView 。 这部分已经完成。 我会liek做的是展示基础上,对单击的单元格的内容不同的菜单项,并没有表现出对特定列的上下文菜单。

这是:

列0和1没有上下文菜单

所有其他细胞应该有这样的上下文菜单:

第一项:“删除” samerow.column1.value
第二项:“保存” samecolumn.headertext

希望这个问题是清楚的..

谢谢

-编辑-

右边的一个是上下文菜单中应该如何看起来像任何给定的细胞。

Answer 1:

那里有一个委托的! - 无需子

在IB如果拖动一个NSTableView到你的窗口/查看你会发现那里有一个menu的表的出口。

所以实现上下文菜单非常容易的方式是到该出口连接到短截线菜单并连接菜单它实现了一个对象的代表出口NSMenuDelegate协议方法- (void)menuNeedsUpdate:(NSMenu *)menu

通常情况下,菜单的代表是它提供了数据源/代表表相同的对象,但它也可能是该公司拥有的表太视图控制器。

看一看的文档以获取更多的信息

那里有聪明的东西捆你可以在协议做的,而是一个非常简单的实现可能像下面

#pragma mark tableview menu delegates

- (void)menuNeedsUpdate:(NSMenu *)menu
{
NSInteger clickedrow = [mytable clickedRow];
NSInteger clickedcol = [mytable clickedColumn];

if (clickedrow > -1 && clickedcol > -1) {



   //construct a menu based on column and row   
   NSMenu *newmenu = [self constructMenuForRow:clickedrow andColumn:clickedcol];

   //strip all the existing stuff       
   [menu removeAllItems];

   //then repopulate with the menu that you just created        
   NSArray *itemarr = [NSArray arrayWithArray:[newmenu itemArray]];
   for(NSMenuItem *item in itemarr)
   {
      [newmenu removeItem:[item retain]];
      [menu addItem:item];
      [item release];
   }        
}

}

再一个方法来构造菜单。

-(NSMenu *)constructMenuForRow:(int)row andColumn:(int)col
{

    NSMenu *contextMenu = [[[NSMenu alloc] initWithTitle:@"Context"] autorelease];

NSString *title1 = [NSString stringWithFormat:@"Delete %@",[self titleForRow:row]]; 

NSMenuItem *item1 = [[[NSMenuItem alloc] initWithTitle:title1 action:@selector(deleteObject:) keyEquivalent:@""] autorelease];
    [contextMenu addItem:item1];
    //
NSString *title2 = [NSString stringWithFormat:@"Save %@",[self titleForColumn:col]];    

NSMenuItem *item2 = [[[NSMenuItem alloc] initWithTitle:title1 action:@selector(saveObject:) keyEquivalent:@""] autorelease];
    [contextMenu addItem:item2];

return contextMenu;
}

你如何选择实施titleForRow:titleForColumn:是你。

需要注意的是NSMenuItem提供财产representedObject ,让您任意对象绑定到菜单项,从而将信息发送到您的方法(例如, deleteObject:

编辑

当心-实施- (void)menuNeedsUpdate:(NSMenu *)menu中的NSDocument子类将停止出现在出现在10.8标题栏中的自动保存/版本菜单。

它仍然在10.7所以大家工作的地方。 在任何情况下,菜单代表将需要比你的其他的东西NSDocument子类。



Answer 2:

编辑:更好的方式来做到这一点比下面的方法是使用代理,如图接受的答案。

你也可以继承你的UITableView并实现menuForEvent:方法:

-(NSMenu *)menuForEvent:(NSEvent *)event{
    if (event.type==NSRightMouseDown) {
        if (self.selectedColumn == 0 || self.selectedColumn ==1) {
            return nil;
        }else {
            //create NSMenu programmatically or get a IBOutlet from one created in IB
            NSMenu *menu=[[NSMenu alloc] initWithTitle:@"Custom"];

            //code to set the menu items

            //Instead of the following line get the value from your datasource array/dictionary
            //I used this as I don't know how you have implemented your datasource, but this will also work
            NSString *deleteValue = [[self preparedCellAtColumn:1 row:self.selectedRow] title]; 

            NSString *deleteString = [NSString stringWithFormat:@"Delete %@",deleteValue];
            NSMenuItem *deleteItem = [[NSMenuItem alloc] initWithTitle:deleteString action:@selector(deleteAction:) keyEquivalent:@""];
            [menu addItem:deleteItem];

            //save item
            //similarly 
            [menu addItem:saveItem];

            return menu;
        }
    }
    return nil;
}

这应该这样做。 我还没有尝试过的代码虽然。 但是,这应该给你一个想法。



Answer 3:

我也试过张贴沃伦顿的解决方案,它工作正常。 但在我的情况下,我不得不添加下面的菜单项:

[item1 setTarget:self];
[item2 setTarget:self];

设置没有目标明确导致上下文菜单保持禁用。

干杯!

亚历克斯

PS:我会发布这作为一个评论,但我没有足够的声誉做:(



Answer 4:

沃伦顿的答案是当场上。 对于那些在斯威夫特工作,下面的示例片段可能会救你脱离目的C.翻译在我的情况,我在NSOutlineView而不是一个NSTableView添加上下文菜单细胞的工作。 在这个例子中,菜单构造着眼于项目,并提供了根据项目类型和状态不同的选项。 委托(IB中设置)是管理的一个NSOutlineView视图控制器。

 func menuNeedsUpdate(menu: NSMenu) {
    // get the row/column from the NSTableView (or a subclasse, as here, an NSOutlineView)
    let row = outlineView.clickedRow
    let col = outlineView.clickedColumn
    if row < 0 || col < 0 {
        return
    }
    let newItems = constructMenuForRow(row, andColumn: col)
    menu.removeAllItems()
    for item in newItems {
        menu.addItem(item)
        // target this object for handling the actions
        item.target = self
    }
}

func constructMenuForRow(row: Int, andColumn column: Int) -> [NSMenuItem]
{
    let menuItemSeparator = NSMenuItem.separatorItem()
    let menuItemRefresh = NSMenuItem(title: "Refresh", action: #selector(refresh), keyEquivalent: "")
    let item = outlineView.itemAtRow(row)
    if let block = item as? Block {
        let menuItem1 = NSMenuItem(title: "Delete \(block.name)", action: #selector(deleteBlock), keyEquivalent: "")
        let menuItem2 = NSMenuItem(title: "New List", action: #selector(addList), keyEquivalent: "")
        return [menuItem1, menuItem2, menuItemSeparator, menuItemRefresh]
    }
    if let field = item as? Field {
        let menuItem1 = NSMenuItem(title: "Delete \(field.name)", action: #selector(deleteField), keyEquivalent: "")
        let menuItem2 = NSMenuItem(title: "New Field", action: #selector(addField), keyEquivalent: "")
        return [menuItem1, menuItem2, menuItemSeparator, menuItemRefresh]
    }
    return [NSMenuItem]()
}


Answer 5:

作为TheGoonie提到的,我也得到了同样的体验 - 上下文菜单项都保持关闭。 然而,对于项目被禁用的原因是“自动启用物品的财产。

让“自动启用项目”属性为关闭。 或者通过编程将其设置为NO。

[mTableViewMenu setAutoenablesItems:NO];


Answer 6:

下面是一个例子的图控制器内编程设定的NSOutlineView。 这是你需要得到上下文菜单启动和运行的所有管道。 无需子类。

我以前的子类NSOutlineView覆盖菜单(事件:NSEvent),而是来到了一个简单的建立与帮助格雷厄姆的答案在这里和沃伦的回答以上。

class OutlineViewController: NSViewController 
{
    // ...
    var outlineView: NSOutlineView!
    var contextMenu: NSMenu! 

    override func viewDidLoad()
    {
        // ...
        outlineView = NSOutlineView()
        contextMenu = NSMenu()
        contextMenu.delegate = self
        outlineView.menu = contextMenu
    }
}

extension OutlineViewController: NSMenuDelegate
{
    func menuNeedsUpdate(_ menu: NSMenu) {

        // clickedRow catches the right-click here 
        print("menuNeedsUpdate called. Clicked Row: \(outlineView.clickedRow)")

        // ... Flesh out the context menu here
    }
}


Answer 7:

这是一个自定义/动态最简单的方法NSMenu我发现,还保留了系统的外观 (蓝色选框)。 子类NSTableView ,并设置你的菜单中menu(for:)

最重要的部分是设置在表视图菜单但从其返回菜单super调用

override func menu(for event: NSEvent) -> NSMenu? {
    let point = convert(event.locationInWindow, from: nil)
    let clickedRow = self.row(at: point)
    var menuRows = selectedRowIndexes

    // The blue selection box should always reflect the
    // returned row indexes.
    if menuRows.isEmpty || !menuRows.contains(clickedRow) {
        menuRows = [clickedRow]
    }

    // Build your custom menu based on the menuRows indexes
    self.menu = <#myMenu#>

    return super.menu(for: event)
}


文章来源: context menu based on NSTableViewCell