2009-08-21 15 views
18

Jak dodać zdolność do kliknięcia prawym przyciskiem myszy w wierszu w widoku NSOutlineView, aby można było powiedzieć, usunąć obiekt lub inną aktywność. (Podobnie jak po kliknięciu prawym przyciskiem myszy na folderze w aplikacji Apple Mail)Jak dodać kontekstowe menu senstive do NSOutlineView (np. Menu prawego przycisku myszy)

Myślę, że jestem w połowie drogi, mam podklasę NSOutlineView, która pozwala mi złapać prawy przycisk myszy i wyświetlić menu kontekstowe w oparciu o zaznaczonego wiersza zamiast wiersza klikniętego przez mysz.

@implementation NSContextOutlineView 

    - (NSMenu *)defaultMenu { 
     if([self selectedRow] < 0) return nil; 
     NSMenu *theMenu = [[[NSMenu alloc] initWithTitle:@"Model browser context menu"] autorelease]; 
     [theMenu insertItemWithTitle:@"Add package" action:@selector(addSite:) keyEquivalent:@"" atIndex:0]; 
     NSString* deleteItem = [NSString stringWithFormat: @"Remove '%i'", [self selectedRow]]; 
     [theMenu insertItemWithTitle: deleteItem action:@selector(removeSite:) keyEquivalent:@"" atIndex:1]; 
     return theMenu; 
    } 

    - (NSMenu *)menuForEvent:(NSEvent *)theEvent { 
     return [self defaultMenu]; 
    } 
@end 

Przepraszam, jeśli odpowiedź jest oczywista. Nie mogę znaleźć pomocy w tym trybie online ani w dokumentacji.

Dzięki nieważna na odpowiedź, to prowadzi mnie do korzystania z tego:

- (NSMenu *)menuForEvent:(NSEvent *)theEvent { 
    NSPoint pt = [self convertPoint:[theEvent locationInWindow] fromView:nil]; 
    id item = [self itemAtRow: [self rowAtPoint:pt]]; 
    return [self defaultMenuFor: item]; 
} 
+0

Nie uruchamiając go, wygląda na to, że powinien działać poprawnie. Czy nie jest? Jeśli nie, to jaki masz problem? –

+4

Nie należy również używać prefiksu NS na własnych klasach. Jeśli Apple doda klasę NSContextOutlineView do przyszłej wersji Cocoa, ich klasa i twoje będą się kolidować, a Twoja aplikacja prawdopodobnie nie będzie działać. –

+1

Myślę, że problem z opublikowanym kodem polega na tym, że użyje on selectedRow, a nie wiersza, w którym wykonano prawy/ctrl-kliknięcie. To może, ale nie musi być wybrany rząd. – VoidPointer

Odpowiedz

21

W swojej metodzie menuForEvent można dowiedzieć się, które rząd kliknięcie nastąpiło. można przekazać, że jako parametr do swojej defaultMenu metody - może nazwać defaultMenuForRow:

-(NSMenu*)menuForEvent:(NSEvent*)evt 
{ 
    NSPoint pt = [self convertPoint:[evt locationInWindow] fromView:nil]; 
    int row=[self rowAtPoint:pt]; 
    return [self defaultMenuForRow:row]; 
} 

Teraz można zbudować menu dla wiersza znalezionego w przypadku ...

-(NSMenu*)defaultMenuForRow:(int)row 
{ 
    if (row < 0) return nil; 

    NSMenu *theMenu = [[[NSMenu alloc] 
           initWithTitle:@"Model browser context menu"] 
           autorelease]; 
    [theMenu insertItemWithTitle:@"Add package" 
          action:@selector(addSite:) 
        keyEquivalent:@"" 
         atIndex:0]; 
    [theMenu insertItemWithTitle:[NSString stringWithFormat:@"Remove '%i'", row] 
          action:@selector(removeSite:) 
        keyEquivalent:@"" 
         atIndex:0]; 
    // you'll need to find a way of getting the information about the 
    // row that is to be removed to the removeSite method 
    // assuming that an ivar 'contextRow' is used for this 
    contextRow = row; 

    return theMenu;   
} 

Ponadto, jak już wspomniano w komentarzach, naprawdę nie powinieneś używać prefiksu NS na własnych zajęciach. Istnieje potencjał do starcia w przyszłości także będzie zmylić każdego, kto szuka w kodzie - w tym siebie :)

nadzieję, że to pomaga ...

+0

Dziękuję bardzo! Tak wiele z tych rzeczy jest tak prostych do zrobienia, ale tylko wtedy, gdy wiesz jak! – Jacob

+0

Smutne, że musimy uzyskać podklasę 'NSOutlineView', aby to osiągnąć. Ta funkcjonalność powinna już być zawarta w protokole delegata :-) –

-1

Jeśli wolisz, możesz dołączyć do menu jednostka lub komórka widok widok wiersz i budować ją z interfejsu konstruktora:

@implementation BSMotleyOutlineView 

-(NSMenu *)menuForEvent:(NSEvent *)event 
{ 
    NSPoint pt = [self convertPoint:[event locationInWindow] fromView:nil]; 
    NSInteger row = [self rowAtPoint:pt]; 
    if (row >= 0) { 
     NSTableRowView* rowView = [self rowViewAtRow:row makeIfNecessary:NO]; 
     if (rowView) { 
      NSInteger col = [self columnAtPoint:pt]; 
      if (col >= 0) { 
       NSTableCellView* cellView = [rowView viewAtColumn:col]; 
       NSMenu* cellMenu = cellView.menu; 
       if(cellMenu) { 
        return cellMenu; 
       } 
      } 
      NSMenu* rowMenu = rowView.menu; 
      if (rowMenu) { 
       return rowMenu; 
      } 
     } 
    } 
    return [super menuForEvent:event]; 
} 
@end 
8

Oto przykład Swift 2.0, który wykorzystuje podklasę i rozszerza domyślne NSOutlineDelegate tak można zdefiniować w menu delegata.

protocol MenuOutlineViewDelegate : NSOutlineViewDelegate { 
    func outlineView(outlineView: NSOutlineView, menuForItem item: AnyObject) -> NSMenu? 
} 

class MenuOutlineView: NSOutlineView { 

    override func menuForEvent(event: NSEvent) -> NSMenu? { 
     let point = self.convertPoint(event.locationInWindow, fromView: nil) 
     let row = self.rowAtPoint(point) 
     let item = self.itemAtRow(row) 

     if (item == nil) { 
      return nil 
     } 

     return (self.delegate() as! MenuOutlineViewDelegate).outlineView(self, menuForItem: item!) 
    } 

} 
Powiązane problemy