0

特定の条件下でマウスクリックを処理できる複数の重ね合わせたコントロールがあります。私がしたいことは次のとおりです。

  1. トップコントロールがイベントを受信し mouseDown:ます。
  2. トップコントロールは、mouseDown:イベントを処理するかどうかを決定します。
  3. もしそうなら、何かをして、他のコントロールがmouseDown:イベントを受け取らないようにしてください。
  4. そうでない場合は、下にあるコントロールにイベントを送信します。
  5. このコントロールは、イベントを処理するかどうかを決定します。

本質的に、私は「Zオーダー」がトップコントロールのすぐ下にあるコントロールにイベントを送信しようとしています。トップコントロールは他のコントロールについて知る必要がなく、インスタンス化時に特別な設定も必要ありません。

[topControl nextResponder]最初に頭に浮かんだのは、イベントをに送信することでしたがnextResponder、ウィンドウ上のすべてのコントロールはウィンドウ自体であり、以前考えていたZオーダーに基づくコントロールのチェーンではないようです。

次のレスポンダーを手動で設定せずにこれを行う方法はありますか?目標は、他のコントロールから独立していて、ウィンドウにドロップするだけで期待どおりに機能するコントロールを取得することです。

前もって感謝します!

4

2 に答える 2

2

あなたがしなければならないのは電話することだけです[super mouseDown:event]。Mac OS X 10.5以降(これは以前と同じようには機能しませんでした)、NSViewは重複するビューを処理する方法を知っており、イベント処理を自動的に処理します。


10.5より前のリリースをターゲットにする必要がある場合:これは本当に悪い考えです。イベント処理メカニズムは、重複するサブビューを処理する方法を知らないだけでなく、描画システムも知らず、いくつかの非常に奇妙なアーティファクトを見ることができます。そうは言っても、あなたが決心しているなら:

-[NSView hitTest:]カスタムコントロール/ビューでオーバーライドします。AppKitはこのメソッドを使用して、マウスイベントを配信する階層内のビューを決定します。カスタムビューでそのポイントを返すnilと無視され、イベントはそのポイントをカバーする次のビューに配信されます。

ただし、上記で概説した理由により、これはまだ悪い考えです。当時、AppKitによって正式にサポートされていたものではありませんでした。10.4以前でより一般的に受け入れられている回避策は、子ウィンドウを使用することです。

于 2009-10-08T22:40:51.483 に答える
1

あなたのアプリケーションが何をするかわからないので、最適なアプローチを正確に知ることは困難ですが、ここに考えがあります。ビュー階層を介してメッセージを渡したいようです...どういうわけか。

とにかく、ビューは次の 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];
}

これはあなたが望んでいたよりもはるかに多いかもしれませんが、それが役に立てば幸いです.

于 2009-10-08T20:34:10.917 に答える