5

iTunes ミニプレーヤー (一例を挙げると) は、再生/一時停止および音量コントロールが使用されているときにアプリケーションが前面に表示されないクリックスルーをサポートしています。

これはどのように行われますか?

私はAppleのドキュメントを調べてきましたが、Cocoa Event-Handling GuideのEvent Dispatchに次のように記載されています。

一部のイベントは、その多くがアプリケーション キット (タイプ NSAppKitDefined) によって定義されており、ウィンドウまたはアプリケーション オブジェクト自体によって制御されるアクションと関係があります。これらのイベントの例としては、アプリケーションのアクティブ化、非アクティブ化、非表示、および表示に関連するイベントがあります。NSApp は、ディスパッチ ルーチンの早い段階でこれらのイベントを除外し、それ自体を処理します。

したがって、私の限られた理解 ( How an Event Enters a Cocoa, Application ) から、NSApplication をサブクラス化し、オーバーライド - (void)sendEvent:(NSEvent *)theEventすると、すべてのマウスとキーボードのイベントをトラップする必要がありますが、それでもクリックするとウィンドウが表示されます。したがって、イベントが NSApplication によって表示される前にウィンドウが発生するか、何か他のものが不足しています。

Matt Gallagher のDemystifying NSApplication を再作成して調べましたが、残念ながら Matt はイベント キューをカバーしていませんでした。

どんな助けでも感謝します、ありがとう。

編集して追加: Loyd's Loungeで同じ問題について話している投稿を見つけ、CocoaBuilder の投稿にリンクし、最初の右マウス ダウンをキャプチャします。[theEvent type] の NSLog をいじって再アクティブ化した後、マウスの左ボタンのアクティビティがキャッチされています。

ここで、ウィンドウを左クリックして前面に出すと、一連のイベント タイプが生成13, 1, 13されます。これらは、NSAppKitDefined、NSLeftMouseDown、および NSAppKitDefined です。これらを除外したり、どこに行くのかを見つけたりすることはできますか?

4

4 に答える 4

3

これはNSPanel、非アクティブ化時に非表示にならず、必要な場合にのみキーになるように設定されているを使用して実現できます。これは、使用するコントロールが;に戻るYESことも前提としています。■デフォルトでそうします。-acceptsFirstMouse:NSButton

パネルのIBを介して非アクティブ化の非アクティブ化フラグをオフにすることができますが-setBecomesKeyOnlyIfNeeded:YES、ボタンのクリックでパネルとアプリが前面に出ないようにするには、パネルにメッセージを発行する必要があります。

于 2009-09-30T20:30:29.423 に答える
2

アプリがアクティブなときの動作を変更せずに、NSButtonをクリックスルーイベントに応答させることができます。

インターフェイス(ClickThroughButton.h):

#import <AppKit/AppKit.h>

@interface ClickThroughButton : NSButton

@end

実装(ClickThroughButton.m):

#import "ClickThroughButton.h"

@implementation ClickThroughButton

- (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent *)theEvent {
    return ![NSApp isActive];    
}

- (void)mouseDown:(NSEvent *)theEvent {    
    if (![NSApp isActive]) {
        [NSApp preventWindowOrdering];        

        [self highlight:YES];

        NSEvent *mouseUpEvent = [[self window] nextEventMatchingMask:NSLeftMouseUpMask
                                                  untilDate:[NSDate distantFuture]
                                                     inMode:NSEventTrackingRunLoopMode
                                                    dequeue:YES];
        NSPoint mouseLocation = [self convertPoint:[mouseUpEvent locationInWindow] fromView:nil];
        BOOL mouseUpInside = [self mouse:mouseLocation inRect:[self bounds]];

        if (mouseUpInside) {
            if ([self target])
                [[self target] performSelector:[self action] withObject:self]; 
        }

        [self highlight:NO];            

    } else {
        [super mouseDown:theEvent];        
    }
}

@end
于 2011-11-16T18:04:19.687 に答える
2

これは私が探していた答えではありませんが、今のところ十分に機能しています。次のメソッドをサブクラス化NSViewして実装することにより、そのビューをボタンとして機能させることができます。

- (void)mouseDown:(NSEvent *)theEvent {
    [NSApp preventWindowOrdering];
//  [self setNeedsDisplay:YES];
}

- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent {
    return YES;
}

- (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent *)theEvent {
    return YES;
}

他に何も必要ありません、それだけです。もちろん、これは私が維持したかったすべての NSButton の利点をバイパスします。ボタンの状態を設計してから、描画と更新を行う必要がありますが、答えが得られてうれしいです。

于 2009-10-23T14:20:39.867 に答える
1

チェックアウトしましたacceptsFirstMouse:か?ウィンドウを前面に表示するのではなく、ビューがイベントを処理する必要があることを示すために、このイベントにNSView戻ることができます。YESおそらく、イベントを傍受することによって、ウィンドウを前面に表示するために使用されることはありませんが、それを保証することはできません。

この動作をオーバーライドしたいコントロールをサブクラス化する必要があることは明らかですacceptsFirstMouse:

于 2009-09-30T19:17:11.433 に答える