Creating the Windows

To set up the basic windows for my application, I wrote a function to call the worker functions that actually create the windows. Because these windows are part of the new Windows 95 common control library, I first had to call InitCommonControls to ensure that COMCTL32.DLL was loaded.

My first control was a multiple-part status bar. The left section of the status bar displays the currently selected city, and the right section displays the number of houses listed for that city. The following code demonstrates how the status bar is implemented:

g_Listing.hWndStatus = CreateStatusWindow ( 
WS_CHILD | WS_BORDER | WS_VISIBLE, // window styles
"", // default window text
hwndParent, // parent window
ID_STATUS); // ID

if (g_Listing.hWndStatus == NULL)
MessageBox (NULL, “Status Bar not created!”, NULL, MB_OK);

// Set the status bar to have two parts.
lpSBParts [0] = (rcl.right - rcl.left) / 2;
lpSBParts [1] = -1;
SendMessage (g_Listing.hWndStatus, SB_SETPARTS, (WPARAM)2,
(LPARAM)&lpSBParts);

Next I created the toolbar, using the TB_ADDBITMAP message to add built-in bitmaps for the standard file and view operations. This code fills out the TBBUTTON structure with the predefined bitmap indexes:

// Toolbar buttons
TBBUTTON tbButtons [] =
{
{STD_FILENEW, IDM_NEW, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0},
{STD_FILEOPEN, IDM_OPEN, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0},
{STD_FILESAVE, IDM_SAVE, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0},
{0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0L, 0},
{VIEW_LARGEICONS, IDM_LARGEICON, TBSTATE_ENABLED, TBSTYLE_BUTTON,
0L, 0},
{VIEW_SMALLICONS, IDM_SMALLICON, TBSTATE_ENABLED, TBSTYLE_BUTTON,
0L, 0},
{VIEW_LIST, IDM_LISTVIEW, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0},
{VIEW_DETAILS, IDM_REPORTVIEW, TBSTATE_ENABLED, TBSTYLE_BUTTON,
0L, 0},
};

This piece of code creates the toolbar, as you saw
earlier, in Chapter 1:

HWND CreateTheToolbar (HWND hWndParent)
{
HWND hWndToolbar;
TBADDBITMAP tb;
int index, stdidx;

hWndToolbar = CreateToolbarEx (hWndParent,
WS_CHILD | WS_BORDER | WS_VISIBLE | WS_CHILD | TBSTYLE_TOOLTIPS,
ID_TOOLBAR, 11, (HINSTANCE)HINST_COMMCTRL, IDB_STD_SMALL_COLOR,
(LPCTBBUTTON)&tbButtons, 4, 0, 0, 100, 30, sizeof (TBBUTTON));

// Add the system-defined view bitmaps.
// The hInst == HINST_COMMCTRL
// The nID == IDB_VIEW_SMALL_COLOR
tb.hInst = HINST_COMMCTRL;
tb.nID = IDB_VIEW_SMALL_COLOR;
stdidx = SendMessage (hWndToolbar, TB_ADDBITMAP, 12, (LPARAM)&tb);

// Update the indexes to the bitmaps.
for (index = 4; index < NUM_BUTTONS; index++)
tbButtons[index].iBitmap += stdidx;

// Add the view buttons.
SendMessage (hWndToolbar, TB_ADDBUTTONS, 4, (LONG) &tbButtons[4]);

return hWndToolbar;
}

As my third step, I created the list view and tree view windows, using helper functions. I made the tree view control one-fourth the width of the window's client area and accounted vertically for both the toolbar and the status bar, as you can see in the following code. (Note that for this sample I hard-coded the values that determine the size of the controls. If I were writing an application for general consumption, I would instead obtain these values by calling GetSystemMetrics.)

