2014-09-30 16 views
5

Trong ứng dụng OSX Tôi có chế độ xem bộ sưu tập là lớp con của NSCollectionView.Cách triển khai thực đơn theo ngữ cảnh cho NSCollectionView

Tôi hoàn toàn hài lòng với cách mọi thứ ngoại trừ menu ngữ cảnh mà tôi chưa thể tìm ra.

Vì vậy, những gì tôi muốn là:

  • nhấp chuột phải vào một mục xem bộ sưu tập sẽ làm xuất hiện menu ngữ cảnh
  • các tùy chọn chọn từ menu (xóa, chỉnh sửa, vv) đều được áp dụng cho các mục rằng nhấp chuột đã được thực hiện.

Tôi biết cách thực hiện nó cho NSOutlineView hoặc NSTableView, nhưng không phải cho chế độ xem bộ sưu tập.

Tôi không thể tìm ra cách lấy chỉ mục của mục được nhấp.

Có ai có bất kỳ ý tưởng nào về cách tôi có thể triển khai tính năng này không?

Mọi loại trợ giúp đều được đánh giá cao!

Trả lời

4

Một cách tiếp cận mà tôi đã sử dụng là không cố gắng áp dụng các thao tác menu theo ngữ cảnh cho một mục cụ thể được nhấp vào nhưng đối với các mục đã chọn. Và tôi làm cho mục được nhấp vào tự thêm vào vùng chọn.

Tôi đã sử dụng chế độ xem tùy chỉnh cho chế độ xem mục bộ sưu tập. Lớp chế độ xem tùy chỉnh có một lối thoát, item, với mục xem bộ sưu tập của riêng mình, mà tôi kết nối trong NIB. Nó cũng ghi đè -rightMouseDown: có mục thêm bản thân để lựa chọn:

- (void) rightMouseDown:(NSEvent*)event 
{ 
    NSCollectionView* parent = self.item.collectionView; 
    NSUInteger index = NSNotFound; 
    NSUInteger count = parent.content.count; 
    for (NSUInteger i = 0; i < count; i++) 
    { 
     if ([parent itemAtIndex:i] == self.item) 
     { 
      index = i; 
      break; 
     } 
    } 

    NSMutableIndexSet* selectionIndexes = [[parent.selectionIndexes mutableCopy] autorelease]; 
    if (index != NSNotFound && ![selectionIndexes containsIndex:index]) 
    { 
     [selectionIndexes addIndex:index]; 
     parent.selectionIndexes = selectionIndexes; 
    } 

    return [super rightMouseDown:event]; 
} 

Nếu bạn thích, chứ không phải thêm mục vào việc lựa chọn, bạn có thể kiểm tra xem nó đã có trong vùng chọn. Nếu có, đừng sửa đổi lựa chọn. Nếu không, thay thế lựa chọn chỉ với mục (làm cho nó là mục được chọn duy nhất).

Hoặc, bạn có thể đặt menu ngữ cảnh trên các chế độ xem mục thay vì trên chế độ xem bộ sưu tập. Sau đó, các mục menu có thể nhắm mục tiêu chế độ xem mục hoặc mục xem bộ sưu tập.

Cuối cùng, bạn có thể phân lớp NSCollectionView và ghi đè -menuForEvent:. Bạn vẫn sẽ gọi tới số super và trả lại menu nó trả về, nhưng bạn có thể nhân cơ hội này để ghi lại sự kiện và/hoặc mục tại vị trí của nó. Để xác định điều đó, bạn muốn làm điều gì đó như:

- (NSMenu*) menuForEvent:(NSEvent*)event 
{ 
    _clickedItemIndex = NSNotFound; 
    NSPoint point = [self convertPoint:event.locationInWindow fromView:nil]; 
    NSUInteger count = self.content.count; 
    for (NSUInteger i = 0; i < count; i++) 
    { 
     NSRect itemFrame = [self frameForItemAtIndex:i]; 
     if (NSMouseInRect(point, itemFrame, self.isFlipped)) 
     { 
      _clickedItemIndex = i; 
      break; 
     } 
    } 

    return [super menuForEvent:event]; 
} 
+0

đẹp !!! Cảm ơn bạn rất nhiều! –

+1

Đó là cách quá phức tạp. Bạn đã thử đặt cửa sổ trình đơn của chế độ xem bộ sưu tập của mình thành menu từ tệp nib của bạn chưa? Đặt đối tượng bộ điều khiển của bạn làm đại biểu cho menu. Mỗi khi menu được gọi, hãy cập nhật menu của bạn theo lựa chọn trong giao diện bộ sưu tập. – iljawascoding

