How to convert DLU into pixels?

Andrew picture Andrew · Jul 29, 2011 · Viewed 7.1k times · Source

Microsoft uses dialog length units (DLU) in their guidelines for UI. How can I convert them into pixels?

As I know, DLU depending on system font size. Can you advise some simple method of such conversion in Delphi for Win32?

Answer

Ian Boyd picture Ian Boyd · May 22, 2012

First we start with what a dialog unit is.

For that i'll quote one of my own un-answered questions:

What's a dialog unit?

A dialog is a unit of measure based on the user's preferred font size. A dialog unit is defined such that the average character is 4 dialog units wide by 8 dialog units high:

enter image description here

This means that dialog units:

  • change with selected font
  • changed with selected DPI setting
  • are not square

i'll also quote another of my own un-answered questions:

You can check the Windows UX Guidelines to see where these measurements come from. The short version is:

  • dlu = dialog unit
  • dlu is based on the font size (items change with user's font size)
  • a horizontal dlu is different from a vertical dlu (dlu's are not square)

This comes from the definition of a dialog unit: the average character is 8dlus high by 4dlus wide.

Georgia 14pt:

enter image description here

If you use a smaller font (i.e. 8pt Tahoma verses 14pt Georgia), the dlus get smaller:

Segoe UI 9pt:

enter image description here

Note: You'll notice that resolution (i.e. dpi) has no impact on the discussion.

So what you need is the average size of a character. Microsoft has an official technique for calculating the average character size.

  • average height:

    GetTextMetrics(dc, {var}textMetrics);
    averageHeight := textMetrics.tmHeight;
    
  • average width:

    Measure the string ABCDEFGHIJLKMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz using GetTextExtentPoint32, and divide by 52:

    GetTextExtentPoint32(dc,
          PChar('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'), 52, Size));
    averageWidth := size.cx / 52.0;
    

So now you need the the size of a horizontal and a vertical dialog units. Remember that a horizontal dialog unit is 1/4 the average character width, and a vertical dlu is 1/8 the average character height:

procedure GetDlus(dc: HDC; out HorizontalDluSize, VerticalDluSize: Real);
var
   tm: TTextMetric; 
   size: TSize;
begin
   GetTextMetric(dc, tm);
   VerticalDluSize := tm.tmHeight / 8.0;

   GetTextExtentPoint32(dc,
         PChar('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'), 52,
         size);
   HorizontalDluSize := size.cx / 52.0;
end;

Note: Any code is released into the public domain. No attribution required.