【发布时间】:2011-06-02 05:24:57
【问题描述】:
好的,基本上我有一个包含一系列稍微重叠的子视图的视图。当一个子视图被点击时,它会通过一个非常简单的两条线移动到顶部(除其他外):
-(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: 事件?
我开始考虑在超级视图中覆盖-hitTest: 并拦截mouseDown 事件,以便将视图置于前台在它实际接收到事件之前。这里的问题是,在-hitTest: 中,我如何区分我实际执行命中测试的事件类型?我不想将子视图移动到其他鼠标事件的前台,例如 mouseMoved 等。
更新 |在我的超级视图中,我实际上已经做到了这一点,但感觉就像一个非常糟糕的代码气味,直接触发了来自 -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 处理的操作。第二个是我没有要传递的事件,所以我传递的是 nil。它适用于这种情况,因为我知道事件处理程序实际上并不处理任何事件数据,但这并不是很好。另一种方法是将整个逻辑移到超级视图中,但这里的关注点分离感觉更糟。
更新 |这个-hitTest: hack 被破坏了......当我没有点击鼠标时它会被触发,例如当我将某些东西拖到视图顶部时。仍在寻找解决此问题的好方法。
答案可以直接指示视图在拖动操作期间如何离开并重新进入其父视图,或者(也许更优雅)将视图移动到前台而不是[view removeFromSuperview]; [superview addSubview:view ...]; 的另一种方法。
【问题讨论】:
-
我现在尝试从
-mouseDown:操作中手动驱动事件循环,但在-mouseUp:事件之前没有收到任何事件。从父视图中删除并重新放回的视图确实让 AppKit 感到困惑。
标签: cocoa macos mouseevent nsview hittest