5

私は、プリンターに送信したい customView を作成した作業中のココア アプリを持っています。サブクラス化された NSView では、いくつかのフレーム オプションも設定しました。コードは以下のとおりです。main() 関数の外で宣言された印刷情報を保持するための 2 つのグローバル変数があります。

- (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.width & height に設定しているため、何が起こっているのか正確にはわかりません。私が見るもののいくつかの画像は以下の通りです。

私の推測では、ページサイズの幅と高さは、ビューのフレームを定義するために使用されるピクセル単位の種類とは異なる単位です。

私の最終的な目標は、ユーザーが必要なものを選択し、選択したオプションに基づいて特定のページを印刷するプログラムを作成することですが、最初に、期待する「コンテンツ」を代わりに「1」ページに取得する方法を理解する必要がありました「2」の。実験によって幅と高さを手動で把握することはできましたが、想定しているさまざまな用紙サイズに対してはそれほど動的ではありません。

前もって感謝します。

画像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/2 と表示されていることに注意してください。2ページ目は真っ白だけど。

ここに画像の説明を入力

4

4 に答える 4

2

そこで、印刷クラスを少し改善して、多くのページでより柔軟に対応できるようにし、コードを共有したいと考えました。一番下の白い境界線がまだわかりませんが、印刷しようとするとそこに表示されませんか? したがって、それを理解するには助けが必要ですが、それ以外の場合は、ビューの配列を送信するだけで、受信した順序でビューを出力するクラスを設計しました。

これを行うために、PSPrint と PSPrintView という 2 つのクラスを作成しました。どちらも 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

私はこれを行うのにしばらく時間がかかりましたが、これらのクラスは印刷をはるかに簡単にします.

于 2012-12-28T18:42:03.187 に答える
1

完全にはわかりませんが、私の質問にはある程度答えました。私のコード (ほとんどの場合、Apple 印刷のサンプル コードから取得したもの) には、次のようなセクションがありました。

- (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 のオーバーライド メソッドの 1 つで、Apple コードでは printHeight + 1 と表示されていたので、printHeight + 0 に変更すると、ページは 1 of 1 としか表示されなくなりました。

まだ奇妙な問題がありますが、その下にまだ白い境界線が残っているようで、それが何のためにあるのかわかりません。誰かがそれが何であるかを理解できる場合は、私に知らせてください. 質問に投稿された画像と同じ白い境界線で、1 の 1 または 1 の 2 と書かれている場所の真上と、「ここにテキストがあります!」の真下にあります。

于 2012-12-24T22:03:29.450 に答える
0

白い帯は、用紙の印刷できない領域の一部である可能性があります。多くの実験の後、私は望むようにページにビューを印刷しましたが、ビューのサイズが[printinfo paperSize]で指定されたページサイズと一致することを確認するだけでなく、[printinfoで指定された長方形にさらにクリップする必要がありましたimageablePageBounds]。(私のサブクラスの rectForPage: メソッド内。)

imageablePageBounds よりも小さいものを指定すると、ページにスペースが残ります。それよりも大きいものは、切り取られたり、改ページされたりする可能性があります。

imageablePageBounds と paperSize の差であるスペースは、印刷ダイアログのプレビューに空白として表示され、ページに印刷されないままになります (選択したプリンター/用紙によると、明らかにページの印刷不可能な領域です)。

于 2015-02-19T11:53:31.443 に答える