我有一个正在使用的 cocoa 应用程序,在其中创建了要发送到打印机的customView。在子类NSView中,我还设置了一些框架选项,代码如下。我有2个全局变量来保存在main()函数外部声明的打印信息。
- (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];
}
我出现打印窗口,并看到我的“绿色背景”,但由于某种原因,它分成了两页。我不确定到底是怎么回事,因为我将框架的宽度和高度设置为pagesize.width和height,任何帮助都是值得的。下面是一些我所看到的图像。
我的猜测是,页面大小的宽度和高度与用于定义 View 框架的像素单位类型的单位不同。
我的最终目标是制作一个程序,让用户选择所需的内容,并根据所选的选项打印特定的页面,但是首先我必须弄清楚如何甚至将我期望的“内容”显示在“1”页面上'2'。我可以通过实验手动确定宽度和高度,但是对于我假设的不同纸张尺寸来说,这并不是很动态。
提前致谢。
编辑 ***
我刚刚将代码编辑为以下子类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
我现在可以得到我想要的东西,当我接受打印预览时仍然接受,出于某种原因,它仍然认为还有第二页?现在不知道为什么。我将上传我所看到的...
请注意,它怎么说2之1?第二页只是空白。
最佳答案
因此,我对打印课进行了一些改进,使其在许多页面上都变得更加灵活,并希望共享代码。我在底部仍然有一个烦人的白色边框,无法完全弄清楚,但是在我打印时似乎没有?因此,我将需要一些帮助来解决这个问题,但是,否则,我设计了一个类,您只需向其发送一个 View 数组即可,它将按接收到的顺序打印 View 。
为此,我创建了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
我希望这可以帮助一些在打印方面遇到困难的人,花了我一些时间来做到这一点,但是这些类(class)使打印变得容易得多。