Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/cocoa/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/macos/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Cocoa 在mouseDown:上将子视图置于顶部,并继续接收事件(用于拖动)_Cocoa_Macos_Mouseevent_Nsview_Hittest - Fatal编程技术网

Cocoa 在mouseDown:上将子视图置于顶部,并继续接收事件(用于拖动)

Cocoa 在mouseDown:上将子视图置于顶部,并继续接收事件(用于拖动),cocoa,macos,mouseevent,nsview,hittest,Cocoa,Macos,Mouseevent,Nsview,Hittest,好的,基本上我有一个视图,有一系列稍微重叠的子视图。单击子视图时,它会通过一个非常简单的双线移动到顶部(除其他外): -(void)mouseDown:(NSEvent *)theEvent { if (_selected) { // Don't do anything this subview is already in the foreground return; } NSView *superview = [self superview]; [self remove

好的,基本上我有一个视图,有一系列稍微重叠的子视图。单击子视图时,它会通过一个非常简单的双线移动到顶部(除其他外):

-(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:
或任何后续事件。只有当我离开鼠标并再次单击视图时,它才会拖动,因为第二次单击不会对视图层次进行任何处理

我能做些什么来让视图像这样移动到前台,并继续接收后续的
-mouseDragged:
-mouseUp:
事件

我开始考虑在superview中重写
-hitTest:
,并截取mouseDown事件,以便在视图实际接收事件之前将其置于前台。这里的问题是,从
-hitTest:
中,如何区分我实际执行命中测试的事件类型?对于其他鼠标事件,如mouseMoved等,我不想将子视图移动到前台

更新|在我的superview中,我实际上已经这样做了,但感觉像是一种非常糟糕的代码气味直接触发了来自
-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;
}
有两件事让人感觉不对劲。最大的问题是,我在
-hitTest:
返回之前执行操作,然后在
-hitTest:
完成之后,按照AppKit处理的方式执行操作。第二,我没有要通过的项目,所以我通过了零。在这种情况下它是有效的,因为我知道事件处理程序实际上并不处理任何事件数据,但这并不好。另一种选择是将整个逻辑移到superview中,但这里的关注点分离感觉更糟

更新|此
-hitTest:
黑客已被破解。。。当我没有进行鼠标点击时,例如当我在视图顶部拖动某个对象时,它会被触发。仍然在寻找解决这个问题的好办法


答案可以从字面上指示视图在拖动操作期间如何离开和重新进入其superview,或者(可能更优雅)将视图移动到前台的另一种方式,而不是
[view removeFromSuperview];[超级视图添加子视图:视图…]

好吧,我一时兴起,尝试了一些不合逻辑的东西

要将视图移动到前景,请执行以下操作:

[theView removeFromSuperview];
[theSuperview addSubview:theView positioned:NSWindowAbove relativeTo:nil];
我简单地删除了
removeFromSuperview
行,想知道如果您尝试向superview添加两次视图,AppKit实际上会做什么(我假设它提供了防止这种情况发生的保护)


它可以工作,至少在雪豹下,它解决了很多问题。正如方法名称所示,superview中已经存在的视图不会被添加,但它确实可以设置其位置,而不必首先将其从superview中删除。

我找到了你的帖子,因为我也遇到了同样的问题(顺便说一句,很烦人)。正确的解决方案是使用您自己的特殊比较器函数对子视图进行排序。在父视图上,调用-sortSubviewsUsingFunction:context:method.

以编程方式触发鼠标事件,您可以使用

如果你有很多内容在移动,你甚至应该调用
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));

这给了用户一种错觉,即使项目从superview移动到另一个superview,用户也可以拖放项目。

我现在尝试从我的
-mouseDown:
操作中手动驱动事件循环,但在
-mouseUp:
事件发生之前,不会收到任何事件。将视图从superview中删除并重新放回AppKit确实让人困惑。这种方法的问题是,尽管正确,但如果视图是层备份的,则排序是动态的。这也发生在OP自己的答案上。
CGEventRef ourEvent = CGEventCreate(NULL);

//Some long operation

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