Mac Developer (Australia): Mac Example -- Drawing Strings with Cocoa
Source code
A source code example of how to use Cocoa to to draw strings using 4 different methods. This is a very simple application of the string class, attributed string class, glyph class and text layout manager..
An XCode project implementing this algorithm can be downloaded here...
Theory
No theory!
The source code that implements this follows:
/*
----------------------------------------------------
The drawing is done here when requested by the
Cocoa framework.
*/
- (void)drawRect:(NSRect)rect
{
NSString* label = NULL;
NSPoint labelLocation;
NSRect bounds = [self bounds];
labelLocation.x = bounds.size.width/2;
labelLocation.y = bounds.size.height/2;
switch(mLayoutMode)
{
case eBezierPathCharacterMode:
{
// Begin: USE_BEZIER_PATHS
label = @"Bezier Path Character Mode";
// Get a font
//NSFont* font = [NSFont boldSystemFontOfSize: 12];
// Get a Bezier path
NSBezierPath* glyphPath = [NSBezierPath bezierPath];
NSFont *font = [NSFont fontWithName:@"Helvetica" size:100.0];
NSGlyph glyph = [font glyphWithName: [label substringToIndex: 1]];
[glyphPath moveToPoint: labelLocation];
[glyphPath appendBezierPathWithGlyph: glyph inFont: font];
[glyphPath stroke];
// End: USE_BEZIER_PATHS
break;
}
case eBezierPathStringMode:
{
// Begin: USE_BEZIER_PATHS
label = @"Bezier Path String Mode";
// Get a font
//NSFont* font = [NSFont boldSystemFontOfSize: 12];
// Get a Bezier path
NSBezierPath* glyphPath = [NSBezierPath bezierPath];
NSFont *font = [NSFont fontWithName:@"Helvetica" size:100.0];
[glyphPath moveToPoint: labelLocation];
// Build glypth array
int stringCount = [label length];
NSGlyph* glyphs = NULL;
glyphs = (NSGlyph*)malloc(sizeof(NSGlyph)*stringCount);
int stringIndex = 0;
for(stringIndex = 0; stringIndex < stringCount; stringIndex++)
{
NSString* singleCharacter = [label
substringWithRange: NSMakeRange(stringIndex, 1)];
glyphs[stringIndex] = [font glyphWithName: singleCharacter];
}
// Add glyphs to path
[glyphPath appendBezierPathWithGlyphs: glyphs
count: stringCount inFont: font];
[glyphPath stroke];
free(glyphs);
// End: USE_BEZIER_PATHS
break;
}
case eStringDrawingMode:
{
// Begin: USE_STRING_METHOD
label = @"String Drawing Mode";
// Draw a string
[label drawAtPoint: labelLocation withAttributes:NULL];
// End: USE_STRING_METHOD
break;
}
case eCentredStringDrawingMode:
{
// Begin: USE_ATTRIBUTED_STRING_METHOD
label = @"Centred String Drawing Mode";
NSAttributedString* aLabel = [[NSAttributedString alloc]
initWithString: label];
NSSize textBox = [aLabel size];
labelLocation.x -= textBox.width/2;
labelLocation.y += textBox.height/2;
// Draw a string
// Note 1: for a string use
// (but the size message used above does not work)
//[label drawAtPoint: labelLocation withAttributes:NULL];
//[label drawInRect: bounds withAttributes:NULL];
// Note 2: for an attributed string
[aLabel drawAtPoint: labelLocation];
//[aLabel drawInRect: labelLocation];
[aLabel release];
// End: USE_ATTRIBUTED_STRING_METHOD
break;
}
case eLayoutManagerMode:
{
// Begin: USE_LAYOUT_MANAGER
label = @"Layout Manager Mode";
// Initialise NSLayoutManager for drawing glyphs
NSTextStorage* textStorage = [[NSTextStorage alloc] initWithString: label];
NSLayoutManager* layoutManager = [[NSLayoutManager alloc] init];
NSTextContainer* textContainer = [[NSTextContainer alloc] init];
[layoutManager addTextContainer: textContainer];
[textContainer release];
[textStorage addLayoutManager: layoutManager];
[layoutManager release];
// End: USE_LAYOUT_MANAGER
// Draw glyphs
#define DRAW_ENTIRE_STRING
#ifdef DRAW_ENTIRE_STRING
// To draw entire string
NSRange glyphRange = [layoutManager
glyphRangeForTextContainer: textContainer];
#else // DRAW_ENTIRE_STRING
// To draw just a string range
NSRange charRange;
NSRange actualCharRange;
charRange.location = 0;
charRange.length = 1;
NSRange glyphRange = [mLayoutManager
glyphRangeForCharacterRange: charRange
actualCharacterRange: &actualCharRange];
#endif // DRAW_ENTIRE_STRING
[self lockFocus];
[layoutManager drawGlyphsForGlyphRange: glyphRange atPoint: bounds.origin];
[self unlockFocus];
// End: USE_LAYOUT_MANAGER
break;
}
}
}
/*
----------------------------------------------------
*/
Comments or corrections welcome. Send an email to farad'aty'farad.com.au.
An XCode project implementing this algorithm can be downloaded here...
|