2012-12-22 15 views
4

我有一个可可应用程序,我在其中创建了一个我想发送给打印机的customView。在子类NSView中,我也设置了一些框架选项,代码如下。我有2个全局变量来保存在main()函数外部声明的打印信息。可可(Mac OS X)打印多页,为什么预览窗口显示2页而不是1?

- (id)initWithFrame:(NSRect)frame 
{ 
    extern NSPrintInfo *globalPrintInfo; 
    extern NSPrintOperation *globalPrintOperation; 

    //Modify the frame before it's sent to it's super method. Also set the global variables to there default values. 
    globalPrintOperation = [NSPrintOperation printOperationWithView:self]; 
    globalPrintInfo = [globalPrintOperation printInfo];//Get the print information from it. 

    [globalPrintInfo setBottomMargin:0.0]; 
    [globalPrintInfo setLeftMargin:0.0]; 
    [globalPrintInfo setTopMargin:0.0]; 
    [globalPrintInfo setRightMargin:0.0]; 

    [globalPrintOperation setPrintInfo:globalPrintInfo];//save the printInfo changes. 

    //modify the frame to reflect the correct height & width of the paper. 
    frame.size.height = globalPrintInfo.paperSize.height-globalPrintInfo.topMargin-globalPrintInfo.bottomMargin; 
    frame.size.width = globalPrintInfo.paperSize.width-globalPrintInfo.leftMargin-globalPrintInfo.rightMargin; 
    frame.origin.x=0; 
    frame.origin.y=0; 

    NSLog(@"Printer Name=%@, Printer Type=%@",globalPrintInfo.printer.name,globalPrintInfo.printer.type); 

    self = [super initWithFrame:frame]; 
    if (self) { 
     // Initialization code here. 

    } 

    return self; 
} 

对于子类的NSView,这样我可以看到它的边界,我添加下面的下面的代码它的drawRect方法。

- (void)drawRect:(NSRect)dirtyRect 
{ 
    if ([NSGraphicsContext currentContextDrawingToScreen]) { 
     NSLog(@"Drawing To Screen"); 
    } else { 
     NSLog(@"Drawing To Printer"); 
    } 

    // Draw common elements here 

    CGContextRef myContext = [[NSGraphicsContext currentContext] graphicsPort]; 

    //Set color of drawing to green, and fill the rectangle green, so we can see it's boundaries. 
    [[NSColor greenColor] setFill]; 
    NSRectFill(dirtyRect); 

    CGContextSelectFont(myContext, "Helvetica-Bold", 18, kCGEncodingMacRoman); 
    CGContextSetCharacterSpacing(myContext, 10); 
    CGContextSetTextDrawingMode(myContext, kCGTextFillStroke); 

    CGContextSetRGBFillColor(myContext, 0, 0, 0, 1);//black 
    CGContextSetRGBStrokeColor (myContext, 0, 0, 1, 1);//blue stroke 
    CGContextShowTextAtPoint(myContext, 40, 0, "Here is some text!", 18); 

} 

当我去使用全局变量来运行打印操作,像这样......

- (IBAction)print:(id)sender { 
    NSLog(@"Testing Print"); 

    extern NSPrintOperation *globalPrintOperation; 

    [globalPrintOperation runOperation]; 
} 

我得到的打印窗口出现,我看到我的“绿色背景”对我的看法,但由于某种原因,它被分成2页。我不确定究竟发生了什么,因为我将框架的宽度和高度设置为高度,因此我们不胜感激任何帮助。下面是我看到的一些图像。

我的猜测是pagesize的宽度和高度与用于定义视图框架的像素单位类型的单位不同。

我的最终目标是制作一个程序,让用户选择他们想要的内容,并根据他们选择的选项打印特定的页面,但首先我要弄清楚如何甚至可以获得我期望的'内容' 1'页面而不是'2'。我可以通过实验手动确定宽度和高度,但对于我所假设的不同纸张尺寸,这不会很动态。

