わかりました、基本的に私は一連のわずかに重なり合うサブビューを持つビューを持っています。サブビューがクリックされると、非常に単純な2つのライナーによって、(とりわけ)一番上に移動します。
-(void)mouseDown:(NSEvent *)theEvent {
if (_selected) { // Don't do anything this subview is already in the foreground
return;
}
NSView *superview = [self superview];
[self removeFromSuperview];
[superview addSubview:self positioned:NSWindowAbove relativeTo:nil];
}
これは正常に機能し、これを行うための「通常の」方法のようです。
問題は、ビューにドラッグロジックを導入しているため、に応答する必要があること-mouseDragged:
です。残念ながら、ビューはビュー階層から削除され、プロセスで再度追加されるため、ビューを前面に表示して同じマウスアクションでドラッグすることはできません。受信しますが、受信したり、後続のイベントmouseDown:
を受信したりすることはありません。mouseDragged:
2回目のクリックではビュー階層のジャグリングが行われないため、マウスを離してビューをもう一度クリックした場合にのみドラッグされます。
ビューをこのように前景に移動し、後続-mouseDragged:
の-mouseUp:
イベントと後続のイベントを引き続き受信できるようにするためにできることはありますか?
私は、実際にイベントを受信する前に-hitTest:
ビューを前面に表示するために、スーパービューでオーバーライドし、mouseDownイベントをインターセプトするという考え方に沿って始めました。ここでの問題は、内部から、実際にヒットテストを実行しているイベントのタイプをどのように区別するかです。mouseMovedなどの他のマウスイベントのためにサブビューをフォアグラウンドに移動したくありません。-hitTest:
更新| 私のスーパービューでは、実際にこれを実行しましたが、-hitTest:
直接からイベントをトリガーする非常に悪いコードの臭いのように感じます。
-(NSView *)hitTest:(NSPoint)aPoint {
NSView *view = [super hitTest:aPoint];
if ([view isKindOfClass:[EDTabView class]] && ![(EDTabView *)view isActive]) {
// Effectively simulate two mouseDown events in sequence for this special case
[view mouseDown:nil]; // Works because I know too much about the implementation
}
return view;
}
これには2つの問題があります。最大の問題は、戻る前にアクションを実行し、完了-hitTest:
後にAppKitによって処理されたとおりに実行していることです。-hitTest:
2つ目は、合格するイベントがないため、nilを合格することです。イベントハンドラーが実際にはイベントデータを処理しないことがわかっているので、この場合は機能しますが、それは素晴らしいことではありません。別の方法は、ロジック全体をスーパービューに移動することでしたが、ここでの関心の分離はさらに悪化しているように感じます。
更新| この-hitTest:
ハックは壊れています...ビューの上部に何かをドラッグしているときなど、マウスをクリックしていないときにトリガーされます。まだこの問題の良い解決策を探しています。
答えは、ドラッグ操作中にビューがスーパービューを離れて再び入る方法を文字通り示すか、(おそらくよりエレガントに)ビューを前景に移動する別の方法です[view removeFromSuperview]; [superview addSubview:view ...];
。