2009-08-21 3 views
18

Làm cách nào để bạn thêm khả năng nhấp chuột phải vào một hàng trong NSOutlineView để bạn có thể nói xóa đối tượng hoặc một số hoạt động khác. (ví dụ như khi bạn nhấp chuột phải vào một thư mục trong ứng dụng Apple Mail)Làm cách nào để thêm menu senstive ngữ cảnh vào NSOutlineView (tức là menu chuột phải)

Tôi nghĩ rằng tôi ở một nửa, tôi có một lớp con của NSOutlineView cho phép tôi nắm bắt nhấp chuột phải và hiển thị menu ngữ cảnh dựa trên hàng đã chọn thay vì hàng mà chuột đang nhấp vào.

@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 

Xin lỗi nếu câu trả lời là hiển nhiên, tôi không thể tìm thấy bất kỳ trợ giúp nào về trực tuyến hoặc trong tài liệu này.

Nhờ Void cho câu trả lời, nó đưa tôi đến với sử dụng này:

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

Nếu không chạy, có vẻ như nó sẽ hoạt động tốt. Phải không? Nếu không, bạn có vấn đề gì với nó? –

+4

Ngoài ra, không sử dụng tiền tố NS trên các lớp học của riêng bạn. Nếu Apple thêm một lớp NSContextOutlineView vào một phiên bản tương lai của Cocoa, lớp của họ và của bạn sẽ va chạm, và ứng dụng của bạn có thể sẽ không chạy. –

+1

Tôi nghĩ rằng vấn đề với mã được đăng là nó sẽ sử dụng selectedRow và không phải là hàng mà trên đó phải/ctrl-click được thực hiện. Điều đó có thể hoặc không thể là hàng đã chọn. – VoidPointer

Trả lời

21

Trong phương pháp menuForEvent của bạn, bạn có thể tìm ra hàng bấm xảy ra vào. Bạn có thể vượt qua điều đó như một tham số để phương pháp defaultMenu của bạn - có thể gọi nó là defaultMenuForRow:

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

Bây giờ bạn có thể xây dựng thực đơn cho hàng bạn tìm thấy trong sự kiện ...

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

Ngoài ra, như đã đề cập trong các nhận xét, bạn thực sự không nên sử dụng tiền tố NS trên các lớp của riêng bạn. Có một tiềm năng cho một cuộc đụng độ trong tương lai cộng với nó sẽ nhầm lẫn giữa tất cả mọi người rằng đang xem xét mã của bạn - bao gồm cả bản thân :)

Hope this helps ...

+0

Cảm ơn bạn rất nhiều! Vì vậy, nhiều thứ trong số này rất đơn giản để làm, nhưng chỉ một khi bạn biết làm thế nào! – Jacob

+0

Buồn, chúng ta cần phải phân lớp 'NSOutlineView' để đạt được điều này. Chức năng này nên được bao gồm trong giao thức đại biểu đã :-) –

-1

Nếu bạn thích, bạn có thể đính kèm menu để quan điểm cá nhân di động hoặc xem hàng và xây dựng nó với xây dựng giao diện:

@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

đây là một Swift 2.0 dụ trong đó sử dụng một lớp con và mở rộng mặc định NSOutlineDelegate, do đó bạn có thể định nghĩa các menu của bạn trong các đại biểu.

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

}