整理してみた。
(1) mouseDragged:
dragImage:実行後にブロック
(2) ドラッグ中に呼び出される
draggedImage:beganAt:
draggingSourceOperationMaskForLocal: 1 同じview
draggingSourceOperationMaskForLocal: 0 他のview
draggingEntered:
draggingUpdated:
:
:
prepareForDragOperation:
performDragOperation:
concludeDragOperation:
draggedImage:endedAt:operation:
(3) dragImage: のブロックが解かれ mouseDragged: 内の処理を続行
2007年10月12日金曜日
ドラッグの流れ(まとめ)
2007年9月10日月曜日
dragImage: で呼び出されるメソッド
NSView#dragImage: ... を使いドラッグしている時に呼び出されるメソッドを整理してみる。
(1) ドラッグ実行
- (void)dragImage:(NSImage *)anImage at:(NSPoint)viewLocation offset:(NSSize)initialOffset event:(NSEvent *)event pasteboard:(NSPasteboard *)pboard source:(id)sourceObj slideBack:(BOOL)slideFlag;
呼び出し後、ブロック。ドラッグが終わるまでこの直後のコードは実行されない。
(2) ドラッグ開始
ドラッグ実行直後にドラッグ対象のViewに対して下記のメソッドが呼び出される。
- (void)draggedImage:(NSImage *)image beganAt:(NSPoint)screenPoint
ドラッグ対象の画像と開始位置が取得できる。
(3) ドラッグ中
ドラッグ先が変わるたびに呼び出される。同一 NSViewの場合は最初の一回のみ。それ以外はドラッグ移動中頻繁に呼び出される。
- (unsigned int)draggingSourceOperationMaskForLocal:(BOOL)flag
(4) ドラッグ終了
ドラッグ終了時にドラッグ対象のViewに対して下記のメソッドが呼び出される。
- (void)draggedImage:(NSImage *)image endedAt:(NSPoint)screenPoint operation:(NSDragOperation)operation
画像と終了位置、それに加えてどのようなオペレーション(コピー、移動など)が行われたかが取得できる。
ここには移動がおこわなれた場合のドラッグ元データの削除などを書くと良さそう。
(5) その他
以前説明したように、同じNSViewにインフォーマルプロトコルの NSDraggingDestination が実装されていると、それらのメソッドが通常通り呼び出される。
なお下記は呼び出されなかった。
- (void)mouseUp:(NSEvent *)theEvent
2007年8月31日金曜日
NSView#dragImage:... を使う
NSView の
- (void)dragImage:(NSImage *)anImage at:(NSPoint)viewLocation offset:(NSSize)initialOffset event:(NSEvent *)event pasteboard:(NSPasteboard *)pboard source:(id)sourceObj slideBack:(BOOL)slideFlag;
を使って、アプリ内外のドラッグ&ドロップを統一的に処理する方法を調査中。
あるカスタムビュー(仮に View1とする)で上記メソッドを実行すると処理はそこでブロックされる。例えば:
[self dragImage:drag_img at:p offset:NSZeroSize
event:event pasteboard:pb source:self slideBack:NO]; --> 終了までブロック
NSLog(@"end");
を実行すると、ドラッグ&ドロップが終わるまで "end"がログに出力されない。
このドラック&ドロップ中のイベントを拾う必要があるのだが NSDraggingDestination(非形式プロトコル)を実装してやるとあっさり取ることができた。NSDraggingDestinationの主要メソッドは6つある。
– draggingEntered:
– draggingUpdated:
– draggingExited:
– prepareForDragOperation:
– performDragOperation:
– concludeDragOperation:
ところでここで疑問が生じてくる。dragImage:.. は処理が終わるまでブロックされているのだから NSDraggingDestination のメソッド群は別スレッドから呼ばれるのか?そうなると排他制御が必要になるな、と。
そこで dragImage:... と draggingEntered: の両方で下記のコードを入れて様子を見てみると:
NSLog(@" %@, %@", self, [NSThread currentThread]);
結果はどちらも同じだった。
2007-08-31 12:34:04.439 DragSample[5671]
1 :
)}
)}
}
つまり dragImage:... と同じスレッドから draggingEntered: が呼び出されていることになる。
とりあえずは一歩前進。
2007年8月30日木曜日
draggingSourceOperationMaskForLocal:
NSView#dragImage:(NSImage *)anImage at:(NSPoint)viewLocation offset:(NSSize)initialOffset event:(NSEvent *)event pasteboard:(NSPasteboard *)pboard source:(id)sourceObj slideBack:(BOOL)slideFlag
を使って同一ウィンドウと他アプリ両方をサポートする D&Dを検証中。
その課程で分かったことをメモ。
下記メソッドを実装しておくと、ドラッグ中に呼び出される。
NSObject(NSDraggingSource)#draggingSourceOperationMaskForLocal:
このメソッドで渡ってくる (BOOL)flag はローカルかどうか(?)を表すのではなく、NSObject(NSDraggingDestination)のメソッドが実装されているかどうかによって YES/NOが返されることが分かった。これらのメソッドが実装されている、すなわちD&Dを受け付ける場合は flag==YES、となり実装していない場合は flag==NO が返る。
2007年8月24日金曜日
ドラッグ、ドラッグ
Safariや他のアプリでやっているように画像をドラッグした時に:
ドラッグ画像を半透明する
アプリ上のオブジェクトをドラッグ&ドロップして他のアプリケーションへ持っていく場合には NSView の dragImage:at:offset:event:pasteboard:source:slideBack: を使えば容易に実装できる。このメソッドへ NSImage を渡せばドラッグ中のイメージとして表示することができる。
ここまでは簡単にできたのだが、できれば Safari などが実現しているようにドラッグ中のイメージを半透明にしたい。ところが該当するような APIが見つからない。簡単にはできないのかとあきらめた矢先、NSImage に対して lock を送ると絵が描けることに気がついた。それなら画像の NSImageとは別にもう一つ NSImageを作りここへ dissolveToPoint:fraction: を使って半透明で描画してあげれば行けるのでは?
// 画像をファイルから読み込む
NSImage* image1 = [[NSImage alloc] initWithContentsOfFile:@"hello.png"];
// 表示用の画像を別途用意。サイズは image1に合わせておく
NSImage* image2 = [[NSImage alloc] initWithSize:[image1 size]];
// image1の画像を image2へ半透明で描画する
[image2 lockFocus];
[image1 dissolveToPoint:NSZeroPoint fraction:0.5];
[image2 unlockFocus];
やってみると簡単にできた。dissolveToPoint:fraction: などの描画メソッドは NSView に対して使うものと思いこんでいたためにこんな簡単なことに気がつかなかった。この方法を使えば拡大・縮小・回転、他の画像との合成などなんでもできる。シンプルながらよくできた仕組みだね。