home link download back number special issue

HMDT - Special Issue / Sketch BP / Sketch に見る印刷


- Case Study -

Sketch に見る印刷

プリントの仕方

Cocoa を使って印刷するには、まず NSView と NSPrintInfo を用意する。NSView は印刷するための view で、NSPrintInfo は印刷するための諸情報が詰まっている。そいつらを使って NSPrintOperation のインスタンスを作って、NSPrintOperation のrunOperation を呼べばいいんだ。

AppKit/NSPrintOperation.h
+ (NSPrintOperation *)printOperationWithView:(NSView *)aView 
                printInfo:(NSPrintInfo *)aPrintInfo;

- (BOOL)runOperation;
- (void)runOperationModalForWindow:(NSWindow *)docWindow 
                delegate:(id)delegate 
                didRunSelector:(SEL)didRunSelector 
                contextInfo:(void *)contextInfo;

runOperation は 2 種類。モーダルになるやつが後者だ。


Sketch に見る印刷

では、Sketch の印刷の様子を調べてみよう。中心となるのは、もちろん NSDocument のサブクラスである SKTDrawDocument。


SKTDrwaDocument の printShowingPrintPanel:

NSDocument のサブクラスで印刷を行うときは、printShowingPrintPanel: メソッドをオーバーライドするんだ。

AppKit/NSDocument.h
- (void)printShowingPrintPanel:(BOOL)flag;

ドキュメントベースアプリケーションを作ると、「ファイル」メニューの「プリント...」コマンドは、FirstResponder の printDocument: に結び付けられているんだ(つまり nil ターゲットメッセージ)。NSDocument が、このメッセージを受けるんだ。そして printDocument: メソッドの中で、

[self printShowingPrintPanel:YES]

を呼ぶんだ。

で、Sketch の printShowingPrintPanel: はどーかっていうと、こんな感じ。

Sketch/DocumentModesl.subprj/SKTDrawDocument.m
- (void)printShowingPrintPanel:(BOOL)flag {
    NSSize paperSize = [self documentSize];
    SKTRenderingView *view = 
        [[SKTRenderingView allocWithZone:[self zone]] 
            initWithFrame:NSMakeRect(
                    0.0, 0.0, paperSize.width, paperSize.height) 
            graphics:[self graphics]];
    NSWindow *window = 
        [[NSWindow allocWithZone:[self zone]] 
            initWithContentRect:NSMakeRect(
                    0.0, 0.0, paperSize.width, paperSize.height) 
            styleMask:NSBorderlessWindowMask 
            backing:NSBackingStoreNonretained 
            defer:NO];
    NSPrintInfo *printInfo = [self printInfo];
    NSPrintOperation *printOp;
    NSWindow *docWindow = [self appropriateWindowForDocModalOperations];

    [[window contentView] addSubview:view];
    [view release];
    printOp = [NSPrintOperation 
        printOperationWithView:view printInfo:printInfo];
    [printOp setShowPanels:flag];
    [printOp setCanSpawnSeparateThread:YES];

    if (docWindow) {
        (void)[printOp runOperationModalForWindow:docWindow 
                                delegate:nil 
                                didRunSelector:NULL 
                                contextInfo:NULL];
    } else {
        (void)[printOp runOperation];
    }
    
    [window release];
}

印刷の流れは、

  • view (SKTRenderingView) を作る
  • NSPrintInfo を取得する
  • NSPrintOperation を作る
  • runOperation を呼ぶ

って感じね。

- view (SKTRenderingView) を作る

まず、印刷する内容を表示する view を作るんだ。ここでは SKTRenderingView だよ。

Sketch/DocumentModesl.subprj/SKTDrawDocument.m
    NSSize paperSize = [self documentSize];
    SKTRenderingView *view = 
        [[SKTRenderingView allocWithZone:[self zone]] 
            initWithFrame:NSMakeRect(
                    0.0, 0.0, paperSize.width, paperSize.height) 
            graphics:[self graphics]];
    NSWindow *window = 
        [[NSWindow allocWithZone:[self zone]] 
            initWithContentRect:NSMakeRect(
                    0.0, 0.0, paperSize.width, paperSize.height) 
            styleMask:NSBorderlessWindowMask 
            backing:NSBackingStoreNonretained 
            defer:NO];

    ...

    [[window contentView] addSubview:view];
    [view release];

    ...
    
    [window release];
}

まず、documentSize を呼んで、ドキュメントのサイズを取得する。そしたら、alloc/init を使って、いきなり SKTRenderingView を作るんだ。大きさはドキュメントのサイズ、今持ってる SKTGraphic で初期化してやる。

その後、NSWindow も作って、その subview に SKTRenderingView を加えているんだ。おそらく、印刷するときに、view の super view が設定されていなと、不都合が起きるのか?作った後は、release を忘れないように。

- NSPrintInfo を取得する

印刷するときの設定を保存しておく NSPrintInfo。デフォルトのものを使ってもいいけど、Sketch ではカスタムのものを使っている。

Sketch/DocumentModesl.subprj/SKTDrawDocument.m
    ...

    NSPrintInfo *printInfo = [self printInfo];

    ...

NSDocument の printInfo メソッドを使って取り出してるんだ。

- NSPrintOperation を作る

続いて NSPrintOperation を作る。

Sketch/DocumentModesl.subprj/SKTDrawDocument.m
    ...

    NSPrintOperation *printOp;

    ...

    printOp = [NSPrintOperation 
        printOperationWithView:view printInfo:printInfo];
    [printOp setShowPanels:flag];
    [printOp setCanSpawnSeparateThread:YES];

    ...

こいつは NSView と NSPrintInfo を使って作られるんだ。あと、いくつかの設定をしておくんだ。

- runOperation を呼ぶ

で、いよいよ runOperation を呼ぶ。runOperation には 2 種類ある。モーダルの方には NSWindow を指定しないといけない。NSWindow は appropriateWindowForDocModalOperations で、適当な NSWindow を取得しているらしい。

Sketch/DocumentModesl.subprj/SKTDrawDocument.m
    ...

    NSWindow *docWindow = [self appropriateWindowForDocModalOperations];

    ...

    if (docWindow) {
        (void)[printOp runOperationModalForWindow:docWindow 
                                delegate:nil 
                                didRunSelector:NULL 
                                contextInfo:NULL];
    } else {
        (void)[printOp runOperation];
    }

    ...

戻り値は無視してるね。これで、印刷が始まるよ。


Home | Link | Download | Back Number | Speciall Issue

Sketch BP

mailto: mkino@xd5.so-net.ne.jp

HMDT