我正在开发一个基于文档的应用程序。该文档可以有多个页面。所以我有一系列NSView对象可供我使用。现在我想在这个应用程序中提供打印功能,但NSPrintOpertion只接受一个NSView对象,因此我无法生成打印预览以及打印文档的多个页面。
在cocoa中有没有办法打印多页文档?
不幸的是,在可可的印刷不是免费的。你必须实现自己的NSView
子类来处理绘图。它必须能够访问您的数据并在每个页面上绘制正确的数据,具体取决于页码。
这是一个可以打印任何NSTableView
的示例源代码。我在这里用它来展示你如何计算在页面上绘制的东西的位置:
MyPrintView.h
:
#import <Cocoa/Cocoa.h>
@interface MyPrintView : NSView {
NSString *printJobTitle;
}
@property (copy, readwrite) NSString *printJobTitle;
- (id)initWithTableView:(NSTableView *)tableToPrint andHeader:(NSString *)header;
@end
MyPrintView.m
:
#import "MyPrintView.h"
@interface MyPrintView ()
@property (nonatomic, weak) NSTableView *tableToPrint;
@property (nonatomic, strong) NSString *header;
@property (nonatomic, strong) NSDictionary *attributes;
@property (nonatomic, strong) NSFont *listFont;
@property (nonatomic) float headerHeight;
@property (nonatomic) float footerHeight;
@property (nonatomic) float lineHeight;
@property (nonatomic) float entryHeight;
@property (nonatomic) NSRect pageRect;
@property (nonatomic) int linesPerPage;
@property (nonatomic) int currentPage;
@end
@implementation MyPrintView
@synthesize printJobTitle;
- (id)initWithTableView:(NSTableView *)tableToPrint andHeader:(NSString *)header
{
// Initialize with dummy frame
self = [super initWithFrame:NSMakeRect(0, 0, 700, 700)];
if (self) {
self.tableToPrint = tableToPrint;
self.header = header;
self.listFont = [NSFont fontWithName:@"Helvetica Narrow" size:10.0];
CGFloat x = self.listFont.capHeight;
x = self.listFont.ascender;
x = self.listFont.descender;
self.lineHeight = self.listFont.boundingRectForFont.size.height;
self.entryHeight = [self.listFont capHeight] * 3;
self.headerHeight = 20 + self.entryHeight;
self.footerHeight = 20;
if (self.listFont) {
self.attributes = @{ NSFontAttributeName: self.listFont };
} else {
self.attributes = nil;
}
printJobTitle = @"My Print Job";
}
return self;
}
#pragma mark Pagination
- (BOOL)knowsPageRange:(NSRangePointer)range
{
NSPrintInfo *printInfo = [[NSPrintOperation currentOperation] printInfo];
self.pageRect = [printInfo imageablePageBounds];
NSRect newFrame;
newFrame.origin = NSZeroPoint;
newFrame.size = [printInfo paperSize];
[self setFrame:newFrame];
// Number of lines per page
self.linesPerPage = (self.pageRect.size.height - self.headerHeight - self.footerHeight) / self.entryHeight - 1;
// Number of full pages
NSUInteger noPages = self.tableToPrint.numberOfRows / self.linesPerPage;
// Rest of lines on last page
if (self.tableToPrint.numberOfRows % self.linesPerPage > 0) {
noPages++;
}
range->location = 1;
range->length = noPages;
return YES;
}
- (NSRect)rectForPage:(NSInteger)page
{
self.currentPage = (int)page - 1;
return self.pageRect;
}
- (NSAttributedString *)pageHeader
{
return [[NSAttributedString alloc] initWithString:self.header];
}
#pragma mark Drawing
- (BOOL)isFlipped
{
// Origin top left
return YES;
}
// We need this to find any transformers which are used to display the values of a certain column
static NSValueTransformer *TransformerFromInfoDict( NSDictionary *dict )
{
NSDictionary *options = dict[NSOptionsKey];
if (options == nil) return nil;
NSValueTransformer *transformer = options[NSValueTransformerBindingOption];
if (transformer == nil || (id)transformer == [NSNull null]) {
transformer = nil;
NSString *name = options[NSValueTransformerNameBindingOption];
if (name != nil && (id)name != [NSNull null]) {
transformer = [NSValueTransformer valueTransformerForName: name];
}
}
return transformer;
}
// This is where the drawing takes place
- (void)drawRect:(NSRect)dirtyRect
{
float margin = 20;
float leftMargin = self.pageRect.origin.x + margin;
float topMargin = self.pageRect.origin.y + self.headerHeight;
[NSBezierPath setDefaultLineWidth:0.25];
CGFloat originalWidth = 0;
for (NSTableColumn *col in self.tableToPrint.tableColumns) {
originalWidth += col.width;
}
CGFloat widthQuotient = (self.pageRect.size.width - margin) / originalWidth;
CGFloat inset = (self.entryHeight - self.lineHeight - 1.0)/2.0;
// Column titles
CGFloat horOffset = 0;
for (NSTableColumn *col in self.tableToPrint.tableColumns) {
NSRect rect = NSMakeRect(linkerRand + horOffset, topMargin, widthQuotient * spalte.width, self.entryHeight);
horOffset += widthQuotient * col.width;
[NSBezierPath strokeRect:rect];
NSString *theTitle = @"--";
if ([col respondsToSelector:@selector(title)]) { // OS X 10.10 and higher
theTitle = col.title;
} else {
NSTableHeaderCell *cell = col.headerCell;
theTitle = cell.title;
}
[theTitle drawInRect:NSInsetRect(rect, inset, inset) withAttributes:self.attributes];
}
NSUInteger firstEntryOfPage = self.currentPage * self.linesPerPage;
NSUInteger lastEntryOfPage = ((self.currentPage + 1) * self.linesPerPage) > self.tableToPrint.numberOfRows ? self.tableToPrint.numberOfRows : ((self.currentPage + 1) * self.linesPerPage);
for (NSUInteger i = 0; i < lastEntryOfPage - firstEntryOfPage; i++) {
@autoreleasepool { // to avoid memory hogging
NSUInteger row = firstEntryOfPage + i;
CGFloat horOffset = 0;
for (NSTableColumn *col in self.tableToPrint.tableColumns) {
NSDictionary *bindingInfo = [spalte infoForBinding: @"value"];
NSArray *columnValues = [bindingInfo[NSObservedObjectKey] valueForKeyPath: bindingInfo[NSObservedKeyPathKey]];
NSString *valueAsStr = @"";
id value = [columnValues objectAtIndex:col];
if ((value != nil) && (![value isKindOfClass:[NSNull class]])) {
// Do we have a transformer for that column? Then transform accordingly.
NSValueTransformer *transformer = TransformerFromInfoDict(bindingInfo);
if (transformer != nil)
value = [transformer transformedValue: value];
if ([value isKindOfClass:[NSString class]]) {
valueAsStr = value;
} else if ([value isKindOfClass:[NSNumber class]]) {
NSCell *cell = [col dataCellForRow:zeile];
if (cell.formatter != nil) {
valueAsStr = [cell.formatter stringForObjectValue:value];
} else {
valueAsStr = [value stringValue];
}
} else {
// We don't know what that is
NSLog(@"value class: %@", [value class]);
valueAsStr = @"????!";
}
}
NSRect rect = NSMakeRect(leftMargin + horOffset, topMargin + (i+1) * self.entryHeight, widthQuotient * col.width, self.entryHeight);
horOffset += widthQuotient * col.width;
// Now we can finally draw the entry
[NSBezierPath strokeRect:rect];
NSRect stringRect = NSInsetRect(rect, inset, inset);
[valueAsStr drawInRect:stringRect withAttributes:self.attributes];
}
}
}
}
@end
这是你必须包含在printDocumentWithSettings
文档类中的内容,当用户选择“Print ...”时会调用它:
[[self.printInfo dictionary] setValue:@YES forKey:NSPrintHeaderAndFooter];
NSString *headerLine = @"My first printed Table View";
MyPrintView *myPrintView = [[MyPrintView alloc] initWithTableView:theTableView andHeader:headerLine];
NSPrintOperation *op = [NSPrintOperation
printOperationWithView:myPrintView
printInfo:[self printInfo]];
[op setShowsPrintPanel:showPrintPanel];
// Run print operation, which shows the print panel if showPanels was YES
[self runModalPrintOperation:op
delegate:self
didRunSelector:nil
contextInfo:NULL];