How to create a transparent window with non-rectangular buttons?

北城余情 提交于 2019-11-27 14:49:27

What about overriding the NSResponder event methods (mouseUp:, mouseDown:, etc) in your custom buttons (presumably you'd be subclassing NSControl or NSButton to make these)? In those methods you could properly calculate your bounding rectangle (or circle, in this case) and do a simple hit test with the coordinates of the click to see if the click should be handled.

You might also be able to find some help in Apple's event handling docs, specifically about mouse events and custom views.

What about making it all a single control? It might make drawing a little bit complex, but it looks like you're doing custom drawing anyway.

If you did it as a single control, you could first check and see if the click point is within the center circle. If it's not, then all you have to do is identify which quadrant it's in to know which "button" it belongs to (while also verifying that the click fits within the outer circle).

Alternatively, you could create a transparent view over your buttons that captures the click events and forwards them on to the appropriate control based on the logic I just specified.

Similar to Marc W's response, in your own event method you can check the alpha value of the clicked on the bitmap and ignore if the alpha is lower than a certain value.

To get the bitmap, read this.

Now you should have a bitmap pointer like this (pseudocode - you'll have to fill in the pieces):

pixels = CGBitmapContextGetData( ctx ); // there's actually two ways to get pixels in the above Apple tech note

Then, you can do this to get the pixel you are interested in, and test it:

// I'm assuming each pixel is 24 bits of color and one byte of alpha
#define getRed(p) ((p) & 0x000000FF)
#define getGreen(p) ((p) & 0x0000FF00) >> 8
#define getBlue(p) ((p) & 0x00FF0000) >> 16
#define getAlpha(p) ((p) & 0xFF000000) >> 24

CGPoint pixPt;
long pixel;
pixPt = getMouseClick();

pixel = pixels[pixPt.x + pixPt.y * bytesPerRow];

if (getAlpha(pixel) < 25)
  // you've clicked on transparent pixels, alpha of 10% or less (alpha ranges from 0-255)

This opens up some possibilities for you, such as having a ring around your inside circle that is inert and won't belong to any of the quadrants or the middle circle. Of course, there's always other ways to do these things without resorting to pixel-wrangling :-)

If you generate the shapes in code using NSBezierPath, testing whether a click is inside one of the shapes is a one-liner: send the shape a containsPoint: message.

I'd make this a single view that owns the five paths. When drawing, draw the center one last; when responding to a mouse event, hit-test it first. Give this view one action property per segment, and optionally one target per segment as well, depending on what you need.

You'd need to do two things:

  1. override NSView's hitTest: method to return NIL whenever the click is outside the image, so the click in that view is ignored and passedto the view overlapping it.
  2. Override mouseDown: and implement your own mouse tracking loop in there (Using NSEventTrackingRunLoopMode) that also checks whether the point is in a non-transparent area. NSBitmapImageRep or NSImage has a colorAtX:y: method or something like hat which you can use for the latter.

Mu solution works only on non-intersect buttons. I have non-rectangular button, that must change images from gray to green.

I change regular gradient button like this

thats all. Hope this help someone.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!