2010-02-17 10 views
9

kakao uygulamamda, NSTableView için özel bir NSCell'e ihtiyacım var. Bu NSCell alt sınıfında, bir tıklatmayla ilgilenen özel bir NSButtonCell bulunur (ve metin içeriği için iki veya üç NSTextFieldCells). Aşağıda kodumun basitleştirilmiş bir örneğini bulacaksınız.NSButtonCell, NSCell

@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]; 
} 

Ben onunla şaşırıp sorundur: (: NSButtonCell daha doğrusu) bu NSCell içine düzgün çalışması için o Düğme almak için en iyi/doğru yolu nedir? "iş" şu anlama gelir: Atanan eylem mesajını tetikler ve tıklatıldığında alternatif görüntüyü gösterir. Kutunun dışında, düğme tıklandığında hiçbir şey yapmaz.

Bu konuyla ilgili bilgi/okuma bulmak zor. Net üzerinde bulunan tek mesaj

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

bunu yapmak için doğru yolu mu uygulamak için bana işaret ??? TrackMouse'ı uygulayın: NSCell içerimde? Ve daha sonra olayı NSButtonCell iletin? NSButtonCell'in kendisinin tıklandığında ne yapılacağını bilmesini beklerdim (ve trackMouse'u gördüm: gerçekten fare hareketlerini takip eden metotlar - 'standart' tıklama davranışı için bir eğitim çarkı olarak değil). Ama sanki bir hücreye dahil olduğu zaman bunu yapmaz gibi görünüyor ... Özel hücreler üzerinde büyük resmi kavramadım gibi görünüyor, ama yine de ;-)

(ya da bazı öğretici ya da benzerleri için bana) bu kendi deneyiminden cevap ve doğru yolda iseniz söyle. peşin

sayesinde

cevap

8

asgari şartlar şunlardır: Fare üzerindeyken her

  • aşağı butonuna sol fare sonra, basılı görünür olmalıdır.
  • Fare daha sonra düğmenin üzerinde serbest kalırsa, hücreniz uygun eylem mesajını göndermelidir.

Düğmenin görünmesini sağlamak için, düğme hücresinin highlighted özelliğini uygun şekilde güncelleştirmeniz gerekir. Durumu tek başına değiştirmek bunu başaramayacaktır, ancak istediğin şey, yalnızca durumunun NSOnState olması durumunda, düğmenin vurgulanmasıdır.

İşlem mesajını göndermek için, farenin ne zaman piyasaya çıktığını bilmeniz ve ardından iletiyi göndermek için -[NSApplication sendAction:to:from:]'u kullanmanız gerekir.

Bu iletileri gönderecek konumda bulunmak için, NSCell tarafından sağlanan etkinlik izleme yöntemlerine bağlanmanız gerekir. Son olarak, -stopTracking:... yönteminin dışındaki tüm izleme yöntemlerinin, "İzleme iletileri almaya devam etmek istiyor musunuz?" Sorusunu yanıtlamak için bir Boole döndürdüğüne dikkat edin.

Son bükülme, herhangi bir izleme iletisinin gönderilmesi için, -hitTestForEvent:inRect:ofView: uygulamanız ve NSCellHit... değerlerinin uygun bir bit maskesini döndürmeniz gerektiğidir. Özel olarak, döndürülen değer içinde NSCellHitTrackableArea değeri yoksa, herhangi bir izleme iletisi almayacaksınız!

Yani, yüksek bir düzeyde, uygulamaya koyma gibi bir şey olacaktır:

- (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

İçindekiler tablosunda, veri kaynağını düğmenin işaretli olduğunu bildirmesini söylüyorsunuz? – Richard

+0

@Jeremy W. Sherman: Bu muhtemelen aptalca bir sorudur, ancak "düğme hücresinin | buttonRect |" ini nasıl alırsınız? [Button frame] gibi çeşitli şeyler denedim, ama bu işe yaramıyor ... – houbysoft

5

NSCell alt sınıflarının noktası oluşturma ve görsel-ve olay-hiyerarşi NSView sınıfların sorumlulukları gelen ortak UI öğeleri (kontrol) işleme sorumluluğunu ayırmaktır Tobi. Bu eşleştirme, her birinin diğerini zorlamadan daha fazla uzmanlık ve değişkenlik sunmasına izin verir. Kakao'da oluşturabileceğiniz çok sayıda NSButton örneğine bakın. İşlevsel olarak bu bölümün bulunmaması durumunda mevcut olacak NSButton alt sınıflarının sayısını düşünün!

Rolleri tanımlamak için tasarım deseni dilini kullanarak: bir NSControl, dış görünüm olarak davranır, bileşenin ayrıntılarını istemcilerinden gizler ve olayları iletir ve iletileri temsilci olarak çalışan NSCell örneğine iletir. senin NSCell alt sınıf Bileşiminde içinde diğer NSCell alt sınıf örneklerini içerdiğinden

, artık doğrudan görünüm hiyerarşide bulunan NSControl örneğinden bu olay mesajları almak. Bu nedenle, bu hücre örneklerinin olay yanıtlayan zincirinden (görünüm hiyerarşisinin) olay iletilerini alması için, hücre örneğinizin ilgili olayları geçmesi gerekir. NSView hiyerarşisinin işini yeniden oluşturuyorsunuz.

Bu, mutlaka kötü bir şey değildir. NSControl (ve onun NSView süper sınıfı) davranışını çoğaltma, ancak bir NSCell formunda, alt hücrelere iletilen olayları konum, olay türü veya diğer ölçütlere göre filtreleyebilirsiniz. Bu dezavantaj, & yönetim mekanizmasının filtrelenmesindeki NSView/NSControl çalışmasını kopyalamaktadır.

Yani arayüz tasarımı, sen NSButtonCell (ve NSTextFieldCell ler) NSCell alt sınıfta normal görünümde hiyerarşide NSControl s daha iyi, ya da alt-hücreleri olarak olup olmadığını dikkate almak gerekir. Kod tabanı içinde halihazırda var olan işlevselliği, yeniden icat etmekten (ve daha sonra bakımını yapmaya devam etmekten) gereksiz bir şekilde faydalanmaktan daha iyidir.

+1

, Huperniketes teşekkürler - İyi bir take konu üzerine! – Tobidobi

+0

@Huperniketes bir tablo için bir özel hücre (yani, yeni tablo NSView hücre yeteneği ile Lion öncesi) uygulayacak olsaydım, temelde gömdüğüm her denetimin davranışını taklit etmeye zorlandım ve sadece hücreyi çizim kısmı gerçekten. Bu doğru mu? – David

+1

@David, sorunuza açık değilim. Bir tablo görünümünde özel bir hücreye bir NSView alt sınıfını gömme hakkında soru soruyorsanız, hücrenizin görünümü alt sınıfın kendisinden gelen iletileri işleyerek veya tablo görünümünde geçirerek veya bırakarak NSControl protokolüne uyması gerekir. söndürdü. Genellikle kontrol hücresinin kendisini kullanabileceğinden, özel bir hücrede bir NSControl alt sınıfını gömmeniz gerekmez. Hücrenin davranışına göre, parçaları çizmek, tıklanan parçaları bulmak vb. Için hücreyi kullanabilirsiniz. – Huperniketes