+0

Tôi thực sự thích cách tiếp cận phân lớp 'NSCollectionView' - mang lại sự nhất quán tốt về hành vi với' NSTableView'. –

3

Dưới đây là Ken's idea để ghi đè menuForEvent: trong một lớp con NSCollectionView thực hiện trong Swift:

// MARK: - Properties 

/** 
The index of the item the user clicked. 
*/ 
var clickedItemIndex: Int = NSNotFound 

// MARK: - Menu override methods 

override func menuForEvent(event: NSEvent) -> NSMenu? 
{ 
    self.clickedItemIndex = NSNotFound 

    let point = self.convertPoint(event.locationInWindow, fromView:nil) 
    let count = self.content.count 

    for index in 0 ..< count 
    { 
     let itemFrame = self.frameForItemAtIndex(index) 
     if NSMouseInRect(point, itemFrame, self.flipped) 
     { 
      self.clickedItemIndex = index 
      break 
     } 
    } 

    return super.menuForEvent(event) 
} 
0

Cảm ơn cho giải pháp này. Tôi đã bọc nó vào lớp con NSCollectionView:

#import <Cocoa/Cocoa.h> 

@interface TAClickableCollectionViewItem : NSCollectionViewItem 
@property (nonatomic, assign) BOOL isClicked; 
@end 



@interface TAClickableCollectionView : NSCollectionView <NSMenuDelegate> 
@property (nonatomic, readonly) id clickedObject; 
@property (nonatomic, readonly) TAClickableCollectionViewItem *clickedItem; 
@end 

Vì vậy, bạn có thể sử dụng các ràng buộc trong Trình tạo giao diện để đánh dấu các mục được nhấp.

#import "TAClickableCollectionView.h" 

@implementation TAClickableCollectionViewItem 
@end 



@implementation TAClickableCollectionView 

- (NSMenu*) menuForEvent:(NSEvent*)event 
{ 
    NSInteger _clickedItemIndex = NSNotFound; 
    NSPoint point = [self convertPoint:event.locationInWindow fromView:nil]; 
    NSUInteger count = self.content.count; 
    for (NSUInteger i = 0; i < count; i++) 
    { 


    NSRect itemFrame = [self frameForItemAtIndex:i]; 
     if (NSMouseInRect(point, itemFrame, self.isFlipped)) 
      { 
      _clickedItemIndex = i; 
      break; 
      } 
     } 

    if(_clickedItemIndex < self.content.count) { 
     id obj = [self.content objectAtIndex:_clickedItemIndex]; 
     TAClickableCollectionViewItem *item = (TAClickableCollectionViewItem *)[self itemAtIndex:_clickedItemIndex]; 

     if(item != _clickedItem) { 
      [self willChangeValueForKey:@"clickedObject"]; 
      _clickedItem.isClicked = NO; 
      _clickedItem = item; 
      [self didChangeValueForKey:@"clickedObject"]; 
     } 

     item.isClicked = YES; 

     if(obj != _clickedObject) { 
      [self willChangeValueForKey:@"clickedObject"]; 
      _clickedObject = obj; 
      [self didChangeValueForKey:@"clickedObject"]; 
     } 
    } 

    return [super menuForEvent:event]; 
} 

- (void)menuDidClose:(NSMenu *)menu { 
    _clickedItem.isClicked = NO; 
} 
@end 
1

Về cơ bản, tất cả các giải pháp của chúng tôi đều có khả năng giải quyết các yêu cầu, nhưng tôi muốn bổ sung cho swift3 +, mà tôi nghĩ là giải pháp hoàn chỉnh.

/// 扩展NSCollectionView功能,增加常用委托 
class ANCollectionView: NSCollectionView { 
    // 扩展委托方式 
    weak open var ANDelegate: ANCollectionViewDelegate? 

    override func menu(for event: NSEvent) -> NSMenu? { 
     var menu = super.menu(for: event); 
     let point = self.convert(event.locationInWindow, from: nil) 
     let indexPath = self.indexPathForItem(at: point); 
     if ANDelegate != nil{ 
      menu = ANDelegate?.collectionView(self, menu: menu, at: indexPath); 
     } 
     return menu; 
    } 
} 

/// 扩展NSCollectionView的委托 
protocol ANCollectionViewDelegate : NSObjectProtocol { 
    func collectionView(_ collectionView:NSCollectionView, menu:NSMenu?, at indexPath: IndexPath?) -> NSMenu? 
} 

Đây là những gì tôi đã viết phần mở rộng và tôi hy vọng sẽ giúp mọi người.

Các vấn đề liên quan