HomeC&C++WainTutorialsSamplesTip&TrickTools


Now we will replace the edit box used to show the result with a list-box.
To create the window is the usual call to CreateWindow:
      CreateWindowEx(WS_EX_CLIENTEDGE,
                     "LISTBOX",
                     "0",
                     WS_CHILD | WS_VISIBLE | WS_TABSTOP |
                     WS_VSCROLL | WS_HSCROLL,
                     5, 65, 120, 80,
                     hwndDlg,
                     (HMENU )ResultListBoxId,
                     InstanceHandle,
                     0);
To add a line to the listbox we send a LB_ADDSTRING message to it. For this we need a const char *. We will show both the expression and the result on a single line, so we change the code for the button event to:
   case WM_COMMAND:
      if(HIWORD(wParam) == BN_CLICKED &&
         LOWORD(wParam) == ButtonId)
      {
         int First =
            GetDlgItemInt(hwndDlg, FirstEditId, 0, FALSE);
         int Second =
            GetDlgItemInt(hwndDlg, SecondEditId, 0, FALSE);
         int Result;
         std::string ResultString;
         if(IsDlgButtonChecked(hwndDlg, AddRadioId))
         {
            Result = First + Second;
            ResultString = ToString(First) +
                           " + " +
                           ToString(Second) +
                           " = " +
                           ToString(Result);
         }
         else
         {
            Result = First - Second;
            ResultString = ToString(First) +
                           " - " +
                           ToString(Second) +
                           " = " +
                           ToString(Result);
         }
         AddListText(hwndDlg, ResultString.c_str());
      }
      break;
ToString is a function I made on the C++ page on 07-01-2005, it simply converts a number into a std::string.
AddListText is a function we will use to display the string, as there is a bit more to it than just sending a message.
The start of AddListText could look like this:
void AddListText(HWND aMainWnd, const char *aMsg)
{
   static int MaxWidth;
   HWND List = GetDlgItem(aMainWnd, ResultListBoxId);
   int idx = SendMessage(List, LB_ADDSTRING, 0, (LPARAM )aMsg);
   SendMessage(List, LB_SETCARETINDEX, idx, 0);
This will get the HWND for the listbox and add the string to listbox. When we add the string SendMessage will return the index of the new item. This is handy as we want to make sure that this item is visible. We do that by sending the LB_SETCARETINDEX message to the listbox, to tell it that the item must be selected and thus visible. If we didn't do that the item would just be added to the end and we would have to scroll down to see it, if there are more items than lines in the listbox.
If we add more items than there are lines in the box, it will add a vertical scrollbar by itself. But the listbox can't figure out if it needs a horizontal scrollbar, so we have to help it.
We have to tell it how wide the text in the list box is. To do that we will use GetTextExtentPoint32, which needs a device context with the right font selected:
   HDC dc = GetDC(List);
   HFONT Font = (HFONT )SendMessage(aMainWnd, WM_GETFONT, 0, 0);
   HFONT OldFont = (HFONT )SelectObject(dc, Font);
   SIZE TextSize;
   GetTextExtentPoint32(dc, aMsg, strlen(aMsg), &TextSize);
   TextSize.cx += 10;
Now TextSize.cx is the width of the new line, we have to check if the new line is wider than any other line in the box, if it is will tell it to the listbox:
   if(TextSize.cx > MaxWidth)
   {
      MaxWidth = TextSize.cx;
      SendMessage(List, LB_SETHORIZONTALEXTENT, MaxWidth, 0);
   }
With a bit cleanup we are done:
   SelectObject(dc, OldFont);
   ReleaseDC(List, dc);
The complete code for the application can be found here.