如果事件不处理,则将事件发送到另一个 NSControl 下的 NSControl

发布于 2024-08-06 23:01:56 字数 566 浏览 10 评论 0原文

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

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

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

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

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

提前致谢!

I have multiple superposed controls which can handle a mouse click under certain conditions. What I want to be able to do is:

  1. The top control receives the
    mouseDown: event.
  2. The top control decides if it handles the mouseDown: event.
  3. If it does, do something and prevent other controls from receiving the mouseDown: event.
  4. If it does not, send the event to the control that's underneath.
  5. This control decides if it handles the event.
  6. etc.

In essence I'm trying to send the event to the control whose "Z-Order" is just below the top control, without the top control needing to know about the other controls or needing some special setup at instantiation.

The first thing that came to my mind was to send the event to [topControl nextResponder] but it seems the nextResponder for all controls on the window is the window itself and not a chain of controls based on their Z-Order as I previously thought.

Is there a way to do this without resorting to setting the next responder manually? The goal is to get a control which is independent from the other controls and can just be dropped on a window and work as expected.

Thanks in advance!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

若无相欠,怎会相见 2024-08-13 23:01:56

您所要做的就是调用[super mouseDown:event]。从 Mac OS X 10.5 开始(这以前的工作方式)NSView 知道如何处理重叠视图,并将为您处理事件。


如果您需要定位 10.5 之前的版本:这是一个非常糟糕的主意。不仅事件处理机制不知道如何处理重叠的子视图,绘图系统也不知道如何处理,并且您可以看到一些非常奇怪的人工制品。也就是说,如果您确定:

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

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

All you have to do is call [super mouseDown:event]. Since Mac OS X 10.5 (this did not work the same way before) NSView knows how to handle overlapping views and will take care of event handling for you.


If you need to target releases before 10.5: This is a really bad idea. Not only does the event handling mechanism not know how to deal with overlapping subviews, neither does the drawing system and you can see some very strange artefacts. That said, if you're determined:

Override -[NSView hitTest:] in your custom control/view. AppKit uses this method to determine which view in the hierarchy to deliver mouse events to. If you return nil that point in your custom view is ignored and the event should get delivered to the next view covering that point.

Mind though, this is still a bad idea because of the reasons I outlined above. It just wasn't something formally supported by AppKit at the time. The more generally accepted workaround on 10.4 and earlier is to use a child window.

極樂鬼 2024-08-13 23:01:56

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

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

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

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

@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];
}

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

It's hard to know exactly the best approach because I don't know what your application does, but here's a thought. It sounds like you want to pass the messages up through the view hierarchy... somehow.

Regardless, a view would do one of two things:

  • handle the message
  • pass it to the "next view" (how you define "next view" depends on your application)

So. How would you do this? The default behavior for a view should be to pass the message to the next view. A good way of implementing this kind of thing is through an informal protocol.

@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

Now, in the views that should have that behavior, you'd do this:

- (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
}

You would probably want to create an NSView subclass to override mouseDown: that you would then base your other custom view classes on.

If you wanted to determine the "next view" based on actual z-order, keep in mind that z-order is determined by the order within the subviews collection, with later views appearing first. So, you could do something like this:

- (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];
}

This might be way more than you wanted, but I hope it helps.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文