如何使用非矩形按钮创建透明窗口?

问题描述 投票:7回答:6

我想制作一个看起来像这样的自定义窗口(不要介意快速的Photoshop):

alt text

我的主要问题是不要让窗口透明(虽然我猜任何信息都是受欢迎的!),但我希望能够只点击按钮的可见部分。例如,如果我点击“5”按钮左上方的外部,我希望它在“1”按钮上注册,而不是“5”按钮,即使我点击了按钮5的边界框。如果我点击“1”按钮的左上角“”“,我希望它点击窗口下方的任何内容而不是按钮上的内容。我还需要能够调整此窗口的大小,按钮中的图片应该随之调整大小。

我正在考虑使用透明的NSWindow,透明的NSButtons包含每个按钮的带有alpha的PNG,但我认为重叠按钮将是一个问题。

我也听说过Bowtie,SweetFM等应用程序以及其他使用WebKit显示其界面的应用程序。如果这是至少10.3的可能性,这将是有趣的,但我不知道这将如何工作。

我四处寻找点击面具,区域或类似的东西,但我还没有找到任何东西。我将更新这篇文章,因为我发现更多信息(如果我这样做!)。

关于如何进行的任何提示?

(请注意,我正在使用10.4,理想情况下我也需要支持一些旧版本的Mac OS X.)

(另外,我在Apple的开发网站上找到了“圆形窗口”示例,但它不再在10.4上运行,所以我不确定这是不是可行的方法。)

提前致谢!

UPDATE:

(见更新2,此问题现已修复)

好的,现在我的问题略有不同(但并非无关)。到目前为止我做的是:

我选择制作一个自定义控件,我可以用于每个按钮:

1-子类NSControl并覆盖drawRect,mouseUp,mouseDragged和mouseDown。这样我可以在拖动按钮时移动我想要的行为(移动窗口)。

2-将每个按钮状态(相同形状但一个变暗)加载到NSImages中,并在必要时使用compositeToPoint:fromRect:operation:将它们绘制到视图中。这些图像是185 x 185像素的PNG文件,从Photoshop导出alpha。

3-获取NSImage的位图表示:

NSBitmapImageRep *bitRep = [[NSBitmapImageRep imageRepWithData:[unpressedImage TIFFRepresentation]] retain];

要么

NSBitmapImageRep *bitRep = [[unpressedImage representations] objectAtIndex:0];

两者似乎都给出了相同的结果。我尝试将这个位图rep合成到我的窗口上以查看图像是否具有相同的大小并且看起来像原始图像并且一切看起来都很好(你会明白为什么我在这个枚举之后就这样做了......)。

4-在鼠标事件方法中,我使用位图表示来获取特定点的alpha分量:

NSPoint mouse = [self convertPoint:[theEvent locationInWindow] fromView:nil]; // Returns the correct x and y positions on the control (i.e: between 0 and 185 for each axis).

NSColor *colorUnderMouse = [[[unpressedImage representations] objectAtIndex:0] colorAtX:mouse.x y:mouse.y];
float alpha = [colorUnderMouse alphaComponent];

然后我将alpha值打印到控制台,但我得到了非常奇怪的结果。获取alpha组件和鼠标下的颜色似乎乍一看(返回的颜色和alpha都在我的位图中),但看起来颜色不是在bitRep中的正确位置拍摄的,或者包含在bitRep是扭曲的(虽然我在窗户上合成bitRep时没有扭曲,这很奇怪)。我再次仔细检查了x和y鼠标坐标是否在(0,185)范围内,并且NSBitmapImageRep的大小也是185 x 185。

首先,看起来NSBitmapImageRep与我的NSImage相比水平翻转。如果我翻转我的坐标,返回的值似乎大部分都可以(大部分形状似乎与返回的值一致)但是仍然有部分图像返回错误的值。

我在这一点上一无所知,之前从未与NSBitmapImageRep合作过,也许我只是忘了指定一些关于我的图像的格式信息,这就是为什么这些值已关闭的原因。有人可以澄清一下吗?

再次感谢!

UPDATE 2:

好吧没关系,我发现了这个问题。我使用setColor:atX:y:方法在bitRep上绘制一个彩色圆点,然后将它打印在我的窗口上,问题就像白天一样清晰:在bitRep中Y坐标反转,但是图像打印出的是“好” “方向。这意味着bitRep具有“Windows风格”的左上角原点坐标系,而窗口具有笛卡尔坐标系(左下角)原点。简单地反转我的Y坐标修复了我获得alpha分量和颜色的问题。

这一定是写在文档的某个地方,很遗憾因为我缺乏研究而困扰你......!

objective-c cocoa nswindow
6个回答
3
投票

怎么样在你的自定义按钮中覆盖NSResponder事件方法(mouseUp:mouseDown:等)(可能你会将NSControlNSButton子类化为这些)?在这些方法中,您可以正确计算边界矩形(或圆形,在本例中)并使用单击的坐标进行简单的命中测试,以查看是否应该处理单击。

您也可以在Apple的事件处理文档中找到一些帮助,特别是有关mouse eventscustom views的帮助。


2
投票

把它全部作为一个控制怎么样?它可能会使绘图变得有点复杂,但看起来你正在做自定义绘图。

如果您将其作为单个控件执行,则可以先检查并查看点击点是否在中心圆内。如果不是,那么你要做的就是确定它所在的象限,以便知道它属于哪个“按钮”(同时还要验证点击是否适合外圈)。

或者,您可以在按钮上创建一个透明视图,捕获单击事件并根据我刚刚指定的逻辑将它们转发到相应的控件。


2
投票

与Marc W的响应类似,在您自己的事件方法中,您可以检查点击位图的alpha值,并忽略alpha是否低于某个值。

要获得位图,read this

现在你应该有一个这样的位图指针(伪代码 - 你必须填写碎片):

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

然后,您可以执行此操作以获取您感兴趣的像素,并对其进行测试:

// 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)

这为您开辟了一些可能性,例如在您的内圈周围有一个惰性且不属于任何象限或中间圆圈的环。当然,总是有其他方法来做这些事情而不诉诸像素争吵:-)


1
投票

如果使用NSBezierPath在代码中生成形状,则测试单击是否在其中一个形状内部是一行的:将形状发送给containsPoint:消息。

我将这个视图拥有五条路径。绘图时,最后绘制中心;在响应鼠标事件时,首先点击测试它。根据您的需要,为每个细分提供一个操作属性,每个细分也可以选择一个目标。


1
投票

你需要做两件事:

  1. 覆盖NSView的hitTest:方法,只要点击位于图像外,就返回NIL,因此忽略该视图中的点击并传递到与其重叠的视图。
  2. 覆盖mouseDown:并在其中实现自己的鼠标跟踪循环(使用NSEventTrackingRunLoopMode),该循环还检查该点是否在非透明区域中。 NSBitmapImageRep或NSImage有一个colorAtX:y:方法或类似帽子的东西,可以用于后者。

0
投票

Mu解决方案仅适用于非交叉按钮。我有非矩形按钮,必须将图像从灰色变为绿色。

我像这样更改常规渐变按钮

就这样。希望这能有所帮助。

© www.soinside.com 2019 - 2024. All rights reserved.