2009-10-06 184 views
7

我期待让这将是这个样子(不去管快速的Photoshop)的自定义窗口:如何用非矩形按钮创建透明窗口?

alt text http://i35.tinypic.com/20ff803.png

主要的问题我已经是不使窗口透明(虽然我想任何信息是受欢迎的!),但我希望能够只点击按钮的可见部分。例如,如果我点击“5”按钮左上方的外部,即使点击了按钮5的边框,我希望它在“1”按钮上注册而不是“5”按钮。如果我点击“1”按钮的左上方“角落”的外侧,我希望它可以点击我窗口下方的任何内容,而不是按钮上的内容。我还需要能够调整这个窗口的大小,并且按钮中的图片应该与它们一起调整大小。

我想使用与含有的PNG用α为每个按钮透明NSButtons透明NSWindow的,但我认为重叠按钮将是一个问题。

我也听说过类似蝴蝶结,SweetFM并使用WebKit的施展接口的应用程序等。如果这是至少有可能的10.3,这将是有趣的,但我不知道如何也可以。

我环顾四周,点击面具,地区或类似的东西,但我还没有发现任何东西。我会更新这篇文章,因为我发现更多的信息(如果我做的!)。

对如何进行任何提示?

(请注意,我在10.4和理想我需要支持一些老版本的Mac OS X的太工作。)

(另外,我发现了“圆窗”例如苹果的开发。网站但它不会在10.4,所以我不知道这是要走的路提前跑了。)

谢谢!

UPDATE:

(见更新2,这个问题已经得到解决)

OK,现在我有一个稍微不同的(但不无关系)的问题。我所做的,到目前为止是这样的:

我选择了做,我就可以用我的每个按键的自定义控制:

1子类的NSControl并重写drawRect中,mouseUp事件,和的mouseDragged鼠标按下。通过这种方式,我可以在拖动按钮(移动窗口)时获得所需的行为。

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

3-获取NSImage中的位图表示:

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

OR

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

似乎都给予同样的结果。我试图将这个位图代表合成到我的窗口,看看图像是否与原始尺寸相同并且看起来不错(你会看到为什么我在枚举之后做了这件事......)。

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一起工作过,也许我只是忘记指定一些关于我的图像的格式信息,这就是为什么值是关闭的。有人可以澄清这一点吗?再次

谢谢!

更新2:

好没关系,我发现这个问题。我使用setColor:atX:y:方法在打印到窗口之前在bitRep上绘制了一个彩色点,并且问题在白天清晰显示:在bitRep中Y坐标反转,但图像打印的是“good “定位。这意味着bitRep具有“Windows风格”的左上角原点坐标系,而窗口具有笛卡尔坐标系(左下)原点。简单地颠倒我的Y坐标可以解决我获得alpha分量和颜色的问题。

这一定是写在文档的某个地方,对不起,因为我缺乏研究而打扰你......!

回答

3

什么覆盖您的自定义按钮NSResponder事件方法(mouseUp:mouseDown:等),(想必你会继承NSControlNSButton使这些)?在这些方法中,您可以正确计算您的边界矩形(在这种情况下为圆形),并使用点击坐标进行简单的点击测试,以查看点击是否应该处理。

您也许能够在Apple的事件处理文档中找到一些帮助,特别是关于mouse eventscustom views

+0

谢谢,这将是该中心按钮的可能性,但与外面的按钮,会比较困难,需要一堆的边界检查代码...如果我改变什么我的按钮的位置由于某种原因?(这不是一个个人项目,所以这可能会有所改变,不幸的是)然后我不得不重写大部分的边界检查代码......有没有办法用某种掩码来做到这一点?说“让点击通过,如果位图透明在这一点上”? – Form 2009-10-06 20:40:47

+0

我不认为你可以像你想的那样使用面具(透明度检测等)。这些都是非常基本的形状(内圈下方的外部按钮的部分圆圈)。您可以在代码中访问控件的当前坐标和尺寸,并使用它们来计算命中范围,以便不对任何东西进行硬编码。使用中心按钮位于最佳位置的事实。 – 2009-10-06 21:27:23

+0

它可以使用透明度(alpha)检测,它工作得很好,虽然我现在使用的方法是10.4+,但有一种方法可以使用除colorAtX之外的其他方法来执行此操作:y:只要您有权访问就像mahboudz指出的那样。 – Form 2009-10-09 13:28:26

2

如何使它成为一个单一的控制?这可能会使绘图有点复杂,但看起来您仍然在进行自定义绘制。

如果你没有它作为一个单一的控制,你可以先检查,看看点击点为中心的圆内。如果不是,那么你所要做的就是确定它在哪个象限以了解它属于哪个“按钮”(同时还要验证点击是否在外圈内)。

或者,您可以创建在你的按钮,透明的观点,即捕获点击事件,并将它们转发到基于我刚才指定的逻辑适当的控制。

2

马克·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) 

这开辟了给你一些可能性,比如具有在你的内圆环形是活泼的,不属于任何象限或中间圆的。当然,还有其他的方法可以做到这些,而不需要像素拼接:-)

+0

这看起来更像是我想要做的事情,那样如果我的控件的形状改变它应该自动调整。有没有一种方法可以检查按钮图像中特定点的图像的不透明度? (我认为将子类化NSButton而不是手动绘制NSView并进行绘制的工作会更少,但如果无法使用按钮检查Alpha,我很可能会使用NSView)。 – Form 2009-10-07 02:21:01

+0

我将位图处理信息添加回我的回复中。 – mahboudz 2009-10-07 05:34:49

+0

非常感谢,我会看到我能用它做什么! – Form 2009-10-07 14:25:30

1

如果您使用NSBezierPath在代码中生成形状,测试点击是否在其中一个形状内是单线:发送形状containsPoint:消息。

我会想办法让这个拥有五个路径的单一视图。绘图时,最后绘制中心;当响应鼠标事件时,首先进行命中测试。根据您的需要,为此视图提供每个细分的一个操作属性,并且还可以选择每个细分的一个目标。

+0

你的解决方案非常有趣,我不知道你可以像这样测试NSBezierPaths。它一定会派上用场。但在我的情况下(随着形状的变化不可忽略的可行性),我认为如果我改变了某些东西,这将会是很多重写。我会先尝试位图alpha测试,如果这不起作用,我希望它能做到这一点。感谢您花时间回答我的问题! – Form 2009-10-07 13:32:54

1

你需要做两件事情:

  1. 覆盖的NSView的则hitTest:方法返回NIL只要点击在图像之外,使该视图中的点击被忽略,passedto重叠它的视图。
  2. 覆盖鼠标按下:和实现自己的鼠标跟踪环路在那里(使用NSEventTrackingRunLoopMode)也检查点是否是在非透明区域。 NSBitmapImageRep或NSImage有一个colorAtX:y:方法或类似帽子的东西,你可以使用后者。
0

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

sample button 我改变这样

properties

多数民众赞成定期渐变按钮。希望这可以帮助别人。