2010-02-17 75 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

相關問題