Calculating height of word-wrapped Label control

M

mike.iles

I've seen a number of questions asking how to calculate the height of
a word-wrapped Label control and I haven't seen an answer that uses
DrawText yet, so I thought I would post.

I needed to dynamically lay out a form at runtime, and the problem I
found was that if I placed a Label on the form then I didn't know what
the height should be to account for word-wrapping.

I used the following imports:

[System.Runtime.InteropServices.DllImport("coredll.dll")]
public static extern IntPtr GetDC(IntPtr hwnd);

[System.Runtime.InteropServices.DllImport("coredll.dll")]
public static extern int ReleaseDC(IntPtr hwnd, IntPtr hdc);

[System.Runtime.InteropServices.DllImport("coredll.dll")]
public static extern IntPtr SelectObject(IntPtr hdc, IntPtr
gdiObject);

private const int DT_TOP = 0x00000000;
private const int DT_LEFT = 0x00000000;
private const int DT_CENTER = 0x00000001;
private const int DT_RIGHT = 0x00000002;
private const int DT_VCENTER = 0x00000004;
private const int DT_BOTTOM = 0x00000008;
private const int DT_WORDBREAK = 0x00000010;
private const int DT_SINGLELINE = 0x00000020;
private const int DT_EXPANDTABS = 0x00000040;
private const int DT_TABSTOP = 0x00000080;
private const int DT_NOCLIP = 0x00000100;
private const int DT_EXTERNALLEADING = 0x00000200;
private const int DT_CALCRECT = 0x00000400;
private const int DT_NOPREFIX = 0x00000800;
private const int DT_INTERNAL = 0x00001000;

public struct RECT
{
public int Left, Top, Right, Bottom;
public RECT(int left, int top, int right, int bottom)
{
this.Left = left;
this.Top = top;
this.Right = right;
this.Bottom = bottom;
}
}

[System.Runtime.InteropServices.DllImport("coredll.dll")]
public static extern int DrawText(IntPtr hdc, string lpString,
int nCount,
ref RECT lpRect, uint uFormat);

Then (paraphrasing roughly), I did this:

Label label = new Label();
label.Text = text;
label.Location = new Point(...);
label.Width = ...;
IntPtr dc = GetDC(IntPtr.Zero);
SelectObject(dc, label.Font.ToHfont());
RECT rect = new RECT(0, 0, label.Width, 0);
DrawText(dc, text, text.Length, ref rect,
DT_CALCRECT | DT_LEFT | DT_WORDBREAK);
ReleaseDC(IntPtr.Zero, dc);
label.Height = rect.Bottom;

Any issues with this approach?

Mike.
 
G

Guest

That's not going to be easy.

You could use Graphics.MeasureString() to work out the width and height in
relation to the width of the control in order to size the control ie:

grfx.MeasureString("A", myFont).Height * 1.1)

The above will calculate the height of A for the myFont object and add in a
1.1 pixel for line spacing. Their might be another way to get line spacing on
devices.

Do the same for the Width so you can figure out how many lines the text will
spawn onto. This will then enable you to set the height of the label.

To get the Graphics object, you can use Control.CreateGraphics() - this is
supported in CF1.0 and CF2.0.

--
Simon Hart
http://simonrhart.blogspot.com


mike.iles said:
I've seen a number of questions asking how to calculate the height of
a word-wrapped Label control and I haven't seen an answer that uses
DrawText yet, so I thought I would post.

I needed to dynamically lay out a form at runtime, and the problem I
found was that if I placed a Label on the form then I didn't know what
the height should be to account for word-wrapping.

I used the following imports:

[System.Runtime.InteropServices.DllImport("coredll.dll")]
public static extern IntPtr GetDC(IntPtr hwnd);

[System.Runtime.InteropServices.DllImport("coredll.dll")]
public static extern int ReleaseDC(IntPtr hwnd, IntPtr hdc);

[System.Runtime.InteropServices.DllImport("coredll.dll")]
public static extern IntPtr SelectObject(IntPtr hdc, IntPtr
gdiObject);

private const int DT_TOP = 0x00000000;
private const int DT_LEFT = 0x00000000;
private const int DT_CENTER = 0x00000001;
private const int DT_RIGHT = 0x00000002;
private const int DT_VCENTER = 0x00000004;
private const int DT_BOTTOM = 0x00000008;
private const int DT_WORDBREAK = 0x00000010;
private const int DT_SINGLELINE = 0x00000020;
private const int DT_EXPANDTABS = 0x00000040;
private const int DT_TABSTOP = 0x00000080;
private const int DT_NOCLIP = 0x00000100;
private const int DT_EXTERNALLEADING = 0x00000200;
private const int DT_CALCRECT = 0x00000400;
private const int DT_NOPREFIX = 0x00000800;
private const int DT_INTERNAL = 0x00001000;

public struct RECT
{
public int Left, Top, Right, Bottom;
public RECT(int left, int top, int right, int bottom)
{
this.Left = left;
this.Top = top;
this.Right = right;
this.Bottom = bottom;
}
}

[System.Runtime.InteropServices.DllImport("coredll.dll")]
public static extern int DrawText(IntPtr hdc, string lpString,
int nCount,
ref RECT lpRect, uint uFormat);

Then (paraphrasing roughly), I did this:

Label label = new Label();
label.Text = text;
label.Location = new Point(...);
label.Width = ...;
IntPtr dc = GetDC(IntPtr.Zero);
SelectObject(dc, label.Font.ToHfont());
RECT rect = new RECT(0, 0, label.Width, 0);
DrawText(dc, text, text.Length, ref rect,
DT_CALCRECT | DT_LEFT | DT_WORDBREAK);
ReleaseDC(IntPtr.Zero, dc);
label.Height = rect.Bottom;

Any issues with this approach?

Mike.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top