我正在尝试为 macOS 应用程序实现打印。我创建了一个自定义 NSView 类来处理它,如 Apple 开发人员文档中所述。为了方便多页打印,我遵循了布局页面内容页面中的指导。
我的 PrintView 类代码如下所示:
import Cocoa
class PrintView: NSView {
let configuration: PrintConfiguration // a struct with some margin info and helpers
let info = NSPrintInfo.shared
private(set) var pageNum = 0
private(set) var ranges: [NSRange] = [] // array of pre-calculated page content
private(set) var content: NSAttributedString
override var isFlipped: Bool {
return true
}
init(printContent: NSAttributedString, config: PrintConfiguration, ranges: [NSRange]) {
self.content = printContent
self.ranges = ranges
self.configuration = config
super.init(frame: CGRect(origin: .zero, size: info.paperSize))
self.frame.size.height = config.printHeight
info.verticalPagination = .automatic
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func draw(_ dirtyRect: NSRect) {
print("Entering draw - dirtyRect: \(dirtyRect)")
let rangeNum = pageNum - 1 // adjust to 0-based for accessing array
let range = ranges[rangeNum]
let text = self.content.attributedSubstring(from: range)
let drawRect = configuration.printRect
text.draw(in: drawRect)
}
override func knowsPageRange(_ range: NSRangePointer) -> Bool {
print("Entering knowsPageRange")
range.pointee.location = 1
range.pointee.length = self.ranges.count
print("Page range: \(range.pointee)")
return true
}
override func rectForPage(_ page: Int) -> NSRect {
print("Entering rectForPage")
self.pageNum = page
let pageHeight = configuration.printHeight
let pageNum = CGFloat(page - 1)
let printRect = CGRect(x: configuration.leftMargin,
y: (pageNum * pageHeight) + configuration.topMargin,
width: configuration.printWidth,
height: configuration.printHeight)
print("Print rect: \(printRect)")
return printRect
}
override func locationOfPrintRect(_ rect: NSRect) -> NSPoint { // only included this method to see if it's called -- it doesn't appear to be required for my implementation
print("Entering locationOfPrintRect")
return NSPoint(x: self.configuration.leftMargin, y: self.configuration.topMargin)
}
}
然后从视图的打印方法中,我可以这样调用它:
let printView = PrintView(printContent: text, config: printConfiguration, ranges: ranges)
let info = NSPrintInfo.shared
let printOp = NSPrintOperation(view: printView, printInfo: info)
printOp.jobTitle = title // a view property
printOp.canSpawnSeparateThread = true
printOp.run()
当我从正在运行的应用程序中使用应扩展到两页的文本调用它时,我会在控制台中看到以下内容:
Entering knowsPageRange
Page range: {1, 2}
Entering knowsPageRange
Page range: {1, 2}
Entering rectForPage
Print rect: (40.0, 80.0, 532.0, 652.0)
Entering locationOfPrintRect
Entering draw - dirtyRect: (40.0, 80.0, 532.0, 572.0)
Entering rectForPage
Print rect: (40.0, 732.0, 532.0, 652.0)
Entering locationOfPrintRect
换句话说,我期望被调用两次的所有方法(每个页面一次)都被调用了两次(或者在knowsPageRange的情况下调用更多),除了draw方法。正如该行为所预期的那样,仅呈现第一页。打印预览对话框确实显示要打印的两页,但第二页是空白的。
同样,如果我选择打印对话框选项将打印作业发送到预览应用程序,它只会显示第一页文本。
最初写完我的问题后,我遛了狗,我突然想到我应该尝试使用应该将文本扩展到两页以上的文本。当我回来执行此操作时,它再次创建了正确的页面数,但仅绘制第一页的文本。然而,对于 6 页的文本,分页方法只调用了 3 次:
Entering knowsPageRange
Page range: {1, 6}
Entering knowsPageRange
Page range: {1, 6}
Entering rectForPage
Print rect: (40.0, 80.0, 532.0, 652.0)
Entering locationOfPrintRect
Entering draw - dirtyRect: (40.0, 80.0, 532.0, 572.0)
Entering rectForPage
Print rect: (40.0, 732.0, 532.0, 652.0)
Entering locationOfPrintRect
Entering rectForPage
Print rect: (40.0, 1384.0, 532.0, 652.0)
Entering locationOfPrintRect
如果有人能告诉我我做错了什么,我将不胜感激。
感谢 @Willeke 引导我走向正确的方向,我的代码现在可以通过对
rectForPage
方法进行以下更改来使用:
override func rectForPage(_ page: Int) -> NSRect {
self.pageNum = page
let printRect = CGRect(x: configuration.leftMargin,
y: configuration.topMargin,
width: configuration.printWidth,
height: configuration.info.paperSize.height - configuration.bottomMargin)
return printRect
}