KnowledgeBase Archive

An Archive of Early Microsoft KnowledgeBase Articles

View on GitHub

Q140158: HOWTO: How to Place Static Text Labels Over Columns in a List Bo

Article: Q140158
Product(s): Microsoft C Compiler
Version(s): winnt:2.0,2.1,2.2,4.0
Operating System(s): 
Keyword(s): kbcode kbCtrl kbListBox kbMFC kbToolTip KbUIDesign kbVC100 kbVC150 kbVC151 kbVC152 kbVC
Last Modified: 06-MAY-2001

-------------------------------------------------------------------------------
The information in this article applies to:

- The Microsoft Foundation Classes (MFC), used with:
   - Microsoft Visual C++ for Windows, 16-bit edition, versions 1.0, 1.5, 1.51, 1.52 
   - Microsoft Visual C++, 32-bit Editions, versions 2.0, 2.1, 2.2, 4.0 
-------------------------------------------------------------------------------

SUMMARY
=======

When creating Microsoft Foundation Class (MFC) applications that contain dialog
boxes, developers often find it useful to add static text labels to identify
dialog controls. One particular use of static text labels is to identify
contents of columns in a list box. This article describes a technique that
allows placement of these labels regardless of the font used in the dialog box.

MORE INFORMATION
================

Steps to Create Columns in a List Box
-------------------------------------

1. Define the list box with the LBS_USETABSTOPS style by selecting the Use
  Tabstops check box in the Resource Editor.

2. Call the CListBox::SetTabStops() function to set the tab stops. SetTabStops()
  expects tab stops specified using dialog units.

3. Insert tab characters ('\t') into the strings added to the list box. These
  tabs are expanded to form the columns.

How to Place the Static Text Labels
-----------------------------------

To place the static text labels, you need to convert the tab stops to pixel
locations in the client area of the dialog box, and move the static text labels
to the appropriate location.

For this example, you need only be concerned with the horizontal position of each
column. The horizontal position is calculated according to the following
formula:

     xpos = (avg_char_width * tab_stop_position) / 4.

The factor of 4 is required because each character is four dialog units wide.
Dialog units were designed around the System font, so other fonts may not
provide exact results. The accuracy depends on the value of avg_char_width in
the previous formula.

Windows rounds up when it calculates tab stop positions, so the previous formula
needs the following modification to force it to round up too:

     xpos = (avg_char_width * tab_stop_position + 2) / 4

For more information on how to calculate dialog units for all possible fonts,
please see the following article in the Microsoft Knowledge Base:

  Q125681 How to Calculate Dialog Base Units with Non-System-Based Font

Article Q125681 describes the following technique.

NOTE: If the font is a fixed-width font, you could just use GetTextMetrics to
obtain the average character width of the font, but that will only be accurate
for fixed-width fonts, so the general-purpose technique, which works for
fixed-width and variable-width fonts, is used below.

Use the following steps to create a list box with columns and static text labels
placed above each column:

1. Define a dialog template with a list box (m_listbox) and one or more static
  text labels (m_text1 and m_text2).

2. In the derived class for the dialog box, define a handler for OnInitDialog().
  Modify the OnInitDialog to provide functionality similar to that provided by
  the following code sample.

Sample Code
-----------

  BOOL CMyDlg::OnInitDialog()
  {
      CDialog::OnInitDialog();

      // Set tabstops at 100 and 200 dialog units
      int tab_stop[2] = {100, 200};
      VERIFY(m_listbox.SetTabStops(2, tab_stop));

      m_listbox.AddString("String1\tString2\tString3");

      CDC *pDC = m_listbox.GetDC();

      // Get a handle to the font used in the list box
      CFont *pFont;
      pFont = m_listbox.GetFont();

      // Select the list box font into the temporary DC
      CFont *pFontOld = pDC->SelectObject(pFont);

      // Call GetTextExtentPoint to compute the string dimensions
      // NOTE: use GetTextExtentPoint32 in Win32 for better results
      CSize size;
      GetTextExtentPoint(pDC->GetSafeHdc(),
        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
        52, &size);

      int avg_char_width = (size.cx/26 +1)/2;

      // Restore Original Font
      pDC->SelectObject(pFontOld);

      m_listbox.ReleaseDC(pDC);

      // Convert DLU to pixel positions
      int xPos1 = (tab_stop[0] * avg_char_width + 2)/4;
      int xPos2 = (tab_stop[1] * avg_char_width + 2)/4;

      // Only concerned about x right now, so y is set to 0
      CPoint mypt1(xPos1, 0);
      CPoint mypt2(xPos2, 0);

      // Convert the coordinates to be relative to the list box
      m_listbox.ClientToScreen(&mypt1);
      m_listbox.ClientToScreen(&mypt2);

      // Convert the screen coordinates back to coordinates that
      // are relative to the dialog box
      ScreenToClient(&mypt1);
      ScreenToClient(&mypt2);

      // Get the current position / width of the text labels
      CRect rect1,rect2;
      m_text1.GetWindowRect(&rect1);
      m_text2.GetWindowRect(&rect2);

      // Convert the rectangles to be relative to the dialog box
      ScreenToClient(&rect1);
      ScreenToClient(&rect2);

      // Move the text labels over the columns
      m_text1.MoveWindow(mypt1.x, rect1.top,
                         rect1.Width(),rect1.Height());
      m_text2.MoveWindow(mypt2.x, rect2.top,
                         rect2.Width(),rect2.Height());

      return TRUE;
  }

Additional query words: kbinf 1.50 1.51 1.52 2.00 2.10 2.20 4.00 1.00 2.5 2.50 2.51 2.52 3.0 3.00 3.1 3.10 3.2 3.20

======================================================================
Keywords          : kbcode kbCtrl kbListBox kbMFC kbToolTip KbUIDesign kbVC100 kbVC150 kbVC151 kbVC152 kbVC200 kbVC210 kbGrpDSMFCATL kbNoUpdate 
Technology        : kbAudDeveloper kbMFC
Version           : winnt:2.0,2.1,2.2,4.0
Issue type        : kbhowto

=============================================================================

THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Copyright Microsoft Corporation 1986-2002.