NSMenuItem 自定义视图上方的间隙

发布于 2024-10-08 21:20:18 字数 3065 浏览 8 评论 0原文

我在 NSMenuItem 上使用 setView: 方法来设置自定义视图。在此自定义视图中,有一个图像占据整个视图。带有此自定义视图的 NSMenuItem 是菜单中的第一个,但问题是它没有与菜单顶部齐平,有一个很大的间隙,如下所示:

alt text

为什么会发生这种情况以及如何阻止它?


编辑

我现在正在使用此代码,但我在InstallControlEventHandler行上收到EXC_BAD_ACCESS

-(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 所以它肯定可以工作吗?

I am using the setView: method on an NSMenuItem to set a custom view. In this custom view there is an image which takes the whole of the view. The NSMenuItem with this custom view is the first in the menu but the problem is it doesn't sit flush with the top of the menu, there is a big gap as you can see here:

alt text

Why is this happening and how can I stop it?


EDIT

I am using this code now but I am getting EXC_BAD_ACCESS on the line 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;
}

Also note the line metrics.top = 0 this is the line which should remove the gap at the top. However I cannot get it work that far. Does anyone know why I would be recieving an EXC_BAD_ACCESS there. I have already created and allocated statusMenu so surely it should work?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

夏九 2024-10-15 21:20:18

尽管您的示例代码是 C 和 Carbon,但您的帖子被标记为“Objective-C”和“Cocoa”。我想您更喜欢可可解决方案?

实际上在 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;

Your post is tagged "Objective-C" and "Cocoa", although your sample code is C and Carbon. I assume you'd prefer a Cocoa solution?

It's actually pretty simple in Cocoa. The only trick is learning how to draw outside the lines. :-)

@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

Use it like this:

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;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文