如何获取 NSDocument 子类来打印自定义视图

Posted

技术标签:

【中文标题】如何获取 NSDocument 子类来打印自定义视图【英文标题】:How to get an NSDocument subclass to print custom views 【发布时间】:2015-01-15 13:41:53 【问题描述】:

What needs to be hooked up for an NSDocument subclass to call its print methods when File->Print... is chosen?

文件->打印菜单是如何连接的? (现在选择器/操作已连接到第一响应者的打印方法。这是在故事板中,而我的 NSDocument 子类有自己的 xib。)

我已经尝试实现所有:

-(void)print:(id)sender;
-(void)printDocument:(id)sender;
-(void)printDocumentWithSettings:(NSDictionary *)printSettings showPrintPanel:(BOOL)showPrintPanel delegate:(id)delegate didPrintSelector:(SEL)didPrintSelector contextInfo:(void *)contextInfo;
-(NSPrintOperation*)printOperationWithSettings:(NSDictionary *)printSettings error:(NSError *__autoreleasing *)outError;

但是当我选择打印时,它们都不会被调用。这些方法应该去哪里/谁调用它们? (我还尝试了一个带有自定义视图的基本应用程序,但也没有运气。)

【问题讨论】:

【参考方案1】:

好的。看起来问题是由于bug in Xcode:使用情节提要创建基于文档的应用程序时,文件菜单默认连接到print:,而printDocument: 不可用。

奇怪的是,我的print: 调用在某处被劫持,但我不知道在哪里(在应用程序级别,而不是文档,因为打印对话框是一个窗口而不是工作表)。 printDocument: 按预期工作,但必须手动定义才能连接。

这适用于基于文档的应用程序,目标为 10.10,并使用情节提要。

在带有主菜单的故事板中,为printDocument: 添加一个用户定义的操作(这是基于故事板的不同之处,我觉得是一个错误。基于 Xib 的不需要此用户定义的操作。)

连接文件选择器 -> 打印到第一响应者并选择 printDocument: 而不是 print:

不要在你的 NSDocument 子类中定义printDocument:。如果您愿意,请务必致电super 或以下方法之一。

来自 NSDocument.h

/* The action of the File menu's Print... item in a document-based application.
The default implementation of this method merely invokes
[self printDocumentWithSettings:[NSDictionary dictionary]
  showPrintPanel:YES 
        delegate:nil
didPrintSelector:NULL
     contextInfo:NULL].
*/
- (IBAction)printDocument:(id)sender;

printDocumentWithSettings 的默认实现依次调用printOperationWithSettings,因此您可以使用其中任何一种方法在打印表出现之前绘制自定义信息。

【讨论】:

基于非故事板文档的应用程序以 Print 指向 printDocument 开头,但是如果您删除连接并尝试将其放回原处,则必须像上面一样手动添加它,因此该错误可能更普遍,或者我在某处缺少设置。【参考方案2】:

将菜单项设置为-printDocument: 的公认解决方案是正确的,但不是(技术上)因为 Xcode 错误。 (不过,这是一个非常糟糕的默认设置。)

菜单项正在调用第一响应者的-print:。 NSView 实现了-print:,所以如果有任何东西被设置为第一响应者,你将使用 NSView 的-print:,而不是你的文档的-print: 打印。如果编辑您的文档需要文本编辑,您用于实现编辑的控件将设置为第一响应者,并且该控件将获得-print:

【讨论】:

非常有帮助。不需要 owenfi 精心设计的解决方法;将打印菜单项的操作重新指向printDocument:(已经出现在第一响应者的可能接收到的操作列表中)并实现printDocument:就足够了。以 nil 为目标的动作将因此以良好的顺序到达响应者链。【参考方案3】:

看看来自 Apple (https://developer.apple.com/library/mac/samplecode/TextEdit/Introduction/Intro.html) 的 TextEdit 示例代码

在我的非基于文档的应用程序中,我为打印菜单项设置了自定义操作。在这种方法中,我通过NSNotificationCenter 通知了我的控制器有关打印操作的信息。也许这也适合你:)

【讨论】:

从该示例中,“文件”->“打印”菜单与 First Responder 的“printDocument:”相关联,我在源代码中的其他任何地方都找不到(即使是用户定义的 First Responder 操作 - 虽然grep 显示它位于名为 designable.nib 的东西中,在 Xcode 中我看不到任何地方)。该方法在我的应用程序中的 First Responder 上不可用(基于文档的应用程序或标准应用程序),但对于调用 printOperationWithSettings: 方法确实很重要。 (如果我从 printDocument: 更改为 print: 在 textedit 中,它将不再打印。) 谢谢,这帮助我找到了 Xcode 错误的根源。

以上是关于如何获取 NSDocument 子类来打印自定义视图的主要内容,如果未能解决你的问题,请参考以下文章

从启动服务中隐藏 NSDocument 子类

如何从持久存储中获取数据并显示在自定义表格视单元上?有没有示例代码?

NSDocument 子类是不是是模型对象?

获取单个可转换属性的请求(Swift)

`attemptRecovery(fromError:optionIndex:)` 在 NSDocument 的 Swift 子类的超类中找不到

使用 NSDocument 时如何将情节提要视图绑定到 Core Data 实体?