2010-02-17 55 views
9

,我需要为NSTableView定制NSCell。这个NSCell子类包含用于处理点击(以及用于文本内容的两个或三个NSTextFieldCell)的自定义NSButtonCell。您会在下面找到我的代码的简化示例。在我的可可应用程序中定制NSCell的NSButtonCell

@implementation TheCustomCell 

- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView { 
    // various NSTextFieldCells 
    NSTextFieldCell *titleCell = [[NSTextFieldCell alloc] init]; 
    .... 
    // my custom NSButtonCell 
    MyButtonCell *warningCell = [[MyButtonCell alloc] init]; 
    [warningCell setTarget:self]; 
    [warningCell setAction:@selector(testButton:)]; 
    [warningCell drawWithFrame:buttonRect inView:controlView]; 
} 

我坚持的问题是:是什么让该按钮的最好/正确的方式(更准确地说是NSButtonCell)这里面的NSCell正常工作?“工作”的意思是:触发指定的动作信息,并单击时显示备用图像。开箱即用,单击按钮时不会执行任何操作。

关于此主题的信息很难找到。我在网上发现的唯一帖子指出我实施了

- (BOOL)trackMouse:(NSEvent *)theEvent inRect:(NSRect)cellFrame ofView:(NSView *)controlView untilMouseUp:(BOOL)untilMouseUp; 

这是正确的方法吗? 实现trackMouse:在我的包含NSCell?然后将事件转发给NSButtonCell?我希望NSButtonCell能够知道当它被点击时该怎么做(并且我更多地看到了trackMouse:方法可以真正追踪鼠标移动 - 而不是“标准”点击行为的训练轮)。但似乎它不包括在单元格本身... 似乎我还没有掌握定制单元格的大图片,但;;)

我会很高兴如果有人可以用他自己的经验回答这个问题(或者指点我一些教程或类似的东西) - 并告诉我如果我在正确的轨道

由于提前, 托比

回答

8

的最低要求是:

  • 鼠标左键向下按钮后,它必须出现,只要按下鼠标悬停它。
  • 如果鼠标通过按钮释放,则您的单元必须发送相应的操作消息。

要使按钮看起来按下,您需要适当更新按钮单元的highlighted属性。单独改变状态不会达到这个目的,但是你想要的是只有当状态是NSOnState时,按钮才会被突出显示。

要发送操作消息,您需要知道鼠标何时被释放,然后使用-[NSApplication sendAction:to:from:]发送消息。

为了能够发送这些消息,您需要挂接到由NSCell提供的事件跟踪方法。请注意,除最终的方法-stopTracking:...之外,所有这些跟踪方法都会返回一个布尔值来回答“您想继续接收跟踪消息吗?”这个问题吗?

最后一点是,为了发送任何跟踪消息,你需要实现-hitTestForEvent:inRect:ofView:并返回一个合适的位掩码NSCellHit...值。具体而言,如果返回的值中没有NSCellHitTrackableArea值,则不会收到任何跟踪消息!

因此,在较高的水平,你的执行将看起来像:

- (NSUInteger)hitTestForEvent:(NSEvent *)event 
         inRect:(NSRect)cellFrame 
         ofView:(NSView *)controlView { 
    NSUInteger hitType = [super hitTestForEvent:event inRect:cellFrame ofView:controlView]; 

    NSPoint location = [event locationInWindow]; 
    location = [controlView convertPointFromBase:location]; 
    // get the button cell's |buttonRect|, then 
    if (NSMouseInRect(location, buttonRect, [controlView isFlipped])) { 
     // We are only sent tracking messages for trackable areas. 
     hitType |= NSCellHitTrackableArea; 
    } 
    return hitType; 
} 

+ (BOOL)prefersTrackingUntilMouseUp { 
    // you want a single, long tracking "session" from mouse down till up 
    return YES; 
} 

- (BOOL)startTrackingAt:(NSPoint)startPoint inView:(NSView *)controlView { 
    // use NSMouseInRect and [controlView isFlipped] to test whether |startPoint| is on the button 
    // if so, highlight the button 
    return YES; // keep tracking 
} 

- (BOOL)continueTracking:(NSPoint)lastPoint at:(NSPoint)currentPoint inView:(NSView *)controlView { 
    // if |currentPoint| is in the button, highlight it 
    // otherwise, unhighlight it 
    return YES; // keep on tracking 
} 

- (void)stopTracking:(NSPoint)lastPoint at:(NSPoint)stopPoint inView:(NSView *)controlView mouseIsUp:(BOOL)flag { 
    // if |flag| and mouse in button's rect, then 
    [[NSApplication sharedApplication] sendAction:self.action to:self.target from:controlView]; 
    // and, finally, 
    [buttonCell setHighlighted:NO]; 
} 
+0

你在哪里告诉表格告诉它的数据源该按钮已被检查? – Richard 2011-12-25 05:49:32

+0

@Jeremy W. Sherman:这可能是一个愚蠢的问题,但你如何得到“button button | buttonRect |”?我尝试了各种各样的东西,如[按钮框],但似乎没有工作... – houbysoft 2012-02-28 04:34:15

5

NSCell小类中所述的点是分离用于再现和处理来自visual-和事件层次结构中的NSView类 责任公共UI元素(对照)的责任。这种配对允许每个人提供更大的专业化和可变性,而不会增加另一方的负担。看看可以在Cocoa中创建的大量NSButton实例。想象一下,如果这种功能分割不存在,那么将存在NSButton个子类的数量!

使用设计模式语言来描述角色:NSControl充当façade,从其客户端隐藏其组成细节,并将事件和呈现消息传递给作为委托的NSCell实例。

因为你的NSCell亚类包括其组合物内的其他子类NSCell的情况下,他们不再直接接收来自NSControl实例这是在视图层次这些事件消息。因此,为了让这些单元实例从事件响应链(视图层次结构)接收事件消息,您的单元实例需要传递这些相关事件。您正在重新创建NSView层次结构的工作。

这不一定是坏事。通过复制NSControl(及其NSView超类)的行为,但复制NSCell表单中的行为,可以按位置,事件类型或其他条件过滤传递到子单元的事件。缺点是复制NSView/NSControl在构建过滤管理机制中的工作。

所以在设计你的界面,你需要考虑NSButtonCell(和NSTextFieldCell S)是否在普通视图层次更好的NSControl S,或子细胞在NSCell子类。最好利用代码库中已存在的功能,而不是不必要地重新创建它(并在以后继续维护)。

+1

谢谢Huperniketes - 好取的话题! – Tobidobi 2010-02-27 15:27:12

+0

@Huperniketes所以如果我要为一个表(这是与新表NSView单元功能的预先狮子)实现自定义单元格,我被迫基本上模仿我嵌入的每个控件的行为,我只是使用单元格绘图部分真的。那是对的吗? – David 2011-11-05 08:06:38

+1

@大卫,我不清楚你的问题。如果你问的是在表格视图中嵌入一个NSView子类到自定义单元格中,你的单元格需要符合NSControl协议,或者处理来自视图子类本身的消息,将它们传递给表视图,或者让它们离开它们存根。您不需要在自定义单元格中嵌入NSControl子类,因为您通常可以使用该控件的单元格本身。至于细胞的行为,你可以使用单元格绘制零件,找到点击零件等。 – Huperniketes 2012-01-20 00:14:25

相关问题