NSButton-自定义形状按钮的点击测试翻转/悬停 [英] NSButton - Hit Testing rollover/hover for custom shaped buttons

查看:130
本文介绍了NSButton-自定义形状按钮的点击测试翻转/悬停的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

(Targeting OS X 10.10,Xcode的最新版本)



我有一个 NSButton 子类。



该按钮需要响应鼠标的悬停/悬停,例如Web按钮。



该按钮需要以圆形显示。因此,使用圆形图形调用 -setImage: -setAlternateImage:



问题1::当在NSButton区域内的任意位置单击鼠标时,NSButton的默认行为会导致正面命中测试。



建议的解决方案:覆盖 -hitTest:以计算到中心的点击距离按钮。如果距离>按钮的半径,则我们没有有效的点击。



好的,很好。



问题2:如何处理鼠标悬停/翻转以及更改



建议的解决方案:在按钮上添加一个 NSTrackingArea ,然后覆盖 -mouseEntered: -mouseExited:,这样我们就可以在鼠标移到按钮上时更改按钮图像和AlternateImage。



好的,很好。



但是 ... NSTrackingArea 适用于矩形,不适用于圆形等任意区域。更糟糕的是,它不遵守-hitTest:



建议的解决方案:将圆形碰撞检测代码添加到 -mouseEntered:- mouseExited:



但是...



-mouseEntered: -mouseExited:仅在每次按钮进入/退出时被调用一次,而不是连续调用。这意味着,如果将鼠标仅移到按钮的矩形区域中,但移动的距离不足以进入按钮的圆形区域,则会调用 -mouseEntered:。但是直到调用 -mouseExited:之后,它才会再次被调用。鼠标进一步移动到圆形区域将无效。 (不会发生过渡。)



即使用这两种方法不可能用准确的鼠标位置信息连续更新按钮的状态。



问题:有谁知道如何实现悬停并按下非矩形按钮?





解决步骤:


  1. 在按钮上添加 NSTrackingArea ,并使用( NSTrackingMouseEnteredAndExited NSTrackingMouseMoved 选项。


  2. 实施 -hitTest:,以便对按钮按下进行准确的(例如圆形)击打测试。我们在此不更改按钮的外观。


  3. 实现 -mouseEntered: -mouseExited:


  4. -mouseEntered 中执行(圆形)碰撞检测,并通过 -setImage相应地更改按钮的外观: (或标记更改您的绘图策略)。


  5. -mouseExited:上,将按钮的外观设置为


  6. 但是, -mouseEntered: -mouseExited:不会被连续调用。因此,我们还需要实现 -mouseMoved:


  7. 但是,我们必须调用 -setAcceptsMouseMovedEvents:YES 在窗口上单击 -mouseMoved:方法。


  8. 添加(圆形)碰撞检测和外观也更改为 -mouseMoved



解决方案

使用 NSTrackingArea 是必经之路,对于非矩形形状,您将必须添加自定义代码以对自定义几何进行命中测试。



不清楚当鼠标悬停在形状上方时为什么要连续设置相同的图像吗?



无论如何,有 mouseMoved :在鼠标在您的跟踪区域内移动时得到通知。
不过,请检查文档-您可能需要在视图或窗口上设置一些额外的标志,因为默认行为可能不会发送移动的消息,以防万一没人收听的情况下大量消息阻塞了框架。 p>

(Targeting OS X 10.10, latest version of Xcode)

I have an NSButton subclass.

The button needs to respond to mouse rollovers/hovers, ala a web button.

The button requires an appearance in the shape of a circle. Accordingly, -setImage: and -setAlternateImage: are called with circular-shaped graphics.

Problem 1: the default behaviour of NSButton results in a positive hit-test when the mouse is clicked anywhere within the rect of the NSButton. This includes mouse clicks that are outside the circular region of the button.

Proposed solution: override -hitTest: to calculate distance of click from centre of the button. If distance > button's radius, we don't have a valid click.

OK, fine. That provides us with accurate collision detection on mouse clicks on circular buttons.

Problem 2: how to handle mouse hover/rollover, and changing the appearance of the button accordingly.

Proposed solution: add an NSTrackingArea to the button, and then override -mouseEntered: and -mouseExited: so we can change the button image and alternateImage as the mouse moves over the button.

OK, fine. That works for rectangles.

But... NSTrackingArea works on rectangles, not arbitrary regions such a circle. Worse, it does NOT honour -hitTest:

Proposed solution: add the circular collision detection code in to -mouseEntered: and -mouseExited:

But...

-mouseEntered: and -mouseExited: are only called ONCE per button entry/exit, not continuously. This means that if the mouse is moved just in to the button's rectangular region, but not far enough that it enters the button's circular region, -mouseEntered: will be called. But it will not be called again, until after -mouseExited: is called. Further movement of the mouse in to the circular region will have no effect. (No rollover will occur.)

i.e. it is not possible to continuously update the button's state with accurate mouse position information using these two methods.

QUESTION: does anyone know how to implement hover and pressing on a non-rectangular button?

[edit - SOLVED thanks to cacau.]

Solution steps:

  1. Add an NSTrackingArea to the button, with (at a minimum) the NSTrackingMouseEnteredAndExited and NSTrackingMouseMoved options.

  2. Implement -hitTest: in order to do accurate (e.g. circular) hit testing for button presses. We do not change the appearance of the button here.

  3. Implement -mouseEntered: and -mouseExited:

  4. Do (circular) collision detection within -mouseEntered, changing the appearance of the button accordingly via -setImage: (or otherwise flagging changes to your drawing strategy.)

  5. On -mouseExited: set the button's appearance back to its default.

  6. But, -mouseEntered: and -mouseExited: are not called continuously. Therefore we also need to implement -mouseMoved:

  7. But, we must call -setAcceptsMouseMovedEvents:YES on the window, so that the -mouseMoved: method is called on the button.

  8. Add the (circular) collision detection and appearance changing to -mouseMoved as well.

解决方案

Using NSTrackingArea is the way to go, for non-rectangular shapes you'll have to add custom code to perform hit testing for your custom geometries.

Not clear why you'd want to continuously set the same image when the mouse is hovering above your shape?

Anyway, there's mouseMoved: to get notified when the mouse moves within you tracking area. Check the docs, though - you might need to set some extra flags on the view or window as the default behaviour might not send moved messages to not clog the framework with huge amount of messages in case nobody listens..

这篇关于NSButton-自定义形状按钮的点击测试翻转/悬停的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