2010-12-26 3 views
18

Я использую метод setView: на NSMenuItem, чтобы установить пользовательский вид. В этом пользовательском представлении есть изображение, которое отображает весь вид. NSMenuItem с этим настраиваемым представлением является первым в меню, но проблема в том, что не сидит на одном уровне с верхней частью меню, есть большая разница, как вы можете увидеть здесь:Gap выше NSMenuItem пользовательский вид

alt text

Почему это происходит и как я могу остановить его?


EDIT

Я использую этот код сейчас, но я получаю EXC_BAD_ACCESS на линии InstallControlEventHandler.

-(void)applicationDidFinishLaunching:(NSNotification *)aNotification { 
    HIViewRef contentView; 
    MenuRef menuRef = [statusMenu carbonMenuRef]; 

    HIMenuGetContentView(menuRef, kThemeMenuTypePullDown, &contentView); 

    EventTypeSpec hsEventSpec[1] = { 
     { kEventClassMenu, kEventMenuCreateFrameView } 
    }; 

    InstallControlEventHandler(contentView, 
          NewEventHandlerUPP((EventHandlerProcPtr)hsMenuCreationEventHandler), 
          GetEventTypeCount(hsEventSpec), 
          hsEventSpec, 
          NULL, 
          NULL); // Get EXC_BAD_ACCESS here. 
} 

static OSStatus hsMenuContentEventHandler(EventHandlerCallRef caller, EventRef event, void* refcon) 
{ 
    OSStatus err; 

    check(GetEventClass(event) == kEventClassControl); 
    check(GetEventKind(event) == kEventControlGetFrameMetrics); 

    err = CallNextEventHandler(caller, event); 
    if (err == noErr) 
    { 
     HIViewFrameMetrics metrics; 

     verify_noerr(GetEventParameter(event, kEventParamControlFrameMetrics, typeControlFrameMetrics, NULL, 
             sizeof(metrics), NULL, &metrics)); 

     metrics.top = 0; 

     verify_noerr(SetEventParameter(event, kEventParamControlFrameMetrics, typeControlFrameMetrics, 
             sizeof(metrics), &metrics)); 
    } 

    return err; 
} 

static OSStatus hsMenuCreationEventHandler(EventHandlerCallRef caller, EventRef event, void* refcon) 
{ 
    OSStatus err = eventNotHandledErr; 

    if (GetEventKind(event) == kEventMenuCreateFrameView) 
    { 
     err = CallNextEventHandler(caller, event); 
     if (err == noErr) 
     { 
      static const EventTypeSpec kContentEvents[] = 
      { 
       { kEventClassControl, kEventControlGetFrameMetrics } 
      }; 

      HIViewRef   frame; 
      HIViewRef   content; 

      verify_noerr(GetEventParameter(event, kEventParamMenuFrameView, typeControlRef, NULL, 
              sizeof(frame), NULL, &frame)); 
      verify_noerr(HIViewFindByID(frame, kHIViewWindowContentID, &content)); 
      InstallControlEventHandler(content, hsMenuContentEventHandler, GetEventTypeCount(kContentEvents), 
             kContentEvents, 0, NULL); 
     } 
    } 

    return err; 
} 

отметить также линию metrics.top = 0 это линия, которая должна устранить разрыв в верхней части. Однако я не могу заставить его работать так далеко. Кто-нибудь знает, почему я получаю EXC_BAD_ACCESS. Я уже создал и выделил statusMenu, так что наверняка он должен работать?

+0

Похоже, есть белая прокладка в верхней и нижней части каждого меню. Я также хотел бы знать, можно ли избежать этого. –

+0

Я предполагаю, что черная часть - это изображение, а не промежуток? Существует несколько дополнений между верхней и нижней частью меню, а также между элементами разделителя по эстетическим соображениям. Я не уверен, что это сделано, это NSMenu или NSMenuItem, но вам может понадобиться подкласс либо один, либо другой, чтобы предотвратить его. – d11wtq

+0

Я провел некоторое исследование и нашел это http://www.mail-archive.com/[email protected]/msg26997.html. Похоже, что потребуется обычная NSMenu и некоторые частные API-интерфейсы , –

ответ

15

Ваше сообщение помечено как «Objective-C» и «Cocoa», хотя ваш пример кода C и Carbon. Предполагаю, вы предпочтете решение Cocoa?

На самом деле это довольно просто в какао. Единственный трюк - это научиться рисовать вне линий. :-)

@interface FullMenuItemView : NSView 
@end 

@implementation FullMenuItemView 
- (void) drawRect:(NSRect)dirtyRect 
{ 
    NSRect fullBounds = [self bounds]; 
    fullBounds.size.height += 4; 
    [[NSBezierPath bezierPathWithRect:fullBounds] setClip]; 

    // Then do your drawing, for example... 
    [[NSColor blueColor] set]; 
    NSRectFill(fullBounds); 
} 
@end 

Используйте это так:

CGFloat menuItemHeight = 32; 

NSRect viewRect = NSMakeRect(0, 0, /* width autoresizes */ 1, menuItemHeight); 
NSView *menuItemView = [[[FullMenuItemView alloc] initWithFrame:viewRect] autorelease]; 
menuItemView.autoresizingMask = NSViewWidthSizable; 

yourMenuItem.view = menuItemView; 
+0

Работает великолепно! Просто нашел опечатку в вашем коде, хотя вы сказали 'initWithRect:', когда это должно быть 'initWithFrame:'. Большое спасибо, я никогда, хотя это было бы так просто! – Joshua

+0

Ах спасибо, исправил опечатку. Рад, что он решил вашу проблему! – skue

+0

joshua: если вам еще нужен приведенный выше код для работы без EXC_BAD_ACCESS, проверьте сообщение http: // stackoverflow.com/questions/6633843/how-to-remove-nsmenuitem-gap-above-custom-view-resolved – AmitSri

Смежные вопросы