Creating TCanvas to measure text width

I want to measure text width of a TButton so that I can resize it when the text changes. If the button uses ParentFont, I can use the form Canvas to get the width:

int GetButtonTextWidth(TForm* form, TButton* btn)
{
    const int base = form->Canvas->TextWidth(btn->Caption);
    const int margin = 16;
    return base + margin;
}

If the button has different font, for example it is bold, this is not accurate. I tried to create a new TCanvas:

int GetButtonTextWidth(TForm* form, TButton* btn)
{
    std::unique_ptr<TCanvas> canvas(new TCanvas);
    canvas->Font = btn->Font;
    const int base = canvas->TextWidth(btn->Caption);
    const int margin = 16;
    return base + margin;
}

This gives exception: “Canvas does not allow drawing”. How do I create a TCanvas that allows measuring text width and gives accurate results?

Answer

The VCL has a TControlCanvas class for associating a Canvas with a UI control.

int GetButtonTextWidth(TButton* btn)
{
    std::unique_ptr<TControlCanvas> canvas(new TControlCanvas);
    canvas->Control = btn;
    canvas->Font = btn->Font;
    const int base = canvas->TextWidth(btn->Caption);
    const int margin = 16;
    return base + margin;
}