在此先感谢。

Image1

Image2

编辑***

我刚编辑我的代码下面的下面的子类的NSView

//METHOD OVERIDES 
- (id)initWithFrame:(NSRect)frame 
{ 
    extern NSPrintInfo *globalPrintInfo; 
    extern NSPrintOperation *globalPrintOperation; 

    //Modify the frame before it's sent to it's super method. Also set the global variables to there default values. 
    globalPrintOperation = [NSPrintOperation printOperationWithView:self];//use whatever is currently there as the default print operation. 
    globalPrintInfo = [globalPrintOperation printInfo];//Get the print information from it. 

    [globalPrintInfo setBottomMargin:0.0]; 
    [globalPrintInfo setLeftMargin:0.0]; 
    [globalPrintInfo setTopMargin:0.0]; 
    [globalPrintInfo setRightMargin:0.0]; 

    [globalPrintOperation setPrintInfo:globalPrintInfo];//save the printInfo changes. 

    //modify the frame to reflect the correct height & width of the paper. 
    frame.size.height = (globalPrintInfo.paperSize.height-globalPrintInfo.topMargin-globalPrintInfo.bottomMargin); 
    frame.size.width = globalPrintInfo.paperSize.width-globalPrintInfo.leftMargin-globalPrintInfo.rightMargin; 
    frame.origin.x=0; 
    frame.origin.y=0; 

    NSLog(@"Printer Name=%@, Printer Type=%@",globalPrintInfo.printer.name,globalPrintInfo.printer.type); 

    self = [super initWithFrame:frame]; 
    if (self) { 
     // Initialization code here. 

    } 

    return self; 
} 

- (void)drawRect:(NSRect)dirtyRect 
{ 
    if ([NSGraphicsContext currentContextDrawingToScreen]) { 
     NSLog(@"Drawing To Screen"); 
    } else { 
     NSLog(@"Drawing To Printer"); 
    } 

    // Draw common elements here 

    CGContextRef myContext = [[NSGraphicsContext currentContext] graphicsPort]; 

    //Set color of drawing to green, and fill the rectangle green, so we can see it's boundaries. 
    [[NSColor greenColor] setFill]; 
    NSRectFill(dirtyRect); 

    CGContextSelectFont(myContext, "Helvetica-Bold", 18, kCGEncodingMacRoman); 
    CGContextSetCharacterSpacing(myContext, 10); 
    CGContextSetTextDrawingMode(myContext, kCGTextFillStroke); 

    CGContextSetRGBFillColor(myContext, 0, 0, 0, 1);//black 
    CGContextSetRGBStrokeColor (myContext, 0, 0, 1, 1);//blue stroke 
    CGContextShowTextAtPoint(myContext, 40, 0, "Here is some text!", 18); 

} 


- (BOOL)knowsPageRange:(NSRangePointer)range { 
    NSRect bounds = [self bounds]; 
    float printHeight = [self calculatePrintHeight]; 

    range->location = 1; 
    range->length = NSHeight(bounds)/printHeight + 1; 

    NSLog(@"Calculated Page Range"); 
    return YES; 
} 

// Return the drawing rectangle for a particular page number 
- (NSRect)rectForPage:(int)page { 
    NSRect bounds = [self bounds]; 
    float pageHeight = [self calculatePrintHeight]; 
    NSLog(@"Created Rect For View"); 
    return NSMakeRect(NSMinX(bounds), NSMaxY(bounds) - page * pageHeight, 
         NSWidth(bounds), pageHeight); 
} 

//CUSTOM METHODS 

// Calculate the vertical size of the view that fits on a single page 
- (float)calculatePrintHeight { 

    extern NSPrintInfo *globalPrintInfo; 
    extern NSPrintOperation *globalPrintOperation; 

    // Obtain the print info object for the current operation 

    // Calculate the page height in points 
    NSSize paperSize = [globalPrintInfo paperSize]; 
    float pageHeight = paperSize.height - [globalPrintInfo topMargin] - [globalPrintInfo bottomMargin]; 

    // Convert height to the scaled view 
    float scale = [[[globalPrintInfo dictionary] objectForKey:NSPrintScalingFactor] 
        floatValue]; 

    NSLog(@"Calculated Print Height:%f",(pageHeight/scale)); 
    return (pageHeight/scale); 
} 

