2

わかりました、基本的に私は一連のわずかに重なり合うサブビューを持つビューを持っています。サブビューがクリックされると、非常に単純な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 ...];

4

3 に答える 3

4

さて、私は気まぐれに出かけて、非論理的なことを試みました。

これの代わりに、ビューをフォアグラウンドに移動します。

[theView removeFromSuperview];
[theSuperview addSubview:theView positioned:NSWindowAbove relativeTo:nil];

removeFromSuperviewビューをスーパービューに2回追加しようとすると、AppKitが実際に何をするのか疑問に思って、私は単に線を落としました(私はそれが起こることに対する保護を提供すると仮定しました)。

少なくともSnowLeopardの下では機能し、多くの問題を解決します。メソッド名が示すように、スーパービューにすでに存在するビューは追加されませんが、最初にスーパービューから削除しなくても、その位置が設定されます。

于 2011-01-02T11:53:42.717 に答える
0

私は同じ問題を抱えていたのであなたの投稿を見つけました(非常に厄介なこと、ところで)。正しい解決策は、独自の特別なコンパレータ関数を使用してサブビューをソートすることです。親ビューで、-sortSubviewsUsingFunction:context:メソッドを呼び出します。

于 2012-03-28T17:14:46.167 に答える
0

プログラムでマウスイベントをトリガーするには、CGEventCreateMouseEvent()を使用してダブルクリックを実行するを使用できます。

CGEventRef ourEvent = CGEventCreate(NULL); //save the mouse event to track location
PostMouseEvent(kCGMouseButtonLeft, NX_LMOUSEDOWN, CGEventGetLocation(ourEvent));

void PostMouseEvent(CGMouseButton button, CGEventType type, const CGPoint point)
{
   CGEventRef theEvent = CGEventCreateMouseEvent(NULL, type, point, button);
   CGEventSetType(theEvent, type);
   CGEventPost(kCGHIDEventTap, theEvent);
   CFRelease(theEvent);
}

移動するコンテンツがたくさんある場合はCGEventCreate(NULL);、操作の前に電話をかけて、次のようなことを行う必要があります。

CGEventRef ourEvent = CGEventCreate(NULL);

//Some long operation

CGEventRef dragEvent = CGEventCreate(NULL);
PostMouseEvent(kCGMouseButtonLeft, NX_LMOUSEDOWN, CGEventGetLocation(ourEvent));
PostMouseEvent(kCGMouseButtonLeft, NX_LMOUSEDRAGGED, CGEventGetLocation(dragEvent));

これにより、ユーザーがスーパービューから別のスーパービューに移動した場合でも、アイテムをドラッグアンドドロップできるように見えます。

于 2014-01-20T14:27:40.530 に答える