2012-03-15 29 views

Trả lời

22

Yup.

Mở nút gọi hành động

[NSMenu popUpContextMenu:menu withEvent:event forView:(NSButton *)sender]; 

nơi menu - menu mà bạn muốn hiển thị người gửi - nút bạn nhấp vào. sự kiện - bạn có thể tạo sự kiện mới và trong khi tạo chỉ định vị trí như nơi bạn muốn trình đơn bật lên được hiển thị.

+0

Đã cố gắng nhưng trình đơn "bật lên" hơi đi khắp nơi. Tôi muốn nó xuất hiện chính xác DƯỚI nút (ví dụ như "Tab mới", "Cửa sổ mới", v.v ... trong Google Chrome), nhưng cách này xuất hiện quá ... cao ... –

+1

Ya. Như tôi đã nói ở trên, bạn có thể chỉ định vị trí của trình đơn bật lên (nơi nó cần được hiển thị) trong khi tạo sự kiện. –

+0

OK. Tôi đã hiểu rồi. Tôi sẽ đăng câu trả lời đầy đủ cho một câu hỏi của tôi ... –

4

Sử dụng menu ngữ cảnh trên cuộc gọi hành động không phải là cách tuyệt vời để thực hiện vì trình đơn không hiển thị cho đến khi mouseUp - bạn không bị giữ hành vi menu kéo &. Mẫu ButtonMadness của Apple cho thấy cách thực sự làm điều này trong một lớp con của NSButton, xem DropDownButton. https://developer.apple.com/library/mac/samplecode/ButtonMadness/Introduction/Intro.html

Tổng kết lớp con rằng: tạo ra một NSPopUpButtonCell với pullsDown thiết lập để YES & preferredEdge để NSMaxYEdge, sao chép thực đơn của bạn để thêm một mục đầu trống và đặt nó như menu của tế bào đó, trên mouseDown gọi [thePopUpCell performClickWithFrame: self.bounds inView : tự] và đặt self.needsDisplay

+0

Ngày 10.8 ít nhất mã DropDownButton bị lỗi. Để làm nổi bật vấn đề xây dựng mẫu ButtonMadness và nhấp vào DropDownButton. Menu sẽ hiển thị - không chọn một mục. Bây giờ bấm nút Radio 2 - menu bị ẩn nhưng mục radio không được chọn. Vì vậy, nhấp một lần nữa, menu sẽ hiển thị lại. một nhấp chuột khác và nó ẩn vv. –

+2

Tại sao bạn cần phải thêm mục trống? Tôi đánh giá cao rằng bạn làm (không thêm nó cắt ngắn menu) nhưng tôi không thể tìm ra lý do tại sao –

5

Như tôi đã nhận xét tôi thấy ví dụ về ButtonMadness ít hoàn hảo hơn. Việc triển khai của tôi dường như hoạt động tốt hơn. Trình đơn được hiển thị trên chuột xuống, nút vẫn bị trầm cảm trong suốt, vị trí menu có thể được chỉ định và menu bị loại bỏ mà không hiển thị giả mạo sau đó.

Thành thật mà nói NSPopupButton là lựa chọn tốt hơn trong phần lớn các tình huống. Tôi sử dụng mã này chủ yếu là do sự tiện lợi của việc có một lớp cho các nút và cửa sổ bật lên và vì trình đơn không chứa hình ảnh và tiêu đề điều khiển bật lên. Tôi tải trình đơn từ một ngòi ngách riêng và tái sử dụng nó như là ở nơi khác trong ứng dụng theo yêu cầu.

Lưu ý rằng nó là tầm thường để thêm hỗ trợ bổ sung để nói một cửa sổ bật lên cũng như menu.

NSButton subclass: 

- (void)mouseDown:(NSEvent *)theEvent { 

    // if a menu is defined let the cell handle its display 
    if (self.menu) { 
     if ([theEvent type] == NSLeftMouseDown) { 
      [[self cell] setMenu:[self menu]]; 
     } else { 
      [[self cell] setMenu:nil]; 
     } 
    } 

    [super mouseDown:theEvent]; 
} 

NSButtonCell subclass: 

- (BOOL)trackMouse:(NSEvent *)event inRect:(NSRect)cellFrame ofView:(NSView *)controlView untilMouseUp:(BOOL)untilMouseUp 
{ 
    // if menu defined show on left mouse 
    if ([event type] == NSLeftMouseDown && [self menu]) { 

     NSPoint result = [controlView convertPoint:NSMakePoint(NSMidX(cellFrame), NSMidY(cellFrame)) toView:nil]; 

     NSEvent *newEvent = [NSEvent mouseEventWithType: [event type] 
               location: result 
              modifierFlags: [event modifierFlags] 
               timestamp: [event timestamp] 
              windowNumber: [event windowNumber] 
               context: [event context] 
              eventNumber: [event eventNumber] 
              clickCount: [event clickCount] 
               pressure: [event pressure]]; 

     // need to generate a new event otherwise selection of button 
     // after menu display fails 
     [NSMenu popUpContextMenu:[self menu] withEvent:newEvent forView:controlView]; 

     return YES; 
    } 

    return [super trackMouse:event inRect:cellFrame ofView:controlView untilMouseUp:untilMouseUp]; 
} 
+0

Hoạt động tuyệt vời cho tôi. Tôi đã tìm thấy tôi có thể thiết lập menu trực tiếp trên các tế bào và không cần phải phân lớp các nút ở tất cả. Tôi có thiếu một số lý do này sẽ là một vấn đề? –

4

Gần đây, tôi đã cố gắng để thực hiện nó và tôi đi, như tôi nghĩ, với một giải pháp đơn giản hơn

-(IBAction)buttonClick:(id)sender { 
    NSButton * b = (NSButton*)sender; 
    NSPoint l = [ self.window convertBaseToScreen:b.frame.origin ]; 

    [ self.menu popUpMenuPositioningItem:nil atLocation:l inView:nil ]; 
} 

Cập nhật

convertBaseToScreen bị phản đối bắt đầu từ 10.7, thay vì nó sử dụng convertRectToScreen theo cách sau:

NSPoint l = [self.window convertRectToScreen:b.frame].origin; 
+0

Đẹp một cách đơn giản, điều này làm việc tốt. –

+1

convertBaseToScreen không được dùng nữa kể từ 10_7 –

+0

Với bảng phân cảnh (trong ViewController), nó có vẻ không hoạt động. Tôi đã thử mà không thành công: 'NSPoint point = [[cửa sổ self.view] convertRectToScreen: ((NSButton *) người gửi) .frame] .origin;' một số ý tưởng? – Joannes

5

Phiên bản Swift của câu trả lời được chấp nhận

@IBAction func actionOccurred(sender: NSButton) { 
    if let event = NSApplication.sharedApplication().currentEvent { 
     NSMenu.popUpContextMenu(sender.menu!, withEvent: event, forView: sender) 
    } 
} 
Các vấn đề liên quan