Cocoa - 从 nib 加载视图并将其显示在 NSView 容器中,作为子视图

Posted

技术标签:

【中文标题】Cocoa - 从 nib 加载视图并将其显示在 NSView 容器中,作为子视图【英文标题】:Cocoa - loading a view from a nib and displaying it in a NSView container , as a subview 【发布时间】:2010-06-21 10:09:54 【问题描述】:

我之前已经问过这个问题,但问题本身和其中的所有信息可能有点令人困惑,而且我想要得到的结果有点复杂。所以我开始了一个新的干净测试项目来处理我目前有兴趣了解的部分。

所以我想要的基本上是这样的:我有一个视图容器(继承 NSView)。在里面,我想放置一些图像,但不仅仅是简单的 NSImage 或 NSImageView,还有一些自定义视图(也继承 NSView),它本身包含一个文本字段和一个 NSImageView。我称之为“图像持有者”,它位于一个单独的 nib 文件中(我使用这种方法,因为我在 Apple SAmple 应用程序 COCOA SLIDES 之后引导自己)。 到目前为止,我得到的结果是一些东西,但不是我所期望的。我想我一定是在 Interface Builder 中做错了什么(没有连接正确的东西),但我希望有更多专业知识的人能够启发我。

下面我将尝试放置我目前拥有的所有代码:

//ImagesContainer.h
#import <Cocoa/Cocoa.h>


@interface ImagesContainer : NSView 


@end
//ImagesContainer.m
#import "ImagesContainer.h"
#import "ImageHolderView.h"
#import "ImageHolderNode.h"
@class ImageHolderView;
@class ImageHolderNode;
@implementation ImagesContainer

- (id)initWithFrame:(NSRect)frame 
    self = [super initWithFrame:frame];
    if (self) 
        // Initialization code here.
  //create some subviews
  for(int i=0;i<3;i++)
   ImageHolderNode *node = [[ImageHolderNode alloc] init];
   [self addSubview:[node rootView]];
  
    
 NSRunAlertPanel(@"subviews", [NSString stringWithFormat:@"%d",[[self subviews] count]], @"OK", NULL, NULL);
    return self;


- (void)drawRect:(NSRect)dirtyRect 
    // Drawing code here.

 [[NSColor blackColor] set];
 NSRectFill(NSMakeRect(0,0,dirtyRect.size.width,dirtyRect.size.height));
 int i=1;
 for(NSView *subview in [self subviews])
  [subview setFrameOrigin:NSMakePoint(10*i, 10)];
  i++;
 


@end

//ImageHolderView.h
#import <Cocoa/Cocoa.h>


@interface ImageHolderView : NSView 
 IBOutlet NSImageView *imageView;

@end
//ImageHolderVIew.m
#import "ImageHolderView.h"


@implementation ImageHolderView
- (id)initWithFrame:(NSRect)frame 
    self = [super initWithFrame:frame];
    if (self) 

    
    return self;


- (void)drawRect:(NSRect)dirtyRect 
    // Drawing code here.
 [[NSColor blueColor]set];
 NSRectFill(NSMakeRect(10,10, 100, 100));
 //[super drawRect:dirtyRect];

@end

//ImageHolderNode.h
#import <Cocoa/Cocoa.h>
@class ImageHolderView;

@interface ImageHolderNode : NSObject 
 IBOutlet ImageHolderView *rootView;
 IBOutlet NSImageView *imageView;

-(NSView *)rootView;
-(void)loadUIFromNib;
@end

//ImageHolderNode.m
#import "ImageHolderNode.h"


@implementation ImageHolderNode

-(void)loadUIFromNib 
 [NSBundle loadNibNamed:@"ImageHolder" owner: self];

-(NSView *)rootView 
 if( rootView == nil) 
  NSRunAlertPanel(@"Loading nib", @"...", @"OK", NULL, NULL);
  [ self loadUIFromNib];
 
 return rootView;


@end

我的笔尖文件是:

    MainMenu.xib

    ImageHolder.xib

    MainMenu 是我启动新项目时生成的 xib。

    ImageHolder 看起来像这样: image link

我将尝试在 xib ImageHolder 中提及迄今为止的连接:

文件的所有者 - 具有 ImageHolderNode 类 ImageHolder.xib 的主视图,具有类 ImageHolderView

所以要恢复,我得到的结果是视图容器中的 3 个蓝色矩形,但我似乎无法让它显示从 ImageHolder.xib 加载的视图

如果有人想看看 CocoaSlides 示例应用程序,它在苹果开发者页面上(不幸的是,我不允许发布超过 1 个链接 :))

