2009-08-05 10 views
48

Mam NSTableView z kilkoma kolumnami tekstu. Domyślnie dataCell dla tych kolumn jest instancją klasy Apple NSTextFieldCell, która wykonuje wszystkie cudowne rzeczy, ale rysuje tekst wyrównany do górnej części komórki i chcę, aby tekst był wyśrodkowany pionowo w komórce.Czy istnieje "właściwy" sposób, aby NSTextFieldCell narysował pionowo wyśrodkowany tekst?

Istnieje wewnętrzna flaga w NSTextFieldCell, która może być używana do pionowego wycentrowania tekstu i działa pięknie. Jednakże, ponieważ jest to flaga wewnętrzna, jego użycie nie jest usankcjonowane przez Apple i może po prostu zniknąć bez ostrzeżenia w przyszłej wersji. Używam tej flagi wewnętrznej, ponieważ jest prosta i skuteczna. Apple najwyraźniej poświęcił trochę czasu na implementację tej funkcji, więc nie podoba mi się pomysł ponownego jej wdrożenia.

Tak; moje pytanie jest następujące: Jaki jest właściwy sposób implementacji czegoś, co zachowuje się dokładnie jak NStextFieldCell firmy Apple, ale rysuje pionowo wyśrodkowany tekst zamiast wyrównanego do góry?

Dla przypomnienia, oto mój prąd "rozwiązanie":

@interface NSTextFieldCell (MyCategories) 
- (void)setVerticalCentering:(BOOL)centerVertical; 
@end 

@implementation NSTextFieldCell (MyCategories) 
- (void)setVerticalCentering:(BOOL)centerVertical 
{ 
    @try { _cFlags.vCentered = centerVertical ? 1 : 0; } 
    @catch(...) { NSLog(@"*** unable to set vertical centering"); } 
} 
@end 

wykorzystane w następujący sposób:

[[myTableColumn dataCell] setVerticalCentering:YES]; 
+0

Nie sądzę, że blok try/catch ma sens w tym przypadku, ponieważ _cflags jest strukturą C, a nie obiektem Objective C. Jeśli ta struktura zostanie zmieniona w przyszłej wersji systemu Mac OS X, może się zdarzyć wiele dziwnych rzeczy, ale żaden wyjątek nie zostanie zgłoszony. –

+0

@Jakob Egger: Prawdopodobnie masz rację. Znalazłem to rozwiązanie w innym miejscu w Internecie i skopiowałem je tak jak jest. –

+0

Powinieneś przyjąć odpowiedź Jakoba Eggera. Kiedy używany jest kod z zaakceptowanej odpowiedzi, powoduje to dziwny błąd podczas edycji 'NSTextFieldCell'. Odpowiedź Jakoba rozwiązuje problem. –

Odpowiedz

35

Pozostałe odpowiedzi nie zadziałały w przypadku wielu linii. Dlatego początkowo nadal korzystałem z nieudokumentowanej właściwości cFlags.vCentered, ale to spowodowało odrzucenie mojej aplikacji ze sklepu z aplikacjami. Skończyło się stosując zmodyfikowaną wersję rozwiązania Matt Bell, który działa na wielu liniach, zawijania tekstu, a obcięty ostatni wiersz:

