2013-03-03 43 views
9

我想將上下文菜單放到NSTableView上。這部分完成了。我想要做的是根據右擊單元格的內容顯示不同的菜單條目,並且不顯示特定列的上下文菜單。基於NSTableViewCell的上下文菜單

是這樣的:

列0和1沒有上下文菜單

所有其他細胞應該有這樣的上下文菜單:

第一項: 「刪除」 samerow.column1.value
第二項: 「保存」 samecolumn.headertext

希望這個問題是清楚..

感謝

CNC中

的一個,右邊是上下文菜單中應該如何看起來像任何給定的細胞。

enter image description here

回答

33

這是一個代表! - 不需要子類

在IB中,如果您將NSTableView拖到窗口/視圖上,您​​會注意到該表爲一個menu插座。

因此,爲了實現上下文菜單非常容易的方式是到該出口處的菜單的委託出口連接到短截線的菜單,並連接到其實現NSMenuDelegate協議方法- (void)menuNeedsUpdate:(NSMenu *)menu

interface builder screen shot

對象通常,菜單的委託是提供數據源/委託給表的同一個對象,但它也可能是擁有該表的視圖控制器。

Have a look at the docs查找有關此

更多信息即使世界的巧妙的東西捆你可以在協議做,但一個非常簡單的實現可能會像下面

#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子類以外的東西。

+0

謝謝!今天會嘗試!這種方法是自動調用還是必須在右擊時調用它?謝謝 – sharkyenergy 2013-03-07 06:54:42

+0

很長時間以來,我寫它,但它應該只是自動發生,由於菜單插座連接 – 2013-03-07 07:27:42

+0

謝謝!現在嘗試,但我無法理解這一點:'//讓你的數據對象提供菜單 NSMenu * newmenu = [thing menuThatMyThingProvides]; ' – sharkyenergy 2013-03-07 18:07:59

3

編輯:更好的方式來做到這一點比下面的方法,如在接受的答案是使用委託。

你可以繼承你的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; 
} 

應該這樣做。儘管我還沒有嘗試過這些代碼。但是這應該給你一個想法。

+0

謝謝你今天測試一下,讓你知道! – sharkyenergy 2013-03-06 08:48:07

+0

不是一個好主意,因爲它通常與MVC模式衝突。如果您需要表格視圖中的值,則不應該在視圖中實現菜單創建,而應該在控制器中實現。 – 2016-01-05 14:46:47

1

我也試過沃倫伯頓發佈的解決方案,它工作正常。 但在我的情況下,我只好下面添加到菜單項:

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

設置沒有目標明確導致上下文菜單保持禁用。

乾杯!

亞歷

PS:我會發布這作爲一個評論,但我沒有足夠的聲譽做:(

0

正如TheGoonie提到的,我也得到了同樣的體驗 - 上下文菜單項,分別爲仍然禁止,但是對於項目被禁用的原因是「自動啓用物品的財產。

使「自動啓用項」財產了。或者通過編程將其設置爲NO。

[mTableViewMenu setAutoenablesItems:NO]; 
1

Warren Burton的答案是現貨。對於那些在Swift中工作的人來說,以下示例片段可能爲您節省從Objective C轉換的工作。在我的情況下,我將上下文菜單添加到NSOutlineView中的單元格而不是NSTableView。在這個例子中,菜單構造函數查看該項目並根據項目類型和狀態提供不同的選項。代理(在IB中設置)是一個管理NSOutlineView的ViewController。

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]() 
} 
0

下面是一個例子的圖控制器內編程設定的NSOutlineView。這就是您需要啓動和運行上下文菜單的所有工具。不需要子類。

我以前子類NSOutlineView覆蓋菜單(事件:NSEvent),而是來到了一個簡單的設置了Graham's答案here及以上Warren's答案的幫助。

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