0

我有多个叠加控件,可以在某些条件下处理鼠标单击。我想要做的是:

  1. 顶部控件接收 mouseDown:事件。
  2. 顶部控件决定它是否处理该mouseDown:事件。
  3. 如果确实如此,请执行某些操作并阻止其他控件接收该mouseDown:事件。
  4. 如果没有,则将事件发送到下面的控件。
  5. 此控件决定它是否处理该事件。
  6. 等等

本质上,我试图将事件发送到其“Z-Order”就在顶部控件下方的控件,而顶部控件不需要了解其他控件或在实例化时需要一些特殊设置。

我想到的第一件事是将事件发送到,[topControl nextResponder]但似乎nextResponder窗口上的所有控件都是窗口本身,而不是我之前认为的基于 Z-Order 的控件链。

有没有办法在不手动设置下一个响应者的情况下做到这一点?目标是获得一个独立于其他控件的控件,并且可以将其放在窗口上并按预期工作。

提前致谢!

4

2 回答 2

2

你所要做的就是打电话[super mouseDown:event]。由于 Mac OS X 10.5(以前工作方式不同) NSView 知道如何处理重叠视图,并将为您处理事件处理。


如果您需要针对 10.5 之前的版本:这是一个非常糟糕的主意。不仅事件处理机制不知道如何处理重叠的子视图,绘图系统也不知道,您会看到一些非常奇怪的伪像。也就是说,如果你确定:

-[NSView hitTest:]在您的自定义控件/视图中覆盖。AppKit 使用此方法来确定将鼠标事件传递到层次结构中的哪个视图。如果您nil在自定义视图中返回该点,则该点将被忽略,并且该事件应传递到覆盖该点的下一个视图。

请注意,由于我上面概述的原因,这仍然是一个坏主意。当时 AppKit 并没有正式支持它。在 10.4 及更早版本上更普遍接受的解决方法是使用子窗口。

于 2009-10-08T22:40:51.483 回答
1

很难确切地知道最好的方法,因为我不知道你的应用程序做什么,但这里有一个想法。听起来您想通过视图层次结构向上传递消息……不知何故。

无论如何,视图会做以下两件事之一:

  • 处理消息
  • 将其传递给“下一个视图”(如何定义“下一个视图”取决于您的应用程序)

所以。你会怎么做?视图的默认行为应该是将消息传递给下一个视图。实现这种事情的一个好方法是通过一个非正式的协议。

@interface NSView (MessagePassing)

- (void)handleMouseDown:(NSEvent *)event;
- (NSView *)nextViewForEvent:(NSEvent *)event;

@end

@implementation NSView (MessagePassing)

- (void)handleMouseDown:(NSEvent *)event {
    [[self nextView] handleMouseDown:event];
}

- (NSView *)nextViewForEvent:(NSEvent *)event {
    // Implementation dependent, but here's a simple one:
    return [self superview];
}

@end

现在,在应该具有该行为的视图中,您可以这样做:

- (void)mouseDown:(NSEvent *)event {
    [self handleMouseDown:event];
}

- (void)handleMouseDown:(NSEvent *)event {
    if (/* Do I not want to handle this event? */) {
        // Let superclass decide what to do.
        // If no superclass handles the event, it will be punted to the next view
        [super handleMouseDown:event];
        return;
    }

    // Handle the event
}

您可能希望创建一个NSView子类来覆盖mouseDown:您的其他自定义视图类。

如果您想根据实际 z 顺序确定“下一个视图”,请记住 z 顺序由subviews集合中的顺序决定,后面的视图首先出现。所以,你可以这样做:

- (void)nextViewForEvent:(NSEvent *)event {
    NSPoint pointInSuperview = [[self superview] convertPoint:[event locationInWindow] fromView:nil];
    NSInteger locationInSubviews = [[[self superview] subviews] indexOfObject:self];
    for (NSInteger index = locationInSubviews - 1; index >= 0; index--) {
        NSView *subview = [[[self superview] subviews] objectAtIndex:index];
        if (NSPointInRect(pointInSuperview, [subview frame]))
            return subview;
    }
    return [self superview];
}

这可能比您想要的要多,但我希望它有所帮助。

于 2009-10-08T20:34:10.917 回答