Cocoa osx PDFView NSPrintOperation PrintPanel not

2019-02-25 01:12发布

In my app for Mac I have a webview that shows some html content. I create a PDFDocument from that webview and then I want to print that document. So I create a PDFView from the document and then I call the NSPrintOperation printOperationWithView. When showing the print panel all appears correct except the page preview which appears blank, but if I press the details button the panel is refreshed and the page preview appears correctly.

How can I solve this?? Need help please. Thanks in advance.

This is an example of my problem:

1- The print panel shows with a blank page preview. Next I press show details.

enter image description here

2- After refreshing the panel the page preview appears correctly.

enter image description here

This is my code:

NSPrintInfo *printInfo = [NSPrintInfo sharedPrintInfo];
[printInfo setTopMargin:0.0];
[printInfo setBottomMargin:0.0];
[printInfo setLeftMargin:0.0];
[printInfo setRightMargin:0.0];
[printInfo setHorizontalPagination:NSFitPagination];
[printInfo setVerticalPagination:NSAutoPagination];
[printInfo setVerticallyCentered:NO];
[printInfo setHorizontallyCentered:YES];

NSData *pdfFinal = [[[[webView mainFrame] frameView] documentView] dataWithPDFInsideRect:[[[webView mainFrame] frameView] documentView].frame];

PDFDocument *doc = [[PDFDocument alloc] initWithData:pdfFinal];
PDFView *pdfView = [[PDFView alloc] init];
[pdfView setDocument:doc];

NSPrintOperation *op;
op = [NSPrintOperation printOperationWithView:pdfView.documentView printInfo:printInfo];

[op setShowsProgressPanel:YES];
[op setShowsPrintPanel:YES];
[op runOperation];

2条回答
够拽才男人
2楼-- · 2019-02-25 01:19

From this link:

PDFDocument *doc = ...;

// Invoke private method.
// NOTE: Use NSInvocation because one argument is a BOOL type. Alternately, you could declare the method in a category and just call it.
BOOL autoRotate = NO; // Set accordingly.
NSMethodSignature *signature = [PDFDocument instanceMethodSignatureForSelector:@selector(getPrintOperationForPrintInfo:autoRotate:)];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
[invocation setSelector:@selector(getPrintOperationForPrintInfo:autoRotate:)];
[invocation setArgument:&printInfo atIndex:2];
[invocation setArgument:&autoRotate atIndex:3];
[invocation invokeWithTarget:doc];

// Grab the returned print operation.
void *result;
[invocation getReturnValue:&result];

NSPrintOperation *op = (__bridge NSPrintOperation *)result;
[op setShowsPrintPanel:YES];
[op setShowsProgressPanel:YES];
[op runOperation];

This works on OSX from 10.4 to 10.10 (Yosemite).

EDIT: You can also see this answer which is similar, but with less lines of code.

查看更多
干净又极端
3楼-- · 2019-02-25 01:27

At a guess, since PDFView is a subclass of NSView, whose designated initializer is -initWithFrame:, not -init, your call to PDFView *pdfView = [[PDFView alloc] init] may not be allowing the PDFView to set up its initial state, though subsequent calls to its machinery may be magically resolving this state for you but NSView and subclasses tend to behave strangely (particularly with respect to drawing) when you don't use the proper designated initializer (which means its frame and bounds are equal to NSZeroRect).

Try using -initWithFrame: with some reasonable, non-zero rectangle.

Update

Alright, just a wild shot in the dark, but the documentation for NSPrintOperation says that -runOperation blocks the main thread and recommends using -runOperationModalForWindow:delegate:didRunSelector:contextInfo: to avoid blocking the main thread entirely. Is it possible that by blocking the main thread something else is being prevented from doing its initial work (I'd call this either undocumented behavior or an API bug, but...)? Try implementing the modal version instead and see if that helps. If not, I'd actually file a bug report with Apple.

查看更多
登录 后发表回答