HWND TV_CreateTreeView (HWND hWndParent, HINSTANCE hInst,
int NumCities, 
CITYINFO *pCity)
{
HWND hwndTree; // handle to tree view window
RECT rcl; // rectangle for setting size of window
HBITMAP hBmp; // handle to a bitmap
HIMAGELIST hIml; // handle to image list

// Get the size and position of the parent window.
GetClientRect (hWndParent, &rcl);

// Create the tree view window, make it 1/4 the width of the parent
// window, and account for the status bar and the toolbar.
hwndTree = CreateWindowEx (0L,
WC_TREEVIEW, // window class
"", // no default text
WS_VISIBLE | WS_CHILD | WS_BORDER | TVS_HASLINES |
TVS_HASBUTTONS | TVS_LINESATROOT, | WS_EX_CLIENTEDGE,
0, 27, // x, y
(rcl.right - rcl.left) / 4, // cx
rcl.bottom - rcl.top - 45, // cy
hWndParent, // parent
(HMENU)ID_TREEVIEW, // ID
hInst, // instance
NULL);

if (hwndTree == NULL)
{
MessageBox (NULL, “CreateWindow of TreeView failed!”, NULL, MB_OK);
return NULL;
}

// First create the image list you will need.
hIml = ImageList_Create (BITMAP_WIDTH, BITMAP_HEIGHT, FALSE, 2, 10);

if (hIml == NULL)
MessageBox (NULL, “ImageList_Create failed!”, NULL, MB_OK);

// Load the bitmaps and add them to the image list.
hBmp = LoadBitmap (hInst, MAKEINTRESOURCE (FORSALE_BMP));
idxForSale = ImageList_Add (hIml, hBmp, NULL);
hBmp = LoadBitmap (hInst, MAKEINTRESOURCE (CITY_BMP));
idxCity = ImageList_Add (hIml, hBmp, NULL);
hBmp = LoadBitmap (hInst, MAKEINTRESOURCE (SELCITY_BMP));
idxSelect = ImageList_Add (hIml, hBmp, NULL);

// Be sure that all the bitmaps were added.
if (ImageList_GetImageCount (hIml) != 3)
{
MessageBox (NULL, “TreeView image list not loaded!”, NULL, MB_OK);
return FALSE;
}

// Associate the image list with the tree view control.
TreeView_SetImageList (hwndTree, hIml, idxForSale);

// Initialize the tree view control by adding "Houses For Sale."
TV_InitTreeView (hInst, hwndTree);

return hwndTree;
}

I created the list view window, made it three-fourths the width of the parent window's client area, placed it on the right side of the area, and accounted vertically for the toolbar and the status bar, using this code:

HWND LV_CreateListView (HWND hWndParent, HINSTANCE hInst,
int NumHouses,
HOUSEINFO *pHouse)
{
HWND hWndList; // handle to list view window
RECT rcl; // rectangle for setting size of window
HICON hIcon; // handle to an icon
int index; // index used in for loops
HIMAGELIST hSmall, hLarge; // handles to image lists
LV_COLUMN lvC; // list view column structure
char szText [MAX_ITEMLEN]; // place to store some text
int iWidth; // column width

// Get the size and position of the parent window.
GetClientRect (hWndParent, &rcl);

iWidth = (rcl.right - rcl.left) - ((rcl.right - rcl.left) / 4);

// Create the list view window, make it 3/4 the width of the
// parent window, and account for the status bar and the toolbar.
hWndList = CreateWindowEx (0L,
WC_LISTVIEW, // list view class
"", // no default text
WS_VISIBLE | WS_CHILD | WS_BORDER | LVS_REPORT | WS_EX_CLIENTEDGE,
(rcl.right - rcl.left) / 4, 27, // x, y
iWidth, rcl.bottom - rcl.top - 42, // cx, cy
hWndParent, // parent
(HMENU)ID_LISTVIEW, // ID
hInst, // instance
NULL);

if (hWndList == NULL )
return NULL;

// First initialize the image lists you will need.
// Create image lists for the small and the large icons.
// TRUE specifies small icons; FALSE specifies large.
hSmall = ImageList_Create (BITMAP_WIDTH, BITMAP_HEIGHT, TRUE, 1, 0);
hLarge = ImageList_Create (LG_BITMAP_WIDTH, LG_BITMAP_HEIGHT, FALSE,
1, 0);

// Load the icons and add them to the image lists.
hIcon = LoadIcon (hInst, MAKEINTRESOURCE (HOUSE_ICON));
if ((ImageList_AddIcon (hSmall, hIcon) == -1) ||
(ImageList_AddIcon (hLarge, hIcon) == -1))
{
MessageBox (NULL, "ImageList_AddIcon failed!”, NULL, MB_OK);
return NULL;
}

// Associate the image lists with the list view control.
ListView_SetImageList (hWndList, hSmall, LVSIL_SMALL);
ListView_SetImageList (hWndList, hLarge, LVSIL_NORMAL);

// Initialize the LV_COLUMN structure.
// The mask specifies that the fmt, cx, pszText, and iSubitem
// members of the structure are valid.
lvC.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
lvC.fmt = LVCFMT_LEFT; // left-align column
lvC.cx = iWidth / NUM_COLUMNS + 1; // width of column in pixels
lvC.pszText = szText;

// Add the columns.
for (index = 0; index < NUM_COLUMNS; index++)
{
lvC.iSubItem = index;
LoadString (hInst,
IDS_ADDRESS + index,
szText,
sizeof (szText));
if (ListView_InsertColumn (hWndList, index, &lvC) == -1)
return NULL;
}
return hWndList;
}