Finding the height of a piece of text

  • Dear List,

    I am attempting to find the height of a piece of text in a particular
    font and color, given that it must be laid out within a specified
    width. There is a piece of code in the "Text Layout Programming Guide"
    that shows how to do this. I have incorporated this code into my
    class, and use various constituents of the Text System, to not only
    calculate the size of my text, but also to display it. I have tried
    various different ways of doing this, up to and including using both
    NSTextViews, NSTextFields and NSTextFieldCells, to do the layout and
    display. I however always end up with the same problem, in that the
    height that I calculate for my text (as per the code in the "Text
    Layout Programming Guide") is always too small (by about ~1 line
    height) . Does anyone have a working solution to this problem or a
    more elegant method of solving it ? I attach my code below. The code
    correctly initializes the various components, and I have checked that
    the font, color and stringValue are all correctly set. I finally call
    desiredHeightForWidth: aWidth to ascertain the correct height, and the
    result is always incorrect.

    Thanks in advance

    Vincent

    - (void) initialize
    {
    [super initialize];
    theDesiredWidth = 10.0f;
    theTextStorage  = [[NSTextStorage alloc] initWithString: @""];
    theTextContainer = [[NSTextContainer alloc] initWithContainerSize:
    NSMakeSize(theDesiredWidth, FLT_MAX)];
    theLayoutManager = [[NSLayoutManager alloc] init];
    [theLayoutManager addTextContainer: theTextContainer];
    [theTextStorage addLayoutManager: theLayoutManager];
    [theTextContainer setLineFragmentPadding:0.0];
    }

    - (void) setStringValue: (NSString*) string
    {
    [theTextStorage replaceCharactersInRange: NSMakeRange(0,
    [theTextStorage length]) withString: string];
    }

    - (float) desiredHeightForWidth: (float) width
    {
    [theTextStorage setFont: [self font]];
    [theTextStorage setForegroundColor: [self textColor]];
    [theTextContainer setContainerSize: NSMakeSize(width,FLT_MAX)];
    [theLayoutManager glyphRangeForTextContainer: theTextContainer];
    return([theLayoutManager usedRectForTextContainer:
    theTextContainer].size.height);
    }
  • On Nov 22, 2007, at 5:56 PM, Vincent Coetzee wrote:

    > I however always end up with the same problem, in that the height
    > that I calculate for my text (as per the code in the "Text Layout
    > Programming Guide") is always too small (by about ~1 line height) .
    > Does anyone have a working solution to this problem or a more
    > elegant method of solving it ?

    To calculate a height that matches an NSTextFieldCell, the line
    fragment padding should be 2 (or 4 for a center alignment).  And the
    layout manager's typesetter behavior should be
    NSTypesetterBehavior_10_2_WithCompatibility.

    --
    Steve
  • Dear List

    I tried your suggestions, alas, it makes no difference ?

    HELP !

    Vincent

    On 23 Nov 2007, at Friday 23/11/200708:39 , Nygard Steve wrote:

    >
    > On Nov 22, 2007, at 5:56 PM, Vincent Coetzee wrote:
    >
    >> I however always end up with the same problem, in that the height
    >> that I calculate for my text (as per the code in the "Text Layout
    >> Programming Guide") is always too small (by about ~1 line height) .
    >> Does anyone have a working solution to this problem or a more
    >> elegant method of solving it ?
    >
    > To calculate a height that matches an NSTextFieldCell, the line
    > fragment padding should be 2 (or 4 for a center alignment).  And the
    > layout manager's typesetter behavior should be
    > NSTypesetterBehavior_10_2_WithCompatibility.
    >
    > --
    > Steve
  • Here we go again...

    On 2007 Nov, 22, at 16:56, Vincent Coetzee wrote:

    > There is a piece of code in the "Text Layout Programming Guide"
    > that shows how to do this....[but] the
    > height that I calculate is always too small (by about ~1 line
    > height). Does anyone have a working solution to this problem

    Please file a Bug Report to Apple.  Tell them it is a duplicate of bug
    5291163, which has a nice demo project.  Supposedly if more people
    complain it is more likely to get attention.

    > or a more elegant method of solving it ?

    I don't see any solution in your code, but I add fudge factors and
    terms, which is about as in-elegant as you can get.  See the message I
    posted 2 days ago, subject = "number of rows for an attributed string".
  • Vincent,

    One thing unclear from your description is how the height returned
    from the code snippet is incorrect.  You mentioned the height is too
    small.
    We need to know how it's small compared to what.  Are you measuring
    using the layout manager and rendering with something else ?

    If you're using either NSStringDrawing or NSCell, as Steve mentioned,
    it's most likely typesetter behavior mismatch.

    Thanks,

    Aki

    On 2007/11/23, at 1:16, Vincent Coetzee wrote:

    > Dear List
    >
    > I tried your suggestions, alas, it makes no difference ?
    >
    > HELP !
    >
    > Vincent
    >
    > On 23 Nov 2007, at Friday 23/11/200708:39 , Nygard Steve wrote:
    >
    >>
    >> On Nov 22, 2007, at 5:56 PM, Vincent Coetzee wrote:
    >>
    >>> I however always end up with the same problem, in that the height
    >>> that I calculate for my text (as per the code in the "Text Layout
    >>> Programming Guide") is always too small (by about ~1 line
    >>> height) . Does anyone have a working solution to this problem or a
    >>> more elegant method of solving it ?
    >>
    >> To calculate a height that matches an NSTextFieldCell, the line
    >> fragment padding should be 2 (or 4 for a center alignment).  And
    >> the layout manager's typesetter behavior should be
    >> NSTypesetterBehavior_10_2_WithCompatibility.
    >>
    >> --
    >> Steve

  • Hmm, since you're using the same layout manager instance for measuring
    and rendering, it doesn't appear to be one of common pitfall cases.

    Maybe you might want to add logging to your -drawRect: and -
    desiredWidthForHeight: method so that the desired width, bounds width,
    and contained width all agree.

    Aki

    On 2007/11/26, at 11:15, Vincent Coetzee wrote:

    > Dear Aki,
    >
    > When I say the height returned is too small, I mean that if I render
    > the text in that font, in an NSRect whose width is the width I used
    > to measure the height with, and whose height is the returned height,
    > then the last line of text is invariably not visible. In other
    > words, the returned height seems to be approximately 1 line too
    > small. I am not sure this is clear. As far as rendering goes, I have
    > tried rendering by just about every means, and they all render
    > incorrectly i.e. the area they render in is too small. I have set
    > the typesetter behavior to no avail, I attach my revised code (for
    > both measuring and rendering) in which the height is still
    > incorrect. Please let me know if this answers the questions or if
    > you need more info...
    >
    > My class FixedWidthTextItem is a subclass of NSView. The unshown
    > objects first set the desired width for the FixedWidthTextItem
    > by means of the accessor FixedWidthTextItem::setDesiredWidth,
    > thereafter they measure the height of the view using
    > FixedWidthTextItem::desiredHeightForWidth and then they set the
    > frame of the view with an NSRect that is calculated to be
    > someX,someY,desiredWidth,desiredHeightForWidth:desiredWidth.
    > The view is then asked to render itself by the normal
    > setNeedsDisplay: YES mechanism.
    >
    > e.g.
    >
    > desiredWidth <- 200
    > textItem <- FixedWidthTextItem new
    > [textItem setDesiredWidth: desiredWidth]
    > height <- [textItem desiredHeightForWidth: desiredWidth]
    > [textItem setFrame: NSMakeRect(someX,someY,desiredWidth,height)]
    > [textItem setNeedsDisplay: YES]
    >
    >
    > @implementation FixedWidthTextItem
    >
    >
    > - (void) initialize
    > {
    > [super initialize];
    > theDesiredWidth = 10.0f;
    > theTextStorage  = [[NSTextStorage alloc] initWithString: @""];
    > theTextContainer = [[NSTextContainer alloc] initWithContainerSize:
    > NSMakeSize(theDesiredWidth, FLT_MAX)];
    > theLayoutManager = [[NSLayoutManager alloc] init];
    > [theLayoutManager setTypesetter: [NSTypesetter
    > sharedSystemTypesetterForBehavior:
    > NSTypesetterBehavior_10_2_WithCompatibility]];
    > [theLayoutManager setHyphenationFactor: 0.5];
    > [theLayoutManager addTextContainer: theTextContainer];
    > [theTextStorage addLayoutManager: theLayoutManager];
    > [theTextContainer setLineFragmentPadding:2.0];
    > //[theLayoutManager setShowsControlCharacters: YES];
    > //[theLayoutManager setShowsInvisibleCharacters: YES];
    > }
    >
    > - (void) update: (NSString*) aspect with: (id) object from: (id)
    > sender
    > {
    > NSString*    value;
    >
    > if (sender == theStringHolder && [aspect isEqualToString: @"value"])
    > {
    > value = [theStringHolder value];
    > NSAssert(value,@"stringHolder value == nil in update");
    > [theTextStorage replaceCharactersInRange: NSMakeRange(0,
    > [theTextStorage length]) withString: value];
    > [self requestLayout];
    > }
    > }
    >
    > - (void) drawRect: (NSRect) rect
    > {
    > [theTextContainer setContainerSize: [self bounds].size];
    > [theLayoutManager glyphRangeForTextContainer: theTextContainer];
    > [theLayoutManager drawGlyphsForGlyphRange: [theLayoutManager
    > glyphRangeForTextContainer: theTextContainer] atPoint: [self
    > bounds].origin];
    > }
    >
    > - (void) setStringValue: (NSString*) string
    > {
    > [theTextStorage replaceCharactersInRange: NSMakeRange(0,
    > [theTextStorage length]) withString: string];
    > }
    >
    > - (float) desiredWidth
    > {
    > return(theDesiredWidth);
    > }
    >
    > - (void) setDesiredWidth: (float) width
    > {
    > theDesiredWidth = width;
    > }
    >
    > - (void) setStyleValues
    > {
    > NSFont*        font;
    > NSColor*    color;
    >
    > font = [[self styleValueForKey: StyleTextFont] value];
    > NSAssert(font,@"font is nil in FixedWidthTextItem::setStyleValues");
    > [theTextStorage setFont: font];
    > color = [[self styleValueForKey: StyleTextColor] value];
    > NSAssert(color,@"color is nil in
    > FixedWidthTextItem::setStyleValues");
    > [theTextStorage setForegroundColor: color];
    > }
    >
    > - (float) desiredHeightForWidth: (float) width
    > {
    > [self setStyleValues];
    > [theTextContainer setContainerSize: NSMakeSize(width,FLT_MAX)];
    > [theLayoutManager glyphRangeForTextContainer: theTextContainer];
    > return([theLayoutManager usedRectForTextContainer:
    > theTextContainer].size.height);
    > }
    >
    >
    > On 26 Nov 2007, at Monday 26/11/200720:11 , Aki Inoue wrote:
    >> Vincent,
    >>
    >> One thing unclear from your description is how the height returned
    >> from the code snippet is incorrect.  You mentioned the height is
    >> too small.
    >> We need to know how it's small compared to what.  Are you measuring
    >> using the layout manager and rendering with something else ?
    >>
    >> If you're using either NSStringDrawing or NSCell, as Steve
    >> mentioned, it's most likely typesetter behavior mismatch.
    >>
    >> Thanks,
    >>
    >> Aki
    >>
    >> On 2007/11/23, at 1:16, Vincent Coetzee wrote:
    >>
    >>> Dear List
    >>>
    >>> I tried your suggestions, alas, it makes no difference ?
    >>>
    >>> HELP !
    >>>
    >>> Vincent
    >>>
    >>> On 23 Nov 2007, at Friday 23/11/200708:39 , Nygard Steve wrote:
    >>>
    >>>>
    >>>> On Nov 22, 2007, at 5:56 PM, Vincent Coetzee wrote:
    >>>>
    >>>>> I however always end up with the same problem, in that the
    >>>>> height that I calculate for my text (as per the code in the
    >>>>> "Text Layout Programming Guide") is always too small (by about
    >>>>> ~1 line height) . Does anyone have a working solution to this
    >>>>> problem or a more elegant method of solving it ?
    >>>>
    >>>> To calculate a height that matches an NSTextFieldCell, the line
    >>>> fragment padding should be 2 (or 4 for a center alignment).  And
    >>>> the layout manager's typesetter behavior should be
    >>>> NSTypesetterBehavior_10_2_WithCompatibility.
    >>>>
    >>>> --
    >>>> Steve

    >>
previous month november 2007 next month
MTWTFSS
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30    
Go to today