別の NSControl の下にある NSControl がイベントを処理しない場合にイベントを送信する
-
20-09-2019 - |
質問
特定の条件下でマウスのクリックを処理できる複数の重ね合わせたコントロールがあります。私ができるようにしたいのは次のとおりです。
- 上部のコントロールは、
mouseDown:
イベント。 - 上部のコントロールは、
mouseDown:
イベント。 - 存在する場合は、何らかの処理を行い、他のコントロールがそのメッセージを受信しないようにします。
mouseDown:
イベント。 - そうでない場合は、その下にあるコントロールにイベントを送信します。
- このコントロールは、イベントを処理するかどうかを決定します。
- 等
本質的に、私はイベントをコントロールに送信しようとしています。 「Zオーダー」 はトップ コントロールのすぐ下にあり、トップ コントロールは他のコントロールについて知る必要も、インスタンス化時に特別な設定も必要ありません。
最初に思いついたのは、イベントを次の宛先に送信することでした。 [topControl nextResponder]
しかしどうやら nextResponder
なぜなら、ウィンドウ上のすべてのコントロールはウィンドウそのものであり、以前考えていたように、Z オーダーに基づくコントロールのチェーンではありません。
次のレスポンダーを手動で設定せずにこれを行う方法はありますか?目標は、他のコントロールから独立し、ウィンドウにドロップするだけで期待どおりに動作するコントロールを取得することです。
前もって感謝します!
解決
アプリケーションが何を行うかわからないため、最適なアプローチを正確に知ることは困難ですが、考えられるのは次のとおりです。ビュー階層を介してメッセージを上に渡したいようですね...どうにか。
いずれにせよ、ビューは次の 2 つのいずれかを実行します。
- メッセージを処理する
- それを「次のビュー」に渡します (「次のビュー」を定義する方法はアプリケーションによって異なります)
それで。これはどうやってやりますか?ビューのデフォルトの動作では、メッセージを次のビューに渡す必要があります。この種のことを実装する良い方法は、非公式のプロトコルを使用することです。
@interface NSView (MessagePassing)
- (void)handleMouseDown:(NSEvent *)event;
- (NSView *)nextViewForEvent:(NSEvent *)event;
@end
@implementation NSView (MessagePassing)
- (void)handleMouseDown:(NSEvent *)event {
[[self nextView] handleMouseDown:event];
}
- (NSView *)nextViewForEvent:(NSEvent *)event {
// Implementation dependent, but here's a simple one:
return [self superview];
}
@end
この動作を行う必要があるビューでは、次のようにします。
- (void)mouseDown:(NSEvent *)event {
[self handleMouseDown:event];
}
- (void)handleMouseDown:(NSEvent *)event {
if (/* Do I not want to handle this event? */) {
// Let superclass decide what to do.
// If no superclass handles the event, it will be punted to the next view
[super handleMouseDown:event];
return;
}
// Handle the event
}
おそらく、 NSView
オーバーライドするサブクラス mouseDown:
これに基づいて他のカスタム ビュー クラスを作成します。
実際の Z オーダーに基づいて「次のビュー」を決定したい場合は、Z オーダーがビュー内の順序によって決定されることに留意してください。 subviews
コレクション。後のビューが最初に表示されます。したがって、次のようなことができます。
- (void)nextViewForEvent:(NSEvent *)event {
NSPoint pointInSuperview = [[self superview] convertPoint:[event locationInWindow] fromView:nil];
NSInteger locationInSubviews = [[[self superview] subviews] indexOfObject:self];
for (NSInteger index = locationInSubviews - 1; index >= 0; index--) {
NSView *subview = [[[self superview] subviews] objectAtIndex:index];
if (NSPointInRect(pointInSuperview, [subview frame]))
return subview;
}
return [self superview];
}
これはあなたが望んでいた以上のものかもしれませんが、お役に立てば幸いです。
他のヒント
あなたがしなければならないのは、コール[super mouseDown:event]
です。マックOS X 10.5(このやったの のではないが、以前と同じように動作します)ので、NSViewのは、重複ビューを処理する方法を知っていて、あなたのためのイベント処理の世話をします。
あなたが10.5より前のリリースをターゲットにする必要がある場合は、次のこれは本当に悪いアイデアのです。イベント処理メカニズムは、重複サブビューに対処する方法を知っていない、どちらも描画システムを行い、あなたには、いくつかの非常に奇妙なアーティファクトを見ることができていないだけでなく。それはあなたが決定している場合、言った:
カスタムコントロール/ビューで上書き-[NSView hitTest:]
。 AppKitのにマウスイベントを配信するために階層で表示するかを決定するために、この方法を使用します。カスタムビューにnil
その点を返した場合は無視され、イベントは、その点をカバーする次のビューに配信を取得する必要があります。
のマインドは、しかし、これは、私が上記で概説した理由をまだ悪い考えです。それはちょうど正式に一度のAppKitでサポートされてものではありませんでした。の10.4およびそれ以前の、より一般的に受け入れられている回避策は、子ウィンドウを使用することです。