@end 

我能得到我想要的东西现在,当我去打印预览时,接受还是认为由于某种原因还有第二页?不知道为什么现在。我会上传我所看到的...

请注意它是如何表示1的2?第二页虽然只是空白。

enter image description here

回答

1

我不能完全肯定,但我已经回答了我的某种程度的问题。在我的代码(这是我从苹果印刷样本代码得到了大部分有提到以下

- (BOOL)knowsPageRange:(NSRangePointer)range { 
    NSRect bounds = [self bounds]; 
    float printHeight = [self calculatePrintHeight]; 

    range->location = 1; 
    range->length = NSHeight(bounds)/printHeight + 0; 

    NSLog(@"Calculated Page Range"); 
    return YES; 
} 

这是的子类的NSView的超越控制的方法之一,在苹果的代码,它说的部分printHeight + 1,所以我把它改为printHeight + 0,现在页面只说1中的1个。

我仍然有一个奇怪的问题,但它似乎仍然存在一些白色边框,我不确定那有什么用,如果有人能弄清楚是什么让我知道。在问题中张贴的图像中,它是相同的白色边框,正上方是1或1或2和右下方的位置,“这是一些文字!”

2

因此,我改进了我的印刷类,使其对许多页面更灵活,并希望共享代码。我仍然在底部有那个令人讨厌的白色边框,但我打印时似乎并不在那里?所以我需要一些帮助来解决这个问题,但除此之外,我设计了一个类,您只需将它发送给一个视图数组,然后它将按照您收到的顺序打印视图。

为此,我创建了2个类,PSPrint & PSPrintView。两者都是的NSView

这里的子类是用于PSPrint.h &代码PSPrint.m

#import <Foundation/Foundation.h> 
#import "PSPrintView.h" 

@interface PSPrint : NSView 
@property NSMutableArray *printViews; 
@property (strong) NSPrintOperation *printOperation; 
- (void)printTheViews; 
@end 

#import "PSPrint.h" 
#import "PSPrintView.h" 

@implementation PSPrint 

- (id)initWithFrame:(NSRect)frame 
{ 
    NSLog(@"Initializing Main PSPrintView"); 
    self = [super initWithFrame:frame]; 
    if (self) { 
     // Initialization code here. 
     _printViews = [[NSMutableArray alloc]initWithCapacity:1];//start it with capacity of 1 
    } 

    return self; 
} 

- (void)drawRect:(NSRect)dirtyRect{ 

} 

- (BOOL)knowsPageRange:(NSRangePointer)range { 
    NSRect bounds = [self bounds]; 
    float printHeight = [self calculatePrintHeight]; 

    range->location = 1; 
    range->length = NSHeight(bounds)/printHeight + 0; 

    NSLog(@"Calculated Page Range"); 
    return YES; 
} 

- (void)printTheViews{ 
    NSLog(@"Starting printTheViews Function of PSPrint"); 

    NSPrintInfo *sharedPrintInfo = [NSPrintInfo sharedPrintInfo]; 

    NSUInteger numOfViews = _printViews.count; 

    NSLog(@"Creating %ld SubViews",numOfViews); 

    NSUInteger totalHeight = 0;//if not initialized to 0 weird problems occur after '3' clicks to print, TODO: Find out why? Maybe because address space in memory not guaranteed to be 0 again? 
    NSUInteger heightOfView = 0; 
    PSPrintView *tempView; 

    for (NSUInteger i=0; i<numOfViews; i++) { 
     tempView = [_printViews objectAtIndex:i]; 
     heightOfView = tempView.frame.size.height; 
     totalHeight = totalHeight + heightOfView; 
    } 

    //Change the frame size to reflect the amount of pages. 
    NSSize newsize; 
    newsize.width = sharedPrintInfo.paperSize.width-sharedPrintInfo.leftMargin-sharedPrintInfo.rightMargin; 
    newsize.height = totalHeight; 
    [self setFrameSize:newsize]; 

    NSLog(@"Total Height Of Main Print View Is %f",_frame.size.height); 

    NSInteger incrementor=-1;//default the incrementor for the loop below. This controls what page a 'view' will appear on. 

    //Add the views in reverse, because the Y position is bottom not top. So Page 3 will have y coordinate of 0. Doing this so order views is placed in array reflects what is printed. 
    for (NSInteger i=numOfViews-1; i>=0; i--) { 
     incrementor++; 
     tempView = [_printViews objectAtIndex:i];//starts with the last item added to the array, in this case rectangles, and then does circle and square. 
     heightOfView = tempView.frame.size.height; 

     NSPoint origin; 
     origin.x = 0; 
     origin.y = heightOfView*incrementor;//So for the rectangle it's placed at position '0', or the very last page. 

     [tempView setFrameOrigin:origin]; 

     [self addSubview:tempView]; 
    } 


    _printOperation = [NSPrintOperation printOperationWithView:self printInfo:sharedPrintInfo]; 
    [_printOperation runOperation]; 
} 

// Return the drawing rectangle for a particular page number 
- (NSRect)rectForPage:(int)page { 
    NSRect bounds = [self bounds]; 
    float pageHeight = [self calculatePrintHeight]; 
    NSLog(@"Created Rect For View"); 
    return NSMakeRect(NSMinX(bounds), NSMaxY(bounds) - page * pageHeight, 
         NSWidth(bounds), pageHeight); 
} 

// Calculate the vertical size of the view that fits on a single page 
- (float)calculatePrintHeight { 

    NSPrintInfo *sharedPrintInfo = [NSPrintInfo sharedPrintInfo]; 

    // Obtain the print info object for the current operation 

    // Calculate the page height in points 
    NSSize paperSize = [sharedPrintInfo paperSize]; 
    float pageHeight = paperSize.height - [sharedPrintInfo topMargin] - [sharedPrintInfo bottomMargin]; 

    // Convert height to the scaled view 
    float scale = [[[sharedPrintInfo dictionary] objectForKey:NSPrintScalingFactor] 
        floatValue]; 

    NSLog(@"Calculated Print Height:%f",(pageHeight/scale)); 
    return (pageHeight/scale); 
} 

@end 

为PSPrintView.h代码& PSPrintView.m低于使用

#import <Cocoa/Cocoa.h> 

@interface PSPrintView : NSView 
enum optionsForView{drawRectangle,drawCircle,drawSquare}; 
@property enum optionsForView myOptions; 
- (void)drawSquare; 
- (void)drawCircle; 
- (void)drawRectangle; 
@end 


#import "PSPrintView.h" 

@implementation PSPrintView 

- (id)initWithFrame:(NSRect)frame 
{ 
    self = [super initWithFrame:frame]; 
    if (self) { 
     // Initialization code here. 
    } 

    return self; 
} 

- (void)drawRect:(NSRect)dirtyRect 
{ 
    NSLog(@"Drawing Green View Boundaries"); 
    NSPrintInfo *sharedPrintInfo = [NSPrintInfo sharedPrintInfo]; 

    //So we know the boundaries for the page. Remove in actual application. 
    [[NSColor greenColor] setFill]; 
    NSRectFill(dirtyRect); 

    NSString *drawType; 
    const char *cString; 

    if(sharedPrintInfo.orientation == NSPortraitOrientation){ 
     drawType = @"Portrait"; 
    }else{ 
     drawType = @"Landscape"; 
    } 

    cString = [drawType cStringUsingEncoding:NSASCIIStringEncoding]; 

    //Draw the print mode for reference. 
    CGContextRef myContext = [[NSGraphicsContext currentContext] graphicsPort]; 
    CGContextSelectFont(myContext, "Helvetica-Bold", 30, kCGEncodingMacRoman); 
    CGContextSetCharacterSpacing(myContext, 10); 
    CGContextSetTextDrawingMode(myContext, kCGTextFillStroke); 
    CGContextSetRGBFillColor(myContext, 0, 0, 0, 1);//black 
    CGContextSetRGBStrokeColor (myContext, 1, 1, 1, 1);//white stroke 
    CGContextShowTextAtPoint(myContext, 0, 0, cString, drawType.length); 

    //Control what type of page is drawn. 
    switch (_myOptions){ 
     case drawSquare: 
      [self drawSquare]; 
      break; 
     case drawCircle: 
      [self drawCircle]; 
      break; 
     case drawRectangle: 
      [self drawRectangle]; 
      break; 
    } 

} 

- (void)drawSquare{ 
    NSLog(@"Drawing Square"); 

    //Because this function can only be called from drawRect we are guaranteed with the function below to be in the correct graphics context 
    CGContextRef myContext = [[NSGraphicsContext currentContext] graphicsPort]; 

    NSRect redSquare = CGRectMake (0, 0, 200, 200); 
    redSquare.origin.y = self.bounds.size.height-redSquare.size.height;//move it to the top of the page. 

    CGContextSetRGBFillColor (myContext, 1, 0, 0, 1);//set to red color 
    CGContextFillRect (myContext,redSquare);//Y coordinate set to height to put it in upper left, 200 is total height of the view. 

} 

-(void)drawCircle{ 
    NSLog(@"Drawing Circle"); 

    //Because this function can only be called from drawRect we are guaranteed with the function below to be in the correct graphics context 
    CGContextRef myContext = [[NSGraphicsContext currentContext] graphicsPort]; 

    CGContextSetRGBFillColor (myContext, 1, 0, 1, 1);//set to red color 
    NSRect ovalFrame = CGRectMake (0, 0, 200, 200); 

    ovalFrame.origin.x=0;//from within the view it's self. 
    ovalFrame.origin.y=0;//at the top of the page. 

    CGContextFillEllipseInRect(myContext,ovalFrame); 
} 

-(void)drawRectangle{ 
    NSLog(@"Drawing Rectangle"); 

    //Because this function can only be called from drawRect we are guaranteed with the function below to be in the correct graphics context 
    CGContextRef myContext = [[NSGraphicsContext currentContext] graphicsPort]; 

    NSRect redRectangle = CGRectMake (0, 0, 300, 100); 
    redRectangle.origin.y = self.bounds.size.height-redRectangle.size.height-(self.bounds.size.height/2);//move it to the top of the page. 

    CGContextSetRGBFillColor (myContext, 1, 1, 0, 1);//set to red color 
    CGContextFillRect (myContext,redRectangle);//Y coordinate set to height to put it in upper left, 200 is total height of the view. 
} 

@end 

一个例子这些类在我的AppController中。我只是简单地创建了一个按钮,并在屏幕上有一个矩形,圆形和正方形的3个复选框。

这里是appController.h和appController.m

#import <Foundation/Foundation.h> 
#import "PSPrint.h" 
#import "PSPrintView.h" 

@interface AppController : NSObject 
- (IBAction)printResultsButton:(id)sender; 
@property (weak) IBOutlet NSButton *squareCheckBox; 
@property (weak) IBOutlet NSButton *circleCheckBox; 
@property (weak) IBOutlet NSButton *rectangleCheckBox; 
@property (strong) PSPrint *PSPrintObject; 
- (IBAction)pageSetup:(id)sender; 
@end 

#import "AppController.h" 
#import "PSPrint.h" 
#import "PSPrintView.h" 

@implementation AppController 

- (IBAction)printResultsButton:(id)sender { 
    NSLog(@"Print Button Pressed"); 

    //First get the shared print info object so we know page sizes. The shared print info object acts like a global variable. 
    NSPrintInfo *sharedPrintInfo = [NSPrintInfo sharedPrintInfo]; 

    //initialize it's base values. 
    sharedPrintInfo.leftMargin = 0; 
    sharedPrintInfo.rightMargin = 0; 
    sharedPrintInfo.topMargin = 0; 
    sharedPrintInfo.bottomMargin = 0; 

    PSPrintView *printPageView; 
    NSRect frame; 
    frame.size.height = sharedPrintInfo.paperSize.height-sharedPrintInfo.topMargin-sharedPrintInfo.bottomMargin; 
    frame.size.width = sharedPrintInfo.paperSize.width-sharedPrintInfo.leftMargin-sharedPrintInfo.rightMargin; 

    //Initiate the printObject without a frame, it's frame will be decided later. 
    _PSPrintObject = [[PSPrint alloc]init]; 

    //[_PSPrintObject.printViews initWithCapacity:1];//start it off with a capacity of '1' 
    if(_squareCheckBox.state == NSOnState){ 

     //Allocate a new instance of NSView into the variable printPageView 
     printPageView =[[PSPrintView alloc] initWithFrame:frame]; 

     //Set the option for the printView for what it should draw. 
     printPageView.myOptions=drawSquare; 

     //Finally append the view to the PSPrint Object. 
     [_PSPrintObject.printViews addObject:printPageView]; 

     NSLog(@"Added Square Print View To Mutable Array"); 
    } 

    if(_circleCheckBox.state == NSOnState){ 
     //Allocate a new instance of NSView into the variable printPageView 
     printPageView =[[PSPrintView alloc] initWithFrame:frame]; 

     //Set the option for the printView for what it should draw. 
     printPageView.myOptions=drawCircle; 

     //Finally append the view to the PSPrint Object. 
     [_PSPrintObject.printViews addObject:printPageView]; 

     NSLog(@"Added Circle Print View To Mutable Array"); 
    } 

    if(_rectangleCheckBox.state == NSOnState){ 
     //Allocate a new instance of NSView into the variable printPageView 
     printPageView =[[PSPrintView alloc] initWithFrame:frame]; 

     //Set the option for the printView for what it should draw. 
     printPageView.myOptions=drawRectangle; 

     //Finally append the view to the PSPrint Object. 
     [_PSPrintObject.printViews addObject:printPageView]; 

     NSLog(@"Added Rectangle Print View To Mutable Array"); 
    } 

    NSLog(@"Attempting to print all views..."); 
    [_PSPrintObject printTheViews];//print all the views, each view being a 'page'. 

} 

- (IBAction)pageSetup:(id)sender { 
    NSPageLayout *pageLayout = [NSPageLayout pageLayout]; 

    [pageLayout runModal];//runs the model for the page layout UI. It saves the global copy of printInfo in printOperation, which can be used to make decisions 

} 
@end 

我希望这有助于一些你们在你的挣扎与印刷,我花了一段时间来做到这一点,但这些类使打印轻松了许多。

0

白色条纹可能是纸张不可打印区域的一部分。经过多次实验后,我已经在页面上打印了视图,但我不仅要确保视图大小与[printinfo paperSize]给出的页面大小相匹配,还要将其进一步剪切到[printinfo imageablePageBounds。 (在我的子类的rectForPage:方法中。)

如果您提供比imageablePageBounds更小的任何内容,则会在页面上留出空间,任何更大的内容都可能会被剪切或分页。

这是imageablePageBounds和纸张大小的区别的空间出现在打印对话框中的预览空白,并留在页面上未打印(这显然页面的打印区域,根据您选择的打印机/纸)

1

要处理这种固定印刷,我更喜欢整体页面模式: 请使用NSFitPagination而不是NSAutoPagination。

[myPrintInfo setHorizontalPagination:NSFitPagination]; 
[myPrintInfo setVerticalPagination:NSFitPagination]; 

希望它适合你!