String in einem NSView zentrieren

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • String in einem NSView zentrieren

    Hallo,

    ich suche nach einer Möglich ein NSString in der Mitte eines Custom Views auszugeben. Bisher habe ich die drawRect Methode benutzt:

    Quellcode

    1. - (void)drawRect:(NSRect)dirtyRect
    2. {
    3. NSRect bounds = [self bounds];
    4. NSString *text =@"Hallo Welt!";
    5. NSPoint textPoint = NSMakePoint(bounds.size.width /2, bounds.size.height /2);
    6. [text drawAtPoint:textPoint withAttributes:nil];
    7. }
    Nun ist aber der Punkt links unten am Text mittig. Ich bräuche also eine Möglichkeit die Breite und Höhe des Textes zu bestimmen, oder die Mitte des Textes als Orientierungspunkt zu nutzen.

    noch eine weitere Frage:
    Ich habe gelesen , dass diese Art Text anzuzeigen relativ langsam ist.
    Geht es dabei darum, dass man den Text nicht schnell ändern kann, oder wo liegt da das Problem.
    Ich möchte auf dem View einige Strings platzieren, alle werden aber höchstens drei Wörter enthalten.


    Schonmal Danke für alle Antworten
    Tom
  • Mac & i Test Abo
  • Hallo,

    siehe unten - mal nen Beispiel…

    Viele Grüße

    Quellcode

    1. @interface ABTextLabel ()
    2. @property (readwrite, copy) NSString *contentText;
    3. @property (readwrite, assign) NSTextAlignment contentTextAlignment;
    4. @property (readwrite, assign) CGFloat contentTextSize;
    5. @property (readwrite, copy) NSColor *contentTextColor;
    6. @property (readwrite, copy) NSFont *contentTextFont;
    7. @end
    8. @implementation ABTextLabel
    9. -(void)dealloc
    10. {
    11. // …
    12. self.contentText = nil;
    13. self.contentTextColor = nil;
    14. self.contentTextFont = nil;
    15. // …
    16. [super dealloc];
    17. // …
    18. }
    19. #pragma mark -
    20. -(void)setText:(NSString*)text
    21. {
    22. // …
    23. self.contentText = text;
    24. // …
    25. [self setNeedsDisplay:YES];
    26. // …
    27. }
    28. -(NSString*)text
    29. {
    30. // …
    31. return self.contentText;
    32. // …
    33. }
    34. -(void)setTextAlignment:(NSTextAlignment)alignment
    35. {
    36. // …
    37. self.contentTextAlignment = alignment;
    38. // …
    39. [self setNeedsDisplay:YES];
    40. // …
    41. }
    42. -(NSTextAlignment)textAlignment
    43. {
    44. // …
    45. return self.contentTextAlignment;
    46. // …
    47. }
    48. -(void)setTextSize:(CGFloat)size
    49. {
    50. // …
    51. self.contentTextSize = size;
    52. // …
    53. [self setNeedsDisplay:YES];
    54. // …
    55. }
    56. -(CGFloat)textSize
    57. {
    58. // …
    59. return self.contentTextSize;
    60. // …
    61. }
    62. -(void)setTextColor:(NSColor*)color
    63. {
    64. // …
    65. self.contentTextColor = color;
    66. // …
    67. [self setNeedsDisplay:YES];
    68. // …
    69. }
    70. -(NSColor*)textColor
    71. {
    72. // …
    73. return self.contentTextColor;
    74. // …
    75. }
    76. -(void)setTextFont:(NSFont*)font
    77. {
    78. // …
    79. self.contentTextFont = font;
    80. // …
    81. [self setNeedsDisplay:YES];
    82. // …
    83. }
    84. -(NSFont*)textFont
    85. {
    86. // …
    87. return self.contentTextFont;
    88. // …
    89. }
    90. #pragma mark -
    91. -(NSParagraphStyle*)textParagraphStyle
    92. {
    93. // …
    94. NSParagraphStyle *paragraphStyle = [NSParagraphStyle defaultParagraphStyle];
    95. if(paragraphStyle == nil)
    96. {
    97. return nil;
    98. }
    99. // …
    100. NSMutableParagraphStyle *mutableParagraphStyle = [[paragraphStyle mutableCopy] autorelease];
    101. if(mutableParagraphStyle == nil)
    102. {
    103. return nil;
    104. }
    105. // …
    106. NSTextAlignment alignment = [self textAlignment];
    107. // …
    108. [mutableParagraphStyle setAlignment:alignment];
    109. // …
    110. paragraphStyle = [[mutableParagraphStyle copy] autorelease];
    111. if(paragraphStyle == nil)
    112. {
    113. return nil;
    114. }
    115. // …
    116. return paragraphStyle;
    117. //
    118. }
    119. -(NSDictionary*)textAttributes
    120. {
    121. // …
    122. NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionary];
    123. if(mutableDictionary == nil)
    124. {
    125. return nil;
    126. }
    127. // …
    128. id object = nil;
    129. // …
    130. object = [self textFont];
    131. if(object != nil)
    132. {
    133. // …
    134. [mutableDictionary setObject:object
    135. forKey:NSFontAttributeName];
    136. // …
    137. }
    138. // …
    139. object = [self textColor];
    140. if(object != nil)
    141. {
    142. // …
    143. [mutableDictionary setObject:object
    144. forKey:NSForegroundColorAttributeName];
    145. // …
    146. }
    147. // …
    148. object = [self textParagraphStyle];
    149. if(object != nil)
    150. {
    151. // …
    152. [mutableDictionary setObject:object
    153. forKey:NSParagraphStyleAttributeName];
    154. // …
    155. }
    156. // …
    157. NSDictionary *dictionary = [NSDictionary dictionaryWithDictionary:mutableDictionary];
    158. if([dictionary count] < 1)
    159. {
    160. return nil;
    161. }
    162. // …
    163. return dictionary;
    164. // …
    165. }
    166. #pragma mark -
    167. -(void)drawRect:(NSRect)dirtyRect
    168. {
    169. // …
    170. [super drawRect:dirtyRect];
    171. // …
    172. NSString *string = [self text];
    173. if([string length] < 1)
    174. {
    175. return;
    176. }
    177. // …
    178. NSDictionary *dictionary = [self textAttributes];
    179. if([dictionary count] < 1)
    180. {
    181. return;
    182. }
    183. // …
    184. NSRect frame = [self bounds];
    185. // …
    186. CGFloat offsetFactor = 0.02;
    187. // …
    188. CGFloat offsetWidth = frame.size.width * offsetFactor;
    189. CGFloat offsetHeight = frame.size.height * offsetFactor;
    190. // …
    191. frame.size.width -= ( offsetWidth * 2.0 );
    192. frame.size.height -= ( offsetHeight * 2.0 );
    193. frame.origin.x = offsetWidth;
    194. frame.origin.y = offsetHeight;
    195. // …
    196. NSStringDrawingOptions stringDrawingOptions = NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin;
    197. // …
    198. NSRect bounding = [string boundingRectWithSize:NSMakeSize(frame.size.width, CGFLOAT_MAX)
    199. options:stringDrawingOptions
    200. attributes:dictionary];
    201. // …
    202. if(bounding.size.height > frame.size.height)
    203. {
    204. bounding.size.height = frame.size.height;
    205. }
    206. // …
    207. frame.origin.y = frame.origin.y + ( ( frame.size.height - bounding.size.height ) / 2.0 );
    208. frame.size.height = bounding.size.height;
    209. // …
    210. // [[[NSColor whiteColor] colorWithAlphaComponent:0.5] set];
    211. // [NSBezierPath fillRect:frame];
    212. // …
    213. [string drawWithRect:frame
    214. options:stringDrawingOptions
    215. attributes:dictionary];
    216. // …
    217. }
    218. @end
    Alles anzeigen
  • Ich hab den Code jetzt mal gekürzt und dann in meine Klasse reingepackt, scheint so auch zu funktionieren:

    Quellcode

    1. - (void)drawRect:(NSRect)dirtyRect
    2. {
    3. NSMutableDictionary *textAttributes = [[NSMutableDictionary alloc]init];
    4. [textAttributes setObject:[NSFont fontWithName:@"Times" size:40] forKey:NSFontAttributeName];
    5. NSString *string = @"Hallo Welt";
    6. NSRect frame = [self bounds];
    7. NSStringDrawingOptions stringDrawingOptions = NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin;
    8. NSRect bounding = [string boundingRectWithSize:NSMakeSize(CGFLOAT_MAX, CGFLOAT_MAX) options:stringDrawingOptions attributes:textAttributes];
    9. if(bounding.size.height > frame.size.height)
    10. {
    11. bounding.size.height = frame.size.height;
    12. }
    13. if(bounding.size.width > frame.size.width)
    14. {
    15. bounding.size.width = frame.size.width;
    16. }
    17. frame.origin.y =( ( frame.size.height - bounding.size.height ) / 2.0 );
    18. frame.size.height = bounding.size.height;
    19. frame.origin.x =( ( frame.size.width - bounding.size.width ) / 2.0 );
    20. frame.size.width = bounding.size.width;
    21. [[[NSColor whiteColor] colorWithAlphaComponent:0.5] set];
    22. [NSBezierPath fillRect:frame];
    23. [string drawWithRect:frame options:stringDrawingOptions attributes:textAttributes];
    24. }
    Alles anzeigen


    Wofür sind allerdings die folgenden Zeilen zuständig? (bei little_pixel Z. 319ff)

    Quellcode

    1. CGFloat offsetFactor = 0.02;
    2. // …
    3. CGFloat offsetWidth = frame.size.width * offsetFactor;
    4. CGFloat offsetHeight = frame.size.height * offsetFactor;
    5. // …
    6. frame.size.width -= ( offsetWidth * 2.0 );
    7. frame.size.height -= ( offsetHeight * 2.0 );
    8. frame.origin.x = offsetWidth;
    9. frame.origin.y = offsetHeight;
    10. // …
    Alles anzeigen


    War ich mal wieder zu langsam mit dem Antworten...

    Die Methode sizeWithFont gefällt mir besser, werde ich also nutzen.

    Ich habe mich bisher noch nicht mir CoreText beschäftigt, ist das aufwendiger zu programmieren?


    Tom
  • Du kannst den Attributes einen NSParagraphStyle mitgeben und auf Center oder Justify stellen.
    Und dann drawInRect:withAttributes:

    Bei einem drawAtPoint: weiß er ja nicht wie breit das Ganze sein soll.

    Alternative 2:

    Quellcode

    1. textPoint.x -= [text sizeWithAttributes:nil].width/2

    Gibt aber Probleme bei MultiLine String und/oder zu breitem String.
  • little_pixel schrieb:

    Du mußt bei meinem gezeigten Quelltext nur Copy & Paste machen.
    Mehr Arbeit hast Du nicht… ;)
    Ich würde gerne verstehen, was ich warum mache, und es scheint ja auch ohne zu funktionieren.

    little_pixel schrieb:

    Dann verändere mal den Wert 0.02 mal zu 0.2 oder so und schaue was passiert.
    Ehrlich gesagt weiß ich nicht, wo ich deinen Code einsetzen soll. Ich programmier noch nicht so lange und bisher bin ich davon ausgegangen, dass das quasi eine Klasse ist.
    Ich weiß auf jeden Fall nicht, wie ich den Code in Xcode einsetze, der Sinn geht mir (glaube ich) schon auf.

    Nach dem Tipp von gritsch nutze ich jetz übrigens folgende Methode:

    Quellcode

    1. - (void)drawText:(NSString*)string centeredAtPoint:(NSPoint)point whithAttributes:(NSDictionary *)attrs{
    2. NSSize size = [string sizeWithAttributes:attrs];
    3. NSPoint centeredPoint;
    4. centeredPoint.x = point.x - size.width /2;
    5. centeredPoint.y = point.y - size.height /2;
    6. [string drawAtPoint:centeredPoint withAttributes:attrs];
    7. }
    Eleganter wäre es vllt. diese Methode irgendwie der Klasse von NSString unterzuordnen, wie es hier gelöst ist.

    Tom
  • Hallo,

    Gibt aber Probleme bei MultiLine String und/oder zu breitem String.

    Genau.
    Deshalb ist mein gezeigter Quelltext schon ne Premiumlösung, die dieses Problem löst.

    Ich würde gerne verstehen, was ich warum mache, und es scheint ja auch ohne zu funktionieren.

    Als solches hast Du mit der Aussage recht.
    Allerdings bezog sich mein Argument auf die Tatsache, dass Du einfach mal ausprobieren kannst/sollst.
    Dann siehst Du was sich verändert und kannst den Code viel leichter verstehen.

    Um die Sache aufzulösen:

    Das ist nichts anderes, als 2% Padding, wie das in HTML-Dingens-Zeugs heißt.
    Damit wird verhindert, dass der Text bis zum Rand des Views gezeichnet wird und schiiissie aussieht.

    Viele Grüße
  • little_pixel schrieb:

    Um die Sache aufzulösen:
    Das ist nichts anderes, als 2% Padding, wie das in HTML-Dingens-Zeugs heißt.
    Damit wird verhindert, dass der Text bis zum Rand des Views gezeichnet wird und schiiissie aussieht.

    Danke, ist eine praktische Erweiterung aber in meinem Fall wahrscheinlich nicht nötig, deshalb werde ich es weglassen. In meiner Methode habe ich dadurch, dass ich statt drawInRect drawAtPoint nutze sogar den Fall, dass der String über den Rand des Views hinausgeht.
    Das mit dem 2% Padding ist auf jeden Fall eine gute Anregung, werde ich bei Bedarf nutzen.

    Tom