无法从另一个类调用NSOpenPanel并将其附加到其父窗口

时间:2016-11-08 20:17:14

标签: objective-c macos cocoa nsopenpanel

我遇到了NSOpenPanel的问题,并从另一个类调用它。

我目前有一个带有按钮的主窗口,打开第二个窗口,使用ImageKit设置为图像编辑器。这很好用。我还想在打开图像编辑器窗口时(由于按钮按下)启动NSOpenPanel。基本上我想绕过让用户点击按钮打开图像编辑器,然后点击"打开"在菜单或命令-O中打开图像。我们知道,如果用户打开图像编辑器,则需要打开图像进行编辑...我希望在显示窗口时打开面板。

在我的appDelegate.m中,我有这个代码来启动图像编辑器窗口" _imageWindow"并打电话给" openImage"方法:

[_imageWindow makeKeyAndOrderFront:self];
Controller *controllerOpenImage = [[Controller alloc] init];
[controllerOpenImage openImage];

除了应该是模态的打开面板作为单独的窗口启动而不附加到图像编辑器窗口(_imageWindow)时,这是有效的,所以当用户选择图像时它没有打开...我尝试添加延迟以允许_imageWindow窗口时间打开无效。我已尝试使用和不使用发件人的IBAction(openImage)和void(openImage),结果相同......

这是在我的Controller.m中打开图像的代码:

- (IBAction)openImage:(id)sender
{
    // present open panel...
    NSString *    extensions = @"tiff/tif/TIFF/TIF/jpg/jpeg/JPG/JPEG";
    NSArray *     types = [extensions pathComponents];

    NSString *url=[[NSUserDefaults standardUserDefaults] objectForKey:@"photoPath"];
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateFormat:@"yyyy"];
    NSString *yearString = [formatter stringFromDate:[NSDate date]];

    NSString *photoUrl =[NSString stringWithFormat:@"%@%@%@",url,@"/",yearString];

    // Let the user choose an output file, then start the process of writing samples
    NSOpenPanel *openPanel = [NSOpenPanel openPanel];
    [openPanel setDirectoryURL:[NSURL fileURLWithPath:photoUrl]];
    [openPanel setAllowedFileTypes:types];
    [openPanel setCanSelectHiddenExtension:YES];
    [openPanel beginSheetModalForWindow:_imageWindow completionHandler:^(NSInteger result) {
        if (result)
        {
                // user did select an image...
                [self openImageURL: [openPanel URL]];
        }
        [_imageView zoomImageToFit: self];
    }];
}

从我的appDelegate.m调用时,发件人是否为null,而从图像编辑器窗口(_imageEditor)调用时,发件人是否具有身份是否存在问题,或者我是否要求做一些无法做到的事情完成。

1 个答案:

答案 0 :(得分:0)

让我们看看你的代码。首先在一些方法/函数中执行:

[_imageWindow makeKeyAndOrderFront:self];

这会访问_imageWindow,它通过通用命名约定可能是实例变量或属性支持变量,但可能是全局的 - 你不会说。

Controller *controllerOpenImage = [[Controller alloc] init];

这会创建一个全新的对象,在局部变量中存储对它的引用。

[controllerOpenImage openImage];

这会在这个全新的对象上调用一个方法,在那个方法中你会这样做:

[openPanel beginSheetModalForWindow:_imageWindow ...

那么_imageWindow来自哪里?通过常见的命名约定,它是一个实例/属性变量,如果是,它属于Controller实例,并且在无法连接中与上面第一行中类似命名的变量。由于您没有显示init方法,因此我们不知道您是否初始化了此变量,如果您没有nil

另一方面,这可以引用全局,如果是,它可能与上面第一个代码行中引用的全局相同。如果是这种情况,您的代码可能会起作用,但它不会......

所以它是公平的猜测,两个引用都是不同的,但同样命名的实例/属性变量,它们没有连接,第二个是nil,因此{{1传递一个openPanel窗口引用并打开一个独立的对话框。

<强>附录

在您的第四条评论中,您将结束:

  

这有什么意义吗?

不幸的是没有。

当您将对象(例如窗口)链接到另一个对象的nil(例如IBOutlet类的实例)时,您将在特定的之间建立连接您的NIB(IB文档)创建的实例

当系统在运行时评估您的NIB时,它会创建一个窗口,作为Controller的实例,以及您的NSWindow类的实例,并放置对该特定将窗口实例放入特定 Controller实例的IBOutlet变量/属性中。

这对您可能创建的任何其他窗口没有影响,它们不会自动链接到Controller个实例;或者在任何其他Controller个实例上,它们不会自动链接到窗口。

当你写:

Controller

您正在创建一个新的Controller *controllerOpenImage = [[Controller alloc] init]; 实例,该实例位于无法连接到您的NIB创建的Controller实例中。最初的后一个实例,你没有使用的实例,可能会引用你的窗口;你正在使用的前者当然不会。

如果您要在NIB中创建Controller实例,那么在您的代码中,您需要使用该特定实例,而不是创建新实例。要使用它,您需要参考它。一种方法是在appDelegate类中添加一个引用它的属性,在你的NIB中设置链接。

在之前的评论中你写道:

  

但我不确定如何从第二条评论中推断出解决方案

您所引用的评论建议您通过将其作为参数传递,将您的窗口引用引入Controller类。这是任何编程语言中非常基本的机制。在这种情况下,它建议您编写一个方法,如:

Controller

使用以下命令创建- (instancetype) initWithWindow:(NSWindow *)aWindow { ... } 实例

Controller

听起来你需要回去研究实例,方法,参数传递的基础知识;然后如何评估NIB。

HTH