Tom
Tom

Reputation: 857

Why is TextRenderer.MeasureText inaccurate here?

I'm trying to draw a margin at 80 characters in my TextBox subclass. Here is my code:

class FooTextBox : TextBox
{
    ...

    void UpdateMarginPosition()
    {
        using (Graphics graphics = CreateGraphics()) {
            int charWidth = TextRenderer.MeasureText(graphics, "M", Font,
                ClientSize, TextFormatFlags.NoPadding).Width;

            const int LeftMargin = 2;
            margin.Left = charWidth * 80 + LeftMargin;
        }
    }
}

This works fine for certain fonts at certain sizes (e.g., Courier New at size 10):

But with other fonts this turns out to be slightly inaccurate. Here is a screenshot with Consolas at size 12, for example:

As you can see, the line cuts through the 0, when instead it should be to the right of the 0.

EDIT:

I forgot to mention that 'margin' is a WinForms.Label.

Upvotes: 3

Views: 5196

Answers (4)

Tom
Tom

Reputation: 857

Okay, I solved the problem. I had to get the left margin of the TextBox by sending EM_GETMARGINS (rather than just assuming that the left margin is 2, which works for only some fonts/sizes), and I had to do this after base.OnFontChanged(e); in my OnFontChanged override. Thanks, all, for the assistance.

Upvotes: 3

SwDevMan81
SwDevMan81

Reputation: 49978

I would try just setting the Width

Width = charWidth * 80 + LeftMargin;

I created a derived class from TextBox that will auto size the width based on the Text. It works with both fonts you mentioned:

public class MyTextBox : TextBox
{
   public override string Text
   {
      get
      {
         return base.Text;
      }
      set
      {
         base.Text = value;
         UpdateTextboxWidth();
      }
   }

   void UpdateTextboxWidth()
   {
      using (Graphics graphics = CreateGraphics())
      {
         int text_width = TextRenderer.MeasureText(graphics, base.Text, Font,
             ClientSize, TextFormatFlags.NoPadding).Width;

         Width = text_width + Margin.Left + Margin.Right;
      }
   }
}

Note: In my project, the Margin.Left and Margin.Right are set to 3

Upvotes: 0

Michal
Michal

Reputation: 343

But, you should use just fixed length font, because width of char 'I' is different than width of char 'M'. Or if you know string in textbox. You can change code:

int stringWidth = TextRenderer.MeasureText(graphics, this.text, Font,
            ClientSize, TextFormatFlags.NoPadding).Width;

        margin.Left = stringWidth;

Upvotes: 1

leppie
leppie

Reputation: 117220

Use Graphics.MeasureString instead. The result is SizeF and not Size like the TextRenderer's method returns.

Upvotes: 3

Related Questions