-(void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView { 
    NSAttributedString *attrString = self.attributedStringValue; 

    /* if your values can be attributed strings, make them white when selected */ 
    if (self.isHighlighted && self.backgroundStyle==NSBackgroundStyleDark) { 
     NSMutableAttributedString *whiteString = attrString.mutableCopy; 
     [whiteString addAttribute: NSForegroundColorAttributeName 
          value: [NSColor whiteColor] 
          range: NSMakeRange(0, whiteString.length) ]; 
     attrString = whiteString; 
    } 

    [attrString drawWithRect: [self titleRectForBounds:cellFrame] 
        options: NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin]; 
} 

- (NSRect)titleRectForBounds:(NSRect)theRect { 
    /* get the standard text content rectangle */ 
    NSRect titleFrame = [super titleRectForBounds:theRect]; 

    /* find out how big the rendered text will be */ 
    NSAttributedString *attrString = self.attributedStringValue; 
    NSRect textRect = [attrString boundingRectWithSize: titleFrame.size 
               options: NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin ]; 

    /* If the height of the rendered text is less then the available height, 
    * we modify the titleRect to center the text vertically */ 
    if (textRect.size.height < titleFrame.size.height) { 
     titleFrame.origin.y = theRect.origin.y + (theRect.size.height - textRect.size.height)/2.0; 
     titleFrame.size.height = textRect.size.height; 
    } 
    return titleFrame; 
} 

(Kod ten zakłada, ARC, dodaj autorelease po attrString.mutableCopy jeśli używasz podręcznik zarządzanie pamięcią)

+0

To działało dla mnie i jest to bardzo ładne wdrożenie - dziękuję. – ioquatix

+0

To działa bardzo dobrze. Przyjęta odpowiedź spowodowała dziwny błąd podczas edycji komórki. –

+3

Przy okazji, czy możliwe jest wycentrowanie tekstu podczas edycji? Mój 'NSTextFieldCell' ma wiele linii, a kiedy użytkownik dwukrotnie kliknie tekst, aby go edytować, wraca do początku aż do zakończenia edycji. –

29

Zastępowanie NSCell na -titleRectForBounds: powinien to zrobić - to metoda odpowiedzialny za mówienie komórka, w której należy narysować jej tekst:

- (NSRect)titleRectForBounds:(NSRect)theRect { 
    NSRect titleFrame = [super titleRectForBounds:theRect]; 
    NSSize titleSize = [[self attributedStringValue] size]; 
    titleFrame.origin.y = theRect.origin.y + (theRect.size.height - titleSize.height)/2.0; 
    return titleFrame; 
} 

- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView { 
    NSRect titleRect = [self titleRectForBounds:cellFrame]; 
    [[self attributedStringValue] drawInRect:titleRect]; 
} 
+0

To wydaje się obiecujący pomysł, ale to nie działa dla mnie. Stworzyłem podklasę 'NSTextFieldCell', skopiowałem twój kod i użyłem klasy niestandardowej dla komórek w moim' NSTableView', ale metoda 'titleRectForBounds' nigdy nie jest wywoływana. –

+3

Ach, zapomniałem, że NSTextFieldCell zasadniczo leży w jego dokumentacji - masz rację, NSTextFieldCell domyślnie nie używa -titleRectForBounds :. Zaktualizowałem swoją odpowiedź, aby przesłonić -drawInteriorWithFrame: inView: aby narysować tekst we właściwym miejscu. –

+0

Ładnie wykonane. To działa jak urok! –

4

FYI działa to dobrze, chociaż nie udało mi się zmusić go do pozostania w środku podczas edycji komórki ... czasami mam komórki z dużymi ilościami tekstu i ten kod może spowodować, że nie będą wyrównane, jeśli wysokość tekstu jest większa niż . komórka to stara się pionowo wyśrodkować go w Oto moja zmodyfikowana metoda:

- (NSRect)titleRectForBounds:(NSRect)theRect 
{ 
    NSRect titleFrame = [super titleRectForBounds:theRect]; 
    NSSize titleSize = [[self attributedStringValue] size]; 
    // test to see if the text height is bigger then the cell, if it is, 
    // don't try to center it or it will be pushed up out of the cell! 
    if (titleSize.height < theRect.size.height) { 
     titleFrame.origin.y = theRect.origin.y + (theRect.size.height - titleSize.height)/2.0; 
    } 
    return titleFrame; 
} 
4

dla każdego, kto próbuje to używając drawInteriorWithFrame:inView: metodę Matt Ball, ten nie będzie już narysować tło jeśli ustawić komórkę wyciągnąć jeden. Aby rozwiązać ten dodatek coś wzdłuż linii

[[NSColor lightGrayColor] set]; 
NSRectFill(cellFrame); 

na początku swojej metodzie drawInteriorWithFrame:inView:.

2

Choć jest to dość stare pytanie ...

wierzę domyślny styl realizacji NSTableView przeznaczony jest wyłącznie do wyświetlania tekstu pojedynczy zgodnie ze wszystkimi samej wielkości & czcionki.

W tym przypadku polecam,

  1. zestaw czcionek.
  2. Dostosuj rowHeight.

Może dostaniesz cicho gęste rzędy. A następnie nadaj im wypełnienie ustawiając intercellSpacing.

Na przykład

core_table_view.rowHeight    = [NSFont systemFontSizeForControlSize:(NSSmallControlSize)] + 4; 
    core_table_view.intercellSpacing  = CGSizeMake(10, 80); 

Oto co dostaniesz z dwoma regulacji własności.

enter image description here

To nie będzie działać dla tekstu multi-line, ale bardzo dobre dla szybkiego centrum pionowym, jeśli nie potrzebują wsparcia wielu linii.

+0

Jest to rozsądne rozwiązanie dla komórek jednoliniowych, które prawdopodobnie obejmują większość przypadków użycia. Dzięki! –

1

miałem ten sam problem i tutaj jest rozwiązanie robiłam:

1) w interfejsie Builder wybierz NSTableCellView. Upewnij się, że jest tak duży, jak wysokość wiersza w Inspektorze rozmiarów. Na przykład, jeśli wysokość wiersza jest 32, dokonać wysokość komórki 32

2) Upewnij się, że komórka jest dobrze umieszczone w rzędzie (mam na myśli widoczny)

3) Wybierz TextField wewnątrz komórki i przejść do inspektora rozmiarze

4) należy patrz „Rozmieszczanie” element i wybierz „Centrum pionowo w pojemnik”

-> pole tekstowe będzie koncentrować się w komórce

0

nr prawo sposobem jest aby umieścić Field w innym widoku i użyć aut o układ lub układ widoku rodzica, aby go ustawić.

+0

OK - ale w jaki sposób zmienię rozmiar pola (zmienić jego wysokość), aby pasował do tekstu? Bez tego, będę miał ładnie wyśrodkowane pole tekstowe, ale tekst wewnątrz pola będzie nadal wyrównany do góry, więc tekst pojawi się nad centrum w widoku rodzica. –

+0

To jest absolutnie właściwa odpowiedź. Zezwalaj NSTextField na poleganie na jego wewnętrznym rozmiarze (dostosuj rozmiar czcionki, który chcesz, który będzie odpowiadał zmianie w wewnętrznym rozmiarze), a następnie dodaj go jako widok podrzędny do widoku kontenera, który ustawi go w ramce w stosunku do tego, co zawiera pole tekstowe a to pozwoli dopasować wewnętrzną wielkość pola tekstowego do całkowitej przestrzeni. – Asher

+0

@Asher, tak naprawdę nie, zmiana rozmiaru czcionki nie powoduje zmiany rozmiaru pola: https://www.dropbox.com/s/9b4vgcp7kuujll2/Screenshot%202016-03-01%2012.02.26.png?dl=0 –

Powiązane problemy