4

I have a printing function like so:

- (void)sendToPrinter:(int)code {
    NSPrintInfo *printInfo;
    NSPrintInfo *sharedInfo;
    NSPrintOperation *printOp;
    NSMutableDictionary *printInfoDict;
    NSMutableDictionary *sharedDict;

    sharedInfo = [NSPrintInfo sharedPrintInfo];
    sharedDict = [sharedInfo dictionary];
    printInfoDict = [NSMutableDictionary dictionaryWithDictionary:
                     sharedDict];
    [printInfoDict setObject:NSPrintSpoolJob 
                      forKey:NSPrintJobDisposition];
    printInfo = [[NSPrintInfo alloc] initWithDictionary: printInfoDict];
    [printInfo setHorizontalPagination: NSAutoPagination];
    [printInfo setVerticalPagination: NSAutoPagination];
    [printInfo setVerticallyCentered:NO];
    [printInfo setLeftMargin:10];
    [printInfo setRightMargin:10];
    [printInfo setTopMargin:10];
    [printInfo setBottomMargin:10];
    [printInfo setScalingFactor:1.1];
    printOp = [NSPrintOperation printOperationWithView:sheet 
                                             printInfo:printInfo];
    [printOp setShowsPrintPanel:YES];
    [printOp runOperation];
}

This prints a representation of a page preview called sheet, which is an NSBox. This works fine.

Sometimes I have more information that can fit on a page and so I have 'next page' buttons that fill sheet with a representation of Page2, Page3, etc. by reloading sheet with the relevant data. This works fine.

Now, if I want to print out information that will fit on 2 or 3 pages rather than 1, I want to be able to feed NSPrintInfo or NSPrintOperation additional pages manually before it goes to print, rather than pagination. Something like:

printOp = [NSPrintOperation printOperationWithView:sheet 
                                             printInfo:printInfo];
[self nextPage];
printOp = [NSPrintOperation printOperationWithView:sheet 
                                             printInfo:printInfo];
[self nextPage];
printOp = [NSPrintOperation printOperationWithView:sheet 
                                             printInfo:printInfo];
// run this in loop until all the pages are accounted for
[printOp setShowsPrintPanel:YES];
[printOp runOperation];

Any solutions? Thanks in advance.

biscuitstack
  • 11,591
  • 1
  • 26
  • 41
  • I'm reading up on suggestions to using PDFView or Quartz. This could be a route I go down but it seems way OTT considering I am printing an NSBox and, with one quick method, can change the entire NSBox to each subsequent page. I just want the print operation to accept the same NSBox as page2, page3 etc. with a quick call to the method to change the NSBox to the relevant page. – biscuitstack Apr 23 '11 at 12:49
  • Also take a look at this tutorial: http://cocoadevcentral.com/articles/000074.php It really helped my printing woes. – siannopollo Nov 03 '12 at 04:59

1 Answers1

1

You can't avoid pagination with the Cocoa printing system; as your comment mentions, you'll need to go to something lower-level.

However I don't think it should be too hard to adapt what you're doing to pagination. Take a look at Providing a Custom Pagination Scheme and Customizing a View's Drawing for Printing. Just subclass NSBox, provide rects that are the size of each page and adjust your coordinate system in beginPageInRect:atPlacement: so the box draws into the rect. You can get the current page number with [[NSPrintOperation currentOperation] currentPage] so you know what to draw.

Update: Turns out you don't even need to mess with your coordinate system if your view is already the right size. Here's an example of a very simple NSBox subclass that just changes its title for every page:

@implementation NumberBox

- (BOOL)knowsPageRange:(NSRangePointer)aRange;
{
    *aRange = NSMakeRange(1, 10);
    return YES;
}

- (void)beginPageInRect:(NSRect)aRect atPlacement:(NSPoint)location;
{
    [self setTitle:[NSString stringWithFormat:@"Page %d", [[NSPrintOperation currentOperation] currentPage]]];
    [super beginPageInRect:aRect atPlacement:location];
}

- (NSRect)rectForPage:(NSInteger)page;
{
    return [self bounds];
}

@end

One thing that may not have been obvious is the need to invoke the superclass's implementation of beginPageInRect:atPlacement:. Also, do not draw in rectForPage:, it won't work properly—that's the role of the beginPage…/endPage methods.

Nicholas Riley
  • 43,532
  • 6
  • 101
  • 124
  • I was hoping it would be as concise as I was summarising in my question but, if that's definitely not possible, these are helpful links to start me researching. Thanks Nicholas. – biscuitstack Apr 23 '11 at 21:02
  • Does subclassing NSBox provide straightforward access to customising Pagination (as in the tutorials) or is this only relevant to NSView? – biscuitstack Apr 24 '11 at 11:10
  • 1
    It applies to any NSView subclass including NSBox. – Nicholas Riley Apr 24 '11 at 15:02
  • Ahh.. for some reason I decided NSBox wasn't derrived from NSView. Makes sense now. This has brought up some other problems in my code so I'm gonna tackle them first and come back to this, when I'll report back. – biscuitstack Apr 25 '11 at 12:16
  • Ok. Sorted out my unexpected problem and am back on this now. With your kind help I've gotten far enough into the problem. I've been able subclass the `NSBox` and correctly inform `knowPageRange` the amount of pages needed. I've also gotten the same coordinate rectangle to print for each page. However, I'm stumped as to where a notice that the print page change happens that I can insert a call to my page change method. I tried it in `rectForPage` without luck. – biscuitstack Apr 26 '11 at 20:28
  • I should add that I'm aware you've pointed out how to get the current printing page. It's more that I need to know when the current printing page changes or has ended to call my method and refresh the `NSBox` to the next pages data. – biscuitstack Apr 26 '11 at 20:31
  • Hmmm... '- (NSRect)rectForPage:(int)page' was one way I found to tell when each new print page was being processed. However, my function being called (from a different class) is not switching the displayed page or producing errors. I'm stumped again. – biscuitstack Apr 26 '11 at 22:49
  • 1
    Don't draw in that method—it won't work. I revised my answer with some sample code. It turns out the default behavior of `beginPageInRect:atPlacement:` is actually quite nice; it centers your view at the top of the page rather than displaying it at the page origin in the bottom left (which is what you'd get without it). – Nicholas Riley Apr 27 '11 at 00:30
  • Ok, everything seems to be working fine but for calling a method in another class to change the NSBox content from `beginPageInRect:atPlacement:`. `NSLog` confirms it's called ok but it appears the problem is an `NSMutableArray` called *records*. If I call the method from within the class or using bindings, *records* contains data, but it's null when I call it from `beginPageInRect:atPlacement:` in my `NSBox` subclass and the method doesn't complete correctly. Thanks again for all your help. – biscuitstack Apr 27 '11 at 15:29
  • Sounds like that's more of an organizational problem in your code... you might describe it more thoroughly in another question. – Nicholas Riley Apr 27 '11 at 15:32
  • Good thinking. I guess the question has moved quite a bit off the the original and needs a new topic. Many thanks - I genuinely appreciate the help on this as it can be quite hard to get answers on xcode related things here compared to some other topics. – biscuitstack Apr 27 '11 at 15:41