- 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];
}
...
|
|