5

マウスの右ボタンのクリックで機能させたい NSButton サブクラスがあります。通常のクリックと同じ種類の動作が必要なため、オーバーロードするだけ-rightMouseDown:ではうまくいきません (たとえば、ボタンが押された場合、ユーザーはボタンを離すことでキャンセルでき、マウスが離されたときにアクションが送信されます)。 )。

私がこれまでに試したことは、 をオーバーロード-rightMouse{Down,Up,Dragged}し、マウスの左ボタンのクリックを示すようにイベントを変更してから に送信すること-mouse{Down,Up,Dragged}です。これは明らかにせいぜいハックであり、Mac OS X はそれをすべて気に入らなかったことが判明しました。ボタンをクリックすることはできますが、離すとボタンが押し込まれたままになります。

私は自分で動作を模倣することができましたが、これはそれほど複雑ではありません。ただし、ボタンを押し込んだように見せる方法がわかりません。


「やめてください! これは Mac OS X の型にはまらない動作であり、避けるべきです」と言う前に: 私はこれを検討しましたが、右クリックによってワークフローが大幅に改善される可能性があります。基本的に、ボタンは 4 つの状態を循環します。右クリックで逆に循環させたいと思います。必須の機能ではありませんが、あると便利です。それでも「やめて!」と言いたい場合は、ご意見をお聞かせください。それは有り難いです!

ありがとう!

編集:これはイベントを変更する私の試みでした(タイプを変更することはできないので、すべての情報をコピーして新しいイベントを作成しました。つまり、これはフレームワークであることを知っています。あなたがするように、私はそれを試してみました):

// I've contracted all three for brevity
- (void)rightMouse{Down,Up,Dragging}:(NSEvent *)theEvent {
    NSEvent *event = [NSEvent mouseEventWithType:NSLeftMouse{Down,Up,Dragging} location:[theEvent locationInWindow] modifierFlags:[theEvent modifierFlags] timestamp:[theEvent timestamp] windowNumber:[theEvent windowNumber] context:[theEvent context] eventNumber:[theEvent eventNumber] clickCount:[theEvent clickCount] pressure:[theEvent pressure]];
    [self mouse{Down,Up,Dragging}:event]; 
}

更新: -mouseUp:NSButton に送信されていないことに気付きました。それを NSControl に変更すると、送信されました。Francis McGrew が、独自のイベント処理ループが含まれていることを指摘するまで、これがなぜなのかわかりませんでした。さて、これも、ルートを変更する前に理由が理解できました-rightMouseDown:が、リリース時にボタンが上がらなかったのです。これは、独自に新しいイベントを取得していたため、マウスの右ボタン イベントから左ボタン イベントをインターセプトして変換できなかったためです。

4

3 に答える 3

6

NSButton がマウス トラッキング ループに入っています。これを変更するには、NSButton をサブクラス化し、独自のカスタム トラッキング ループを作成する必要があります。このコードを試してください:

- (void) rightMouseDown:(NSEvent *)theEvent 
{
    NSEvent *newEvent = theEvent;
    BOOL mouseInBounds = NO;

    while (YES) 
        {
            mouseInBounds = NSPointInRect([newEvent locationInWindow], [self convertRect:[self frame] fromView:nil]);
            [self highlight:mouseInBounds];

            newEvent = [[self window] nextEventMatchingMask:NSRightMouseDraggedMask | NSRightMouseUpMask];

            if (NSRightMouseUp == [newEvent type])
            {
                break;
            }
        }
    if (mouseInBounds) [self performClick:nil];
}

これが私のやり方です。うまくいけば、それはあなたのために働くでしょう。

于 2011-04-28T13:50:56.077 に答える
2

マウスの左クリック アンド ホールドを、パス コントロール上で偽の右マウス ダウンに変えました。これですべての問題が解決するかどうかはわかりませんが、これを行ったときの主な違いはタイムスタンプを変更することであることがわかりました。

NSEvent *event = [NSEvent mouseEventWithType:NSLeftMouseDown 
                                    location:[theEvent locationInWindow] 
                               modifierFlags:[theEvent modifierFlags] 
                                   timestamp:CFAbsoluteGetTimeCurrent()
                                windowNumber:[theEvent windowNumber] 
                                     context:[theEvent context]
 // I was surprised to find eventNumber didn't seem to need to be faked 
                                 eventNumber:[theEvent eventNumber]   
                                  clickCount:[theEvent clickCount] 
                                    pressure:[theEvent pressure]];

もう 1 つは、ボタンのタイプによっては、ボタンstateが押されているかどうかに関係なく値が設定されている可能性があるため、それを調べてみることができます。

rightMouseUp:更新:が呼び出されない理由がわかったと思います。ドキュメント-[NSControl mouseDown:]によると、ボタンはイベントを取得するとマウスの追跡を開始し、取得するまで追跡を停止mouseDownしません。追跡中は、他に何もできません。たとえば、カスタムの最後に試しました:mouseUpmouseDown:

[self performSelector:@selector(mouseUp:) withObject:myFakeMouseUpEvent afterDelay:1.0];

しかし、これは法線mouseUp:が別の方法でトリガーされるまで延期されます。したがって、マウスの右ボタンをクリックした場合、(マウスで) を送信することはできませんleftMouseUp。したがって、ボタンは引き続き追跡され、rightMouseUpイベントを受け入れません。解決策はまだわかりませんが、有益な情報になると思います。

于 2011-04-28T02:19:48.687 に答える
1

上記の回答に追加することはあまりありませんが、Swift で作業している人にとっては、ドキュメントの奥深くに埋もれているイベント マスクの定数を見つけるのに苦労するかもしれません。コンパイラが受け入れるため、これにより時間を節約できます。もっときちんとした方法はありますか?これはあなたのサブクラスに入ります-

var rightAction: Selector = nil 
  // add a new property, by analogy with action property

override func rightMouseDown(var theEvent: NSEvent!) {
  var newEvent: NSEvent!

  let maskUp = NSEventMask.RightMouseUpMask.rawValue
  let maskDragged = NSEventMask.RightMouseDraggedMask.rawValue
  let mask = Int( maskUp | maskDragged ) // cast from UInt

  do {
    newEvent = window!.nextEventMatchingMask(mask)
  }
  while newEvent.type == .RightMouseDragged

私のループは常に少なくとも 1 回は実行する必要があるため、do..while になりましたwhile true

おそらく、コントロールがテーブル ビューに埋め込まれていたため、convertRect() から意味のある結果を得るのに際限なく苦労しました。上記の Gustav Larsson に、最後の部分でこれを終わらせてくれてありがとう -

let whereUp = newEvent.locationInWindow
let p = convertPoint(whereUp, fromView: nil)
let mouseInBounds = NSMouseInRect(p, bounds, flipped) // bounds, not frame
if mouseInBounds {
  sendAction(rightAction, to: target)
  // assuming rightAction and target have been allocated
  }
}
于 2014-11-10T23:03:33.200 に答える