gpt4 book ai didi

objective-c - Cocoa (Mac Os X) 打印多页,为什么预览窗口显示 2 页而不是 1 页?

转载 作者:太空狗 更新时间:2023-10-30 03:52:40 26 4
gpt4 key购买 nike

我有一个正在开发的 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];
}

我让打印窗口出现,我看到了我的 View 的“绿色背景”,但由于某种原因它被分成了 2 页。当我将框架的宽度和高度设置为 pagesize.width & height 时,我不确定到底发生了什么,感谢您的帮助。下面是我看到的一些图片。

我的猜测是页面大小宽度和高度的单位与用于定义 View 框架的像素单位类型不同。

我的最终目标是制作一个程序,用户可以在其中选择他们想要的内容,并根据他们选择的选项打印特定页面,但首先我必须弄清楚如何将我期望的“内容”添加到 '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 of 2 的吗?不过,第二页只是空白。

enter image description here

最佳答案

所以我改进了我的打印类,使其对许多页面更加灵活,并希望共享代码。我在底部仍然有那个烦人的白色边框,我不太明白,但是当我去打印时它似乎不在那里?所以我需要一些帮助来解决这个问题,但除此之外,我设计了一个类,您只需向它发送一组 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)使打印变得更加容易。

关于objective-c - Cocoa (Mac Os X) 打印多页,为什么预览窗口显示 2 页而不是 1 页?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13999971/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com