【问题讨论】:

【参考方案1】:

确切地说,不是答案,因为不清楚你在问什么..

您创建一个视图(类“ImagesContainer”)。我们称之为 imagesContainerView

ImagesContainerView 生成 3 个对象(“ImageHolderNode”类)。 ImagesContainerView 向每个 imageHolderNode 询问它的 -rootView(可能是“ImageHolderView”)并将返回值添加到它的视图层次结构中。

ImagesContainerView 丢弃(但泄漏)每个 imageHolderNode。

所以视图层级看起来像:-

+ imagesContainerView
    + imageHolderView1 or maybe nil
    + imageHolderView2 or maybe nil
    + imageHolderView3 or maybe nil

这是您所期待的吗?

那么你在哪里打电话给-(void)loadUIFromNib 并等待笔尖加载? 在某些代码中您没有显示?

一般来说,一次进步一个步骤,让每个步骤都发挥作用。

NSAssert 是你的朋友。尝试它而不是误用警报面板和日志记录以进行调试。 IE。

ImageHolderNode *node = [[[ImageHolderNode alloc] init] autorelease];
NSAssert([node rootView], @"Eek! RootView is nil.");
[self addSubview:[node rootView]];

一个视图当然应该画一些东西。 TextViews 绘制文本,ImageViews 绘制图像。如果您需要绘制 Cocoa 提供的文本、图像、表格等以外的内容,则应将 NSView 子类化。

如果您需要从多个 nib 组装视图,您应该根据应用程序的需要在 nib 中排列视图,或者使用 viewController 或 windowController。这就是他们的目的。

编辑

界面生成器连接

如果 RootView 不是 nil,那么您似乎已正确连接了连接,但您说您不清楚..

确保将 IB 窗口设置为列表视图,以便您可以清楚地看到 nib 的内容。 'File's Owner' 代表将要加载 nib 的对象,对吧?在你的情况下 ImageHolderNode. 控制 单击文件的所有者,除其他外,您可以看到它的出口。当 nib 由 ImageHolderNode 加载时,控制从插座拖动(在列表视图中)到要设置为实例变量的对象。我知道你已经知道这一点,但没有别的了。

多哈

您究竟希望看到什么?一个空的图像视图?好吧,那看起来什么都不是。一个空的文本字段?那也一样,看起来什么都没有。将插座连接到您的 textfield 和 imageView 并在它们上设置一些内容。

【讨论】:

感谢您的回答。要回答你的两个问题:1)我问为什么在容器中,我没有看到我在 InterfaceBuilder 中创建的视图(我只得到我在 ImageHolderView 的 -drawRect 中所做的蓝色填充)2)我在哪里加载nib :这是在 ImageHolderNode 的实现中完成的,在 -(NSView *)rootView 的主体中。我很乐意使用另一种方式来做到这一点,但由于 Apple 示例是我目前为止 inspiration 的唯一来源,我试图使用我在那里找到的东西。 好的,我明白了。所以你需要检查rootView。是你认为的观点吗? IE。你把它正确连接了吗?它有多少个子视图,什么位置等等。 挂机是指在InterfaceBuilder中挂机?如果是的话,我想对此提出一些建议,因为我有点迷失在所有的挂钩过程中:) 我试图将它连接到尽可能接近我用作指南的示例应用程序中的连接处,但也许我没有不正确地做。好的,我刚刚做了一个快速测试,我显示了 rootView 拥有的子视图的数量:它应该有 2 个子视图(1 个文本字段和 1 个 nsimageview),它确实有 2 个。所以我猜它的加载正常,但仍然没有正确显示。 如果我在 NSText 字段中有一些内容,不应该显示吗?我想到了 NSImageView 它不能显示任何东西,因为它上面没有设置要显示的东西,但是如果文本字段在 IB 中有一些内容,我认为它应该已经显示了。我会调查一下然后回来。 嗨eemerge,我也有类似的问题。你是怎么解决这个问题的?

以上是关于Cocoa - 从 nib 加载视图并将其显示在 NSView 容器中,作为子视图的主要内容,如果未能解决你的问题,请参考以下文章

从 Cocoa 中的其他 nib(即 Interface Builder)加载 nib

从情节提要加载的 nib 的 Cocoa replaceSubview

如何获取从 nib ios 加载的自定义视图的实际大小

Cocoa 加载 ViewNib

nib 本地化时 Cocoa 无法加载窗口 nib 文件

从 Nib 加载 NSView 的多个实例