2010-12-26 15 views
18

Używam metody setView: na NSMenuItem, aby ustawić niestandardowy widok. W tym niestandardowym widoku znajduje się obraz, który zajmuje cały widok. NSMenuItem z tego widoku niestandardowego jest pierwszym w menu, ale problemem jest to, że nie siedzieć w jednej płaszczyźnie z góry menu, istnieje duża różnica jak widać tutaj:Gap powyżej NSMenuItem niestandardowy widok

alt text

Dlaczego czy to się dzieje i jak mogę to powstrzymać?


EDIT

używam tego kodu, ale teraz jestem coraz EXC_BAD_ACCESS na linii 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; 
} 

Również zwrócić uwagę na linię metrics.top = 0 jest to linia, która powinna usunąć lukę na górze. Jednak nie mogę zrobić tego tak daleko. Czy ktoś wie, dlaczego dostałbym tam EXC_BAD_ACCESS. Mam już utworzone i przydzielone statusMenu, więc na pewno powinno działać?

+0

Wygląda na to, że jest biały spacer na górze i na dole każdej menu. Chciałbym też wiedzieć, czy można tego uniknąć. –

+0

Zakładam, że czarna część jest obrazem, a nie luką? Między górną i dolną częścią menu znajduje się dopełnienie, oprócz elementów separujących, ze względów estetycznych. Nie jestem pewien, czy jest to wykonane NSMenu lub NSMenuItem, ale może trzeba podklasy jednego lub drugiego, aby temu zapobiec. – d11wtq

+0

Zrobiłem kilka badań i pojawiłem się na http://www.mail-archive.com/[email protected]/msg26997.html Wygląda na to, że potrzebne będzie niestandardowe NSMenu i trochę prywatnego majsterkowania API . –

Odpowiedz

15

Twój post jest oznaczony jako "Objective-C" and "Cocoa", chociaż Twój przykładowy kod to C i Carbon. Zakładam, że wolisz rozwiązanie kakao?

Jest to całkiem proste w kakao. Jedyną sztuczką jest nauczenie się rysowania poza liniami. :-)

@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 

Używaj go tak:

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

Działa doskonale! Właśnie znalazłem literówkę w twoim kodzie, chociaż powiedziałeś "initWithRect:", kiedy powinno być 'initWithFrame:'. Dziękuję bardzo, nigdy nie byłbym tak łatwy jak to! – Joshua

+0

Ah dzięki, naprawiono literówkę. Cieszę się, że rozwiązał twój problem! – skue

+0

joshua: jeśli nadal potrzebujesz powyższego kodu do pracy bez EXC_BAD_ACCESS, sprawdź post http: // stackoverflow.com/questions/6633843/how-to-remove-nsmenuitem-gap-over-custom-view-solveved – AmitSri

Powiązane problemy