c++firemonkeyc++builder-xe8tlabel

Firemonkey: Shrink text font to fit in TLabel


I am attempting to lower the font size of a TLabel if its text is to large to fit in the confines of the label. I didn't see any properties I could set on the label to achieve this, so I have tried writing my own method. My method works by using TCanvas.TextWidth to measure the width of the text in a label, and shrink the font until the width of the text fits within the width of the label.

void __fastcall ShrinkFontToFitLabel( TCanvas * Canvas, TLabel * Label )
{
    float NewFontSize = Label->Font->Size;

    Canvas->Font->Family = Label->Font->Family;
    Canvas->Font->Size = NewFontSize;

    while( Canvas->TextWidth( Label->Text ) > Label->Width && NewFontSize > MinimumFontSize )
    {
        NewFontSize -= FontSizeDecrement;
        Canvas->Font->Size = NewFontSize;
    }

    Label->Font->Size = NewFontSize;
}

This works some of the time, however other times it does not shrink the font near enough. It seems as if the value I get from calling Canvas->TextWidth is a lot of times, much smaller than the number of pixels wide the label actually needs to be in order to fit the text.

Am I using Canvas->TextWidth incorrectly? Is there a better way to calculate the width of a string, or to re-size the font of a TLabel so its text fits within its demensions?

Edit:
In this case, I am passing in to my function, the TCanvas that my label is sitting in. I have tried using that TCanvas as well as Label->Canvas. Both give me the same number for text width, and both are short of the actual value in pixels needed to display the whole string.


Solution

  • The following code is taken from code that works in an FMX application, modified slightly to remove arrays that are being iterated through and declaring a variable locally to the function. It is being run in a TForm method. Canvas here is the Form's Canvas. You can see that I'm using "- 35" at one point - this might be because the numbers weren't quite right.

    double InitialFontSize = 30;    
    Canvas->Font->Size = InitialFontSize;
    StoryHeadlineLabel->Font->Size = InitialFontSize;
    bool fits = false;
    do
    {
        double widthA = Canvas->TextWidth (StoryHeadlineLabel->Text);
        if (widthA > StoryHeadlineLabel->Width - 35)
        {
            StoryHeadlineLabel->Font->Size --;
            Canvas->Font->Size --;
        }
        else
            fits = true;
        if (StoryHeadlineLabel->Font->Size < 6)
            fits = true;
    } while (!fits);