Figure 2 VListVw.c
/**************************************************************************
File: VListVw.c
**************************************************************************/
·
·
·
/**************************************************************************
Global Variables
**************************************************************************/
HANDLE g_hInst;
TCHAR g_szClassName[] = TEXT("VListVwClass");
#define ITEM_COUNT 100000000
#define IDC_LISTVIEW 2000
/******************************************************************************
WinMain
******************************************************************************/
int PASCAL WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
INITCOMMONCONTROLSEX iccex;
//required to use the common controls
iccex.dwSize = sizeof(INITCOMMONCONTROLSEX);
iccex.dwICC = ICC_LISTVIEW_CLASSES;
InitCommonControlsEx(&iccex);
g_hInst = hInstance;
if(!hPrevInstance)
if(!InitApplication(hInstance))
return FALSE;
/* Perform initializations that apply to a specific instance */
if (!InitInstance(hInstance, nCmdShow))
return FALSE;
/* Acquire and dispatch messages until a WM_QUIT uMessage is received. */
while(GetMessage( &msg, NULL, 0x00, 0x00))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
·
·
·
/******************************************************************************
CreateListView
******************************************************************************/
HWND CreateListView(HINSTANCE hInstance, HWND hwndParent)
{
DWORD dwStyle;
HWND hwndListView;
HIMAGELIST himlSmall;
HIMAGELIST himlLarge;
BOOL bSuccess = TRUE;
dwStyle = WS_TABSTOP |
WS_CHILD |
WS_BORDER |
WS_VISIBLE |
LVS_AUTOARRANGE |
LVS_REPORT |
LVS_OWNERDATA;
hwndListView = CreateWindowEx( WS_EX_CLIENTEDGE, // ex style
WC_LISTVIEW, // class name defined in commctrl.h
NULL, // window text
dwStyle, // style
0, // x position
0, // y position
0, // width
0, // height
hwndParent, // parent
(HMENU)IDC_LISTVIEW, // ID
g_hInst, // instance
NULL); // no extra data
if(!hwndListView)
return NULL;
ResizeListView(hwndListView, hwndParent);
//set the image lists
himlSmall = ImageList_Create(16, 16, ILC_COLORDDB | ILC_MASK, 1, 0);
himlLarge = ImageList_Create(32, 32, ILC_COLORDDB | ILC_MASK, 1, 0);
if (himlSmall && himlLarge)
{
HICON hIcon;
//set up the small image list
hIcon = LoadImage(g_hInst, MAKEINTRESOURCE(IDI_DISK), IMAGE_ICON, 16, 16,
LR_DEFAULTCOLOR);
ImageList_AddIcon(himlSmall, hIcon);
//set up the large image list
hIcon = LoadIcon(g_hInst, MAKEINTRESOURCE(IDI_DISK));
ImageList_AddIcon(himlLarge, hIcon);
SendMessage(hwndListView, LVM_SETIMAGELIST, (WPARAM)LVSIL_SMALL,
(LPARAM)himlSmall);
SendMessage(hwndListView, LVM_SETIMAGELIST, (WPARAM)LVSIL_NORMAL,
(LPARAM)himlLarge);
}
return hwndListView;
}
/******************************************************************************
ResizeListView
******************************************************************************/
void ResizeListView(HWND hwndListView, HWND hwndParent)
{
RECT rc;
GetClientRect(hwndParent, &rc);
MoveWindow( hwndListView,
rc.left,
rc.top,
rc.right - rc.left,
rc.bottom - rc.top,
TRUE);
}
/******************************************************************************
InitListView
******************************************************************************/
BOOL InitListView(HWND hwndListView)
{
LV_COLUMN lvColumn;
int i;
TCHAR szString[5][20] = { TEXT("Main Column"),
TEXT("Column 1"),
TEXT("Column 2"),
TEXT("Column 3"),
TEXT("Column 4")};
//initialize the columns
lvColumn.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
lvColumn.fmt = LVCFMT_LEFT;
lvColumn.cx = 120;
for(i = 0; i < 5; i++)
{
lvColumn.pszText = szString[i];
SendMessage(hwndListView, LVM_INSERTCOLUMN, (WPARAM)i, (LPARAM)&lvColumn);
}
InsertListViewItems(hwndListView);
return TRUE;
}
/******************************************************************************
InsertListViewItems
******************************************************************************/
BOOL InsertListViewItems(HWND hwndListView)
{
//empty the list
SendMessage(hwndListView, LVM_DELETEALLITEMS, 0, 0);
//set the number of items in the list
SendMessage(hwndListView, LVM_SETITEMCOUNT, (WPARAM)ITEM_COUNT,
(LPARAM)LVSICF_NOINVALIDATEALL);
return TRUE;
}
/**************************************************************************
ListViewNotify()
**************************************************************************/
LRESULT ListViewNotify(HWND hWnd, LPARAM lParam)
{
LPNMHDR lpnmh = (LPNMHDR) lParam;
HWND hwndListView = GetDlgItem(hWnd, IDC_LISTVIEW);
switch(lpnmh->code)
{
case LVN_GETDISPINFO:
{
LV_DISPINFO *lpdi = (LV_DISPINFO *)lParam;
TCHAR szString[MAX_PATH];
if(lpdi->item.iSubItem)
{
if(lpdi->item.mask & LVIF_TEXT)
{
wsprintf(szString, TEXT("Item %d - Column %d"), lpdi->item.iItem + 1,
lpdi->item.iSubItem);
lstrcpyn(lpdi->item.pszText, szString, lpdi->item.cchTextMax);
}
}
else
{
if(lpdi->item.mask & LVIF_TEXT)
{
wsprintf(szString, TEXT("Item %d"), lpdi->item.iItem + 1);
lstrcpyn(lpdi->item.pszText, szString, lpdi->item.cchTextMax);
}
if(lpdi->item.mask & LVIF_IMAGE)
{
lpdi->item.iImage = 0;
}
if(lpdi->item.mask & LVIF_INDENT)
{
lpdi->item.iIndent = 0;
}
}
}
return 0;
case LVN_ODCACHEHINT:
{
LPNMLVCACHEHINT lpCacheHint = (LPNMLVCACHEHINT)lParam;
/*
This sample doesn't use this notification, but this is sent when the
ListView is about to ask for a range of items. On this notification,
you should load the specified items into your local cache. It is still
possible to get an LVN_GETDISPINFO for an item that has not been cached,
therefore, your application must take into account the chance of this
occurring.
*/
}
return 0;
case LVN_ODFINDITEM:
{
LPNMLVFINDITEM lpFindItem = (LPNMLVFINDITEM)lParam;
/*
This sample doesn't use this notification, but this is sent when the
ListView needs a particular item. Return -1 if the item is not found.
*/
}
return 0;
}
return 0;
}
/**************************************************************************
SwitchView()
**************************************************************************/
void SwitchView(HWND hwndListView, DWORD dwView)
{
DWORD dwStyle = GetWindowLong(hwndListView, GWL_STYLE);
SetWindowLong(hwndListView, GWL_STYLE, (dwStyle & ~LVS_TYPEMASK) | dwView);
ResizeListView(hwndListView, GetParent(hwndListView));
}
·
·
·
/**************************************************************************
HandleContextMenu()
**************************************************************************/
BOOL HandleContextMenu( HWND hWnd,
WPARAM wParam,
LPARAM lParam)
{
HMENU hMenuLoad,
hMenu;
if((HWND)wParam != GetDlgItem(hWnd, IDC_LISTVIEW))
return FALSE;
hMenuLoad = LoadMenu(g_hInst, MAKEINTRESOURCE(IDM_CONTEXT_MENU));
hMenu = GetSubMenu(hMenuLoad, 0);
UpdateMenu(GetDlgItem(hWnd, IDC_LISTVIEW), hMenu);
TrackPopupMenu( hMenu,
TPM_LEFTALIGN | TPM_RIGHTBUTTON,
LOWORD(lParam),
HIWORD(lParam),
0,
hWnd,
NULL);
DestroyMenu(hMenuLoad);
return TRUE;
}
·
·
·
Figure 3 ListView Extended Styles
Style Flag | Description |
LVS_EX_CHECKBOXES | The control supplies check boxes for each item. You can retrieve the state of thecheck box by using the ListView_GetCheckState macro. |
LVS_EX_FULLROWSELECT | When an item is selected, all of its subitems are also displayed as selected. Clicking on any subitem will select the entire row. This extended style is only effective in conjunction with the LVS_REPORT style. |
LVS_EX_GRIDLINES | Dashed gridlines are displayed around all items and subitems. This extended style is only effective in conjunction with the LVS_REPORT style. |
LVS_EX_HEADERDRAGDROP | Enables drag-and-drop re-ordering of the columns in the ListView. This extended style is only effective in conjunction with the LVS_REPORT style. |
LVS_EX_SUBITEMIMAGES | Allows images to be displayed for subitems. This extended style is only effective in conjunction with the LVS_REPORT style. |
LVS_EX_TRACKSELECT | Enables hot tracking of items in a ListView control. Hot Tracking, also known as Hover Selection, means that an item is automatically selected when the mouse pointer is over it for more than 1 second. This style applies to all styles of the ListView control. |
Figure 4 New ListView Messages
Message | Description | wParam | lParam | Return Value |
LVM_GETEXTENDEDLISTVIEWSTYLES | Retrieves the extended ListView styles. | Not used. | Not used. | A DWORD value which contains the extended style flags currently set in the control. |
LVM_SETEXTENDEDLISTVIEWSTYLES | Sets the extended ListView styles. | Not used. | A DWORD value which contains the extended style flags to be set. | Not used. |
LVM_GETCOLUMNORDERARRAY | Retrieves the current column-ordering information. | An integer value that indicates the number of columns in the control. | A pointer to an array of integers that receives the column-ordering information. The ordering information is given as the columns are displayed left-to-right. This array must be at least <number of columns> * sizeof(int). | A BOOL value indicating the success or failure of the message. |
LVM_SETCOLUMNORDERARRAY | Sets the column-ordering information. | An integer value indicating the number of elements pointed to by the lParam. | A pointer to an array of integers that contains the new column-ordering information. The ordering information is given as the columns are displayed left-to-right. | A BOOL value indicating the success or failure of the message. |
LVM_GETSUBITEMRECT | Retrieves the bounding rectangle of an item's subitem. | Index of the subitem's parent item. | Pointer to a RECT structure. Before sending the message, the one-based index of the subitem of interest is placed in the top member of the RECT structure and one of the following flags is placed in the left member of the RECT structure. After themessage is sent, the RECT structure will contain the desired information. | A BOOL value indicating the success or failure of the message. |
LVM_SUBITEMHITTEST | Determines what item or subitem, if any, is at the given point. | Not used. | Pointer to an LVHITTESTINFO structure.Before sending the message, the POINT member of the LVHITTESTINFO structure must contain the client coordinates of the point to be tested. After sending the message, if the hit test is successful and the point falls on an item, the iItem member of the LVHITTESTINFO structure will contain the index of the item on which the point falls. If the point falls on a subitem, the iSubItem member will contain the one-based index of the subitem on which the point falls andthe the iItem member will contain the subitem's parent index. | The index of the item or subitem if the hit test is successful. If the hit test fails, the subitem return value will be -1. |
LVM_SETICONSPACING | Sets the icon spacing for a ListView which has the LVS_ICON style. | Not used. | A DWORD value that contains the new horizontal spacing (cx) in the low word and the new vertical spacing (cy) in the high word. | A DWORD value that contains the previous icon spacing. The previous horizontal spacing (cx) is in the low word and the previous vertical spacing (cy) is in the high word. |
Figure 6 ListView.c
/**************************************************************************
File: ListView.c
**************************************************************************/
·
·
·
/**************************************************************************
Global Variables
**************************************************************************/
HANDLE g_hInst;
TCHAR szClassName[] = TEXT("ListViewClass");
BOOL g_bCustomDraw;
#define IDC_LISTVIEW 1000
/******************************************************************************
WinMain
******************************************************************************/
int PASCAL WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
INITCOMMONCONTROLSEX iccex;
//required to use the common controls
iccex.dwSize = sizeof(INITCOMMONCONTROLSEX);
iccex.dwICC = ICC_LISTVIEW_CLASSES;
InitCommonControlsEx(&iccex);
g_hInst = hInstance;
if(!hPrevInstance)
if(!InitApplication(hInstance))
return FALSE;
/* Perform initializations that apply to a specific instance */
if (!InitInstance(hInstance, nCmdShow))
return FALSE;
/* Acquire and dispatch messages until a WM_QUIT uMessage is received. */
while(GetMessage(&msg, NULL, 0x00, 0x00))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
·
·
·
/******************************************************************************
MainWndProc
******************************************************************************/
LRESULT CALLBACK MainWndProc( HWND hWnd,
UINT uMessage,
WPARAM wParam,
LPARAM lParam)
{
switch (uMessage)
{
case WM_CREATE:
{
HWND hwndListView;
g_bCustomDraw = FALSE;
// create the TreeView control
hwndListView = CreateListView(g_hInst, hWnd);
//initialize the TreeView control
InitListView(hwndListView);
}
break;
case WM_NOTIFY:
return ListViewNotify(hWnd, lParam);
case WM_SIZE:
ResizeListView(GetDlgItem(hWnd, IDC_LISTVIEW), hWnd);
break;
case WM_INITMENUPOPUP:
UpdateMenu(GetDlgItem(hWnd, IDC_LISTVIEW), GetMenu(hWnd));
break;
case WM_CONTEXTMENU:
if(HandleContextMenu(hWnd, wParam, lParam))
return FALSE;
break;
case WM_COMMAND:
return HandleCommand(hWnd, wParam, lParam);
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
break;
}
return DefWindowProc(hWnd, uMessage, wParam, lParam);
}
/******************************************************************************
AboutDlgProc
******************************************************************************/
BOOL CALLBACK AboutDlgProc( HWND hDlg,
UINT uMessage,
WPARAM wParam,
LPARAM lParam)
{
switch (uMessage)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
switch(wParam)
{
case IDOK:
EndDialog(hDlg, IDOK);
break;
case IDCANCEL:
EndDialog(hDlg, IDOK);
break;
}
return TRUE;
}
return FALSE;
}
/******************************************************************************
CreateListView
******************************************************************************/
HWND CreateListView(HINSTANCE hInstance, HWND hwndParent)
{
DWORD dwStyle;
HWND hwndListView;
HIMAGELIST himlSmall;
HIMAGELIST himlLarge;
SHFILEINFO sfi;
BOOL bSuccess = TRUE;
dwStyle = WS_TABSTOP |
WS_CHILD |
WS_BORDER |
LVS_AUTOARRANGE |
LVS_REPORT |
LVS_EDITLABELS |
LVS_SHAREIMAGELISTS |
WS_VISIBLE;
hwndListView = CreateWindowEx( WS_EX_CLIENTEDGE, // ex style
WC_LISTVIEW, // class name defined in commctrl.h
NULL, // window text
dwStyle, // style
0, // x position
0, // y position
0, // width
0, // height
hwndParent, // parent
(HMENU)IDC_LISTVIEW, // ID
g_hInst, // instance
NULL); // no extra data
if(!hwndListView)
return NULL;
ResizeListView(hwndListView, hwndParent);
//set the large and small icon image lists
himlSmall = (HIMAGELIST)SHGetFileInfo( TEXT("C:\\"),
0,
&sfi,
sizeof(SHFILEINFO),
SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
himlLarge = (HIMAGELIST)SHGetFileInfo( TEXT("C:\\"),
0,
&sfi,
sizeof(SHFILEINFO),
SHGFI_SYSICONINDEX | SHGFI_LARGEICON);
if (himlSmall && himlLarge)
{
SendMessage(hwndListView, LVM_SETIMAGELIST, (WPARAM)LVSIL_SMALL,
(LPARAM)himlSmall);
SendMessage(hwndListView, LVM_SETIMAGELIST, (WPARAM)LVSIL_NORMAL,
(LPARAM)himlLarge);
}
return hwndListView;
}
/******************************************************************************
ResizeListView
******************************************************************************/
void ResizeListView(HWND hwndListView, HWND hwndParent)
{
RECT rc;
GetClientRect(hwndParent, &rc);
MoveWindow( hwndListView,
rc.left,
rc.top,
rc.right - rc.left,
rc.bottom - rc.top,
TRUE);
}
/******************************************************************************
InitListView
******************************************************************************/
BOOL InitListView(HWND hwndListView)
{
LV_COLUMN lvColumn;
int i;
TCHAR szString[5][20] = { TEXT("Image Number"),
TEXT("Left"),
TEXT("Top"),
TEXT("Right"),
TEXT("Bottom")};
//initialize the columns
lvColumn.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
lvColumn.fmt = LVCFMT_LEFT;
lvColumn.cx = 100;
for(i = 0; i < 5; i++)
{
//make the secondary columns smaller
if(i)
lvColumn.cx = 50;
lvColumn.pszText = szString[i];
SendMessage(hwndListView, LVM_INSERTCOLUMN, (WPARAM)i, (LPARAM)&lvColumn);
}
InsertListViewItems(hwndListView);
return TRUE;
}
/******************************************************************************
InsertListViewItems
******************************************************************************/
BOOL InsertListViewItems(HWND hwndListView)
{
LV_ITEM lvItem;
int i,
nIndex,
nImageCount;
TCHAR szString[MAX_PATH];
HIMAGELIST himl;
IMAGEINFO ii;
SendMessage(hwndListView, WM_SETREDRAW, FALSE, 0);
//empty the list
SendMessage(hwndListView, LVM_DELETEALLITEMS, 0, 0);
//get the number of icons in the image list
himl = (HIMAGELIST)SendMessage(hwndListView, LVM_GETIMAGELIST,
(WPARAM)LVSIL_SMALL, 0);
nImageCount = ImageList_GetImageCount(himl);
for(i = 0; i < nImageCount; i++)
{
wsprintf(szString, TEXT("Image #%d"), i);
//fill in the LV_ITEM structure for the first item
lvItem.mask = LVIF_TEXT | LVIF_IMAGE;
lvItem.pszText = szString;
lvItem.iImage = i;
lvItem.iItem = SendMessage(hwndListView, LVM_GETITEMCOUNT, 0, 0);
lvItem.iSubItem = 0;
//add the item - get the index in case the ListView is sorted
nIndex = SendMessage(hwndListView, LVM_INSERTITEM, (WPARAM)0, (LPARAM)&lvItem);
//set the text and images for the sub-items
ImageList_GetImageInfo(himl, i, &ii);
wsprintf(szString, TEXT("%d"), ii.rcImage.left);
lvItem.iSubItem = 1;
SendMessage(hwndListView, LVM_SETITEM, 0, (LPARAM)&lvItem);
wsprintf(szString, TEXT("%d"), ii.rcImage.top);
lvItem.iSubItem = 2;
SendMessage(hwndListView, LVM_SETITEM, 0, (LPARAM)&lvItem);
wsprintf(szString, TEXT("%d"), ii.rcImage.right);
lvItem.iSubItem = 3;
SendMessage(hwndListView, LVM_SETITEM, 0, (LPARAM)&lvItem);
wsprintf(szString, TEXT("%d"), ii.rcImage.bottom);
lvItem.iSubItem = 4;
SendMessage(hwndListView, LVM_SETITEM, 0, (LPARAM)&lvItem);
}
SendMessage(hwndListView, WM_SETREDRAW, TRUE, 0);
UpdateWindow(hwndListView);
return TRUE;
}
/**************************************************************************
ListViewNotify()
**************************************************************************/
LRESULT ListViewNotify(HWND hWnd, LPARAM lParam)
{
LPNMHDR lpnmh = (LPNMHDR) lParam;
HWND hwndListView = GetDlgItem(hWnd, IDC_LISTVIEW);
switch(lpnmh->code)
{
case NM_CUSTOMDRAW:
{
LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)lParam;
/*
CDDS_PREPAINT is sent when the control is about to paint itself. You
implement custom draw by returning the proper value to this
notification.
*/
if(lplvcd->nmcd.dwDrawStage == CDDS_PREPAINT)
{
if(g_bCustomDraw)
{
//tell the control we want pre-paint notifications for each item
return CDRF_NOTIFYITEMDRAW;
}
//tell the control that we won't be doing any custom drawing
return CDRF_DODEFAULT;
}
/*
CDDS_ITEMPREPAINT is sent when the control is about to paint an item.
You will only get these if you returned CDRF_NOTIFYITEMDRAW in
response to CDDS_PREPAINT.
*/
if(lplvcd->nmcd.dwDrawStage == CDDS_ITEMPREPAINT)
{
LRESULT lReturn = CDRF_DODEFAULT;
/*
For the ListView, the index of the item being drawn is stored in the
dwItemSpec member of the NMCUSTOMDRAW structure. In this example, only
the odd items will be drawn using the bold font.
*/
if(lplvcd->nmcd.dwItemSpec & 0x01)
{
HFONT hFont;
LOGFONT lf;
//get the existing font
hFont = (HFONT)SendMessage(hwndListView, WM_GETFONT, 0, 0);
//now get the font's information
GetObject(hFont, sizeof(lf), &lf);
//make this font bold
lf.lfWeight = FW_BOLD;
//create the new font
hFont = CreateFontIndirect(&lf);
/*
To change the font, just select the desired font into the HDC
provided.
*/
SelectObject(lplvcd->nmcd.hdc, hFont);
/*
To change the text and background colors in a ListView, set the
clrText and clrTextBk members of the NMLVCUSTOMDRAW structure to
the desired color. This is different than most other controls that
support custom draw. To change the text and background colors in
the others, you just call SetTextColor and SetBkColor on the HDC
provided.
*/
lplvcd->clrText = RGB(255, 0, 0);
lplvcd->clrTextBk = RGB(255, 255, 255);
/*
If you change the font, return CDRF_NEWFONT so the control can
recalculate the extent of the text. Returning CDRF_NOTIFYPOSTPAINT
causes the control to send us notifications with CDDS_ITEMPOSTPAINT.
*/
lReturn = CDRF_NEWFONT | CDRF_NOTIFYPOSTPAINT;
}
else
{
lplvcd->clrText = RGB(0, 0, 255);
lplvcd->clrTextBk = RGB(255, 255, 255);
}
return lReturn;
}
if(lplvcd->nmcd.dwDrawStage == CDDS_ITEMPOSTPAINT)
{
HFONT hFont = GetStockObject(DEFAULT_GUI_FONT);
//clean up stuff here
hFont = SelectObject(lplvcd->nmcd.hdc, hFont);
DeleteFont(hFont);
return CDRF_DODEFAULT;
}
}
return CDRF_DODEFAULT;
}
return 0;
}
/**************************************************************************
SwitchView()
**************************************************************************/
void SwitchView(HWND hwndListView, DWORD dwView)
{
DWORD dwStyle = GetWindowLong(hwndListView, GWL_STYLE);
SetWindowLong(hwndListView, GWL_STYLE, (dwStyle & ~LVS_TYPEMASK) | dwView);
ResizeListView(hwndListView, GetParent(hwndListView));
}
/**************************************************************************
AddExStyle()
**************************************************************************/
void AddExStyle(HWND hwndListView, DWORD dwNewStyle)
{
DWORD dwStyle = SendMessage(hwndListView, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
dwStyle |= dwNewStyle;
SendMessage(hwndListView, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, dwStyle);
}
/**************************************************************************
RemoveExStyle()
**************************************************************************/
void RemoveExStyle(HWND hwndListView, DWORD dwNewStyle)
{
DWORD dwStyle = SendMessage(hwndListView, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
dwStyle &= ~dwNewStyle;
SendMessage(hwndListView, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, dwStyle);
}
/**************************************************************************
HandleCommand()
**************************************************************************/
LRESULT HandleCommand( HWND hWnd,
WPARAM wParam,
LPARAM lParam)
{
switch (GET_WM_COMMAND_ID(wParam, lParam))
{
case IDM_LARGEICONS:
SwitchView(GetDlgItem(hWnd, IDC_LISTVIEW), LVS_ICON);
break;
case IDM_SMALLICONS:
SwitchView(GetDlgItem(hWnd, IDC_LISTVIEW), LVS_SMALLICON);
break;
case IDM_LIST:
SwitchView(GetDlgItem(hWnd, IDC_LISTVIEW), LVS_LIST);
break;
case IDM_REPORT:
SwitchView(GetDlgItem(hWnd, IDC_LISTVIEW), LVS_REPORT);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
case IDM_ABOUT:
DialogBox(g_hInst, MAKEINTRESOURCE(IDD_ABOUT), hWnd, AboutDlgProc);
break;
case IDM_INDENT:
{
LV_ITEM lvItem;
int i,
nItemCount;
ZeroMemory(&lvItem, sizeof(lvItem));
nItemCount = (int)SendDlgItemMessage(hWnd, IDC_LISTVIEW, LVM_GETITEMCOUNT,
0, 0);
//run through the list, indenting the selected items
for(i = 0; i < nItemCount; i++)
{
lvItem.mask = LVIF_STATE | LVIF_INDENT;
lvItem.iItem = i;
lvItem.stateMask = LVIS_SELECTED;
SendDlgItemMessage(hWnd, IDC_LISTVIEW, LVM_GETITEM, 0, (LPARAM)&lvItem);
if(lvItem.state & LVIS_SELECTED)
{
lvItem.mask = LVIF_INDENT;
lvItem.iIndent++;
SendDlgItemMessage(hWnd, IDC_LISTVIEW, LVM_SETITEM, 0,
(LPARAM)&lvItem);
}
}
}
break;
case IDM_UNINDENT:
{
LV_ITEM lvItem;
int i,
nItemCount;
ZeroMemory(&lvItem, sizeof(lvItem));
nItemCount = (int)SendDlgItemMessage(hWnd, IDC_LISTVIEW, LVM_GETITEMCOUNT,
0, 0);
//run through the list, unindenting the selected items
for(i = 0; i < nItemCount; i++)
{
lvItem.mask = LVIF_STATE | LVIF_INDENT;
lvItem.iItem = i;
lvItem.stateMask = LVIS_SELECTED;
SendDlgItemMessage(hWnd, IDC_LISTVIEW, LVM_GETITEM, 0, (LPARAM)&lvItem);
if(lvItem.state & LVIS_SELECTED)
{
lvItem.mask = LVIF_INDENT;
if(lvItem.iIndent)
{
lvItem.iIndent--;
SendDlgItemMessage(hWnd, IDC_LISTVIEW, LVM_SETITEM, 0,
(LPARAM)&lvItem);
}
}
}
}
break;
case IDM_CUSTOMDRAW:
//toggle the custom draw flag
g_bCustomDraw = !g_bCustomDraw;
//force the control to redraw itself
InvalidateRect(GetDlgItem(hWnd, IDC_LISTVIEW), NULL, TRUE);
break;
case IDM_CHECKBOXES:
if(LVS_EX_CHECKBOXES &
(DWORD)SendDlgItemMessage(hWnd, IDC_LISTVIEW,
LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0))
RemoveExStyle(GetDlgItem(hWnd, IDC_LISTVIEW), LVS_EX_CHECKBOXES);
else
AddExStyle(GetDlgItem(hWnd, IDC_LISTVIEW), LVS_EX_CHECKBOXES);
break;
case IDM_HOVERSELECT:
if(LVS_EX_TRACKSELECT &
(DWORD)SendDlgItemMessage(hWnd, IDC_LISTVIEW,
LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0))
RemoveExStyle(GetDlgItem(hWnd, IDC_LISTVIEW), LVS_EX_TRACKSELECT);
else
AddExStyle(GetDlgItem(hWnd, IDC_LISTVIEW), LVS_EX_TRACKSELECT);
break;
case IDM_GRIDLINES:
if(LVS_EX_GRIDLINES &
(DWORD)SendDlgItemMessage(hWnd, IDC_LISTVIEW,
LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0))
RemoveExStyle(GetDlgItem(hWnd, IDC_LISTVIEW), LVS_EX_GRIDLINES);
else
AddExStyle(GetDlgItem(hWnd, IDC_LISTVIEW), LVS_EX_GRIDLINES);
break;
case IDM_FULLROWSELECT:
if(LVS_EX_FULLROWSELECT &
(DWORD)SendDlgItemMessage(hWnd, IDC_LISTVIEW,
LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0))
RemoveExStyle(GetDlgItem(hWnd, IDC_LISTVIEW), LVS_EX_FULLROWSELECT);
else
AddExStyle(GetDlgItem(hWnd, IDC_LISTVIEW), LVS_EX_FULLROWSELECT);
break;
case IDM_HEADERDRAGDROP:
if(LVS_EX_HEADERDRAGDROP &
(DWORD)SendDlgItemMessage(hWnd, IDC_LISTVIEW,
LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0))
RemoveExStyle(GetDlgItem(hWnd, IDC_LISTVIEW), LVS_EX_HEADERDRAGDROP);
else
AddExStyle(GetDlgItem(hWnd, IDC_LISTVIEW), LVS_EX_HEADERDRAGDROP);
break;
case IDM_SUBITEMIMAGES:
if(LVS_EX_SUBITEMIMAGES &
(DWORD)SendDlgItemMessage(hWnd, IDC_LISTVIEW,
LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0))
RemoveExStyle(GetDlgItem(hWnd, IDC_LISTVIEW), LVS_EX_SUBITEMIMAGES);
else
AddExStyle(GetDlgItem(hWnd, IDC_LISTVIEW), LVS_EX_SUBITEMIMAGES);
InvalidateRect(GetDlgItem(hWnd, IDC_LISTVIEW), NULL, TRUE);
UpdateWindow(GetDlgItem(hWnd, IDC_LISTVIEW));
break;
}
return 0;
}
/**************************************************************************
HandleContextMenu()
**************************************************************************/
BOOL HandleContextMenu( HWND hWnd,
WPARAM wParam,
LPARAM lParam)
{
HMENU hMenuLoad,
hMenu;
if((HWND)wParam != GetDlgItem(hWnd, IDC_LISTVIEW))
return FALSE;
hMenuLoad = LoadMenu(g_hInst, MAKEINTRESOURCE(IDM_CONTEXT_MENU));
hMenu = GetSubMenu(hMenuLoad, 0);
UpdateMenu(GetDlgItem(hWnd, IDC_LISTVIEW), hMenu);
TrackPopupMenu( hMenu,
TPM_LEFTALIGN | TPM_RIGHTBUTTON,
LOWORD(lParam),
HIWORD(lParam),
0,
hWnd,
NULL);
DestroyMenu(hMenuLoad);
return TRUE;
}
/**************************************************************************
UpdateMenu()
**************************************************************************/
void UpdateMenu(HWND hwndListView, HMENU hMenu)
{
UINT uID;
DWORD dwStyle;
//uncheck all of these guys
CheckMenuItem(hMenu, IDM_LARGEICONS, MF_BYCOMMAND | MF_UNCHECKED);
CheckMenuItem(hMenu, IDM_SMALLICONS, MF_BYCOMMAND | MF_UNCHECKED);
CheckMenuItem(hMenu, IDM_LIST, MF_BYCOMMAND | MF_UNCHECKED);
CheckMenuItem(hMenu, IDM_REPORT, MF_BYCOMMAND | MF_UNCHECKED);
CheckMenuItem(hMenu, IDM_CUSTOMDRAW, MF_BYCOMMAND | MF_UNCHECKED);
CheckMenuItem(hMenu, IDM_CHECKBOXES, MF_BYCOMMAND | MF_UNCHECKED);
CheckMenuItem(hMenu, IDM_HOVERSELECT, MF_BYCOMMAND | MF_UNCHECKED);
CheckMenuItem(hMenu, IDM_GRIDLINES, MF_BYCOMMAND | MF_UNCHECKED);
CheckMenuItem(hMenu, IDM_FULLROWSELECT, MF_BYCOMMAND | MF_UNCHECKED);
CheckMenuItem(hMenu, IDM_HEADERDRAGDROP, MF_BYCOMMAND | MF_UNCHECKED);
CheckMenuItem(hMenu, IDM_SUBITEMIMAGES, MF_BYCOMMAND | MF_UNCHECKED);
//check the appropriate view menu item
dwStyle = GetWindowLong(hwndListView, GWL_STYLE);
switch(dwStyle & LVS_TYPEMASK)
{
case LVS_ICON:
uID = IDM_LARGEICONS;
break;
case LVS_SMALLICON:
uID = IDM_SMALLICONS;
break;
case LVS_LIST:
uID = IDM_LIST;
break;
case LVS_REPORT:
uID = IDM_REPORT;
break;
}
CheckMenuRadioItem(hMenu, IDM_LARGEICONS, IDM_REPORT, uID, MF_BYCOMMAND |
MF_CHECKED);
//check the appropriate extended style items
dwStyle = (DWORD)SendMessage(hwndListView, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
//only update and enable grid lines, full row select, header drag drop, and
//sub-item images items if in report view
if(uID == IDM_REPORT)
{
EnableMenuItem(hMenu, IDM_GRIDLINES, MF_BYCOMMAND | MF_ENABLED);
EnableMenuItem(hMenu, IDM_FULLROWSELECT, MF_BYCOMMAND | MF_ENABLED);
EnableMenuItem(hMenu, IDM_HEADERDRAGDROP, MF_BYCOMMAND | MF_ENABLED);
EnableMenuItem(hMenu, IDM_SUBITEMIMAGES, MF_BYCOMMAND | MF_ENABLED);
//can we indent or unindent?
if(SendMessage(hwndListView, LVM_GETSELECTEDCOUNT, 0, 0))
{
EnableMenuItem(hMenu, IDM_INDENT, MF_BYCOMMAND | MF_ENABLED);
EnableMenuItem(hMenu, IDM_UNINDENT, MF_BYCOMMAND | MF_ENABLED);
}
else
{
EnableMenuItem(hMenu, IDM_INDENT, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
EnableMenuItem(hMenu, IDM_UNINDENT, MF_BYCOMMAND | MF_DISABLED |
MF_GRAYED);
}
if(dwStyle & LVS_EX_GRIDLINES)
{
CheckMenuItem(hMenu, IDM_GRIDLINES, MF_BYCOMMAND | MF_CHECKED);
}
if(dwStyle & LVS_EX_FULLROWSELECT)
{
CheckMenuItem(hMenu, IDM_FULLROWSELECT, MF_BYCOMMAND | MF_CHECKED);
}
if(dwStyle & LVS_EX_HEADERDRAGDROP)
{
CheckMenuItem(hMenu, IDM_HEADERDRAGDROP, MF_BYCOMMAND | MF_CHECKED);
}
if(dwStyle & LVS_EX_SUBITEMIMAGES)
{
CheckMenuItem(hMenu, IDM_SUBITEMIMAGES, MF_BYCOMMAND | MF_CHECKED);
}
}
else
{
EnableMenuItem(hMenu, IDM_INDENT, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
EnableMenuItem(hMenu, IDM_UNINDENT, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
EnableMenuItem(hMenu, IDM_GRIDLINES, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
EnableMenuItem(hMenu, IDM_FULLROWSELECT, MF_BYCOMMAND | MF_DISABLED |
MF_GRAYED);
EnableMenuItem(hMenu, IDM_HEADERDRAGDROP, MF_BYCOMMAND | MF_DISABLED |
MF_GRAYED);
EnableMenuItem(hMenu, IDM_SUBITEMIMAGES, MF_BYCOMMAND | MF_DISABLED |
MF_GRAYED);
}
//is custom drawing turned on?
if(g_bCustomDraw)
{
CheckMenuItem(hMenu, IDM_CUSTOMDRAW, MF_BYCOMMAND | MF_CHECKED);
}
//are checkboxes turned on?
if(dwStyle & LVS_EX_CHECKBOXES)
{
CheckMenuItem(hMenu, IDM_CHECKBOXES, MF_BYCOMMAND | MF_CHECKED);
}
//is hover select turned on?
if(dwStyle & LVS_EX_TRACKSELECT )
{
CheckMenuItem(hMenu, IDM_HOVERSELECT, MF_BYCOMMAND | MF_CHECKED);
}
}
Figure 7 HDITEM Structure
Member | Description |
UINT mask | Specifies which of the members contain valid information. Or, when retrieving information, which members are being requested. In addition to the mask values that are defined for the HD_ITEM structure, there are two new mask flags: HDI_IMAGE - The iImage member is valid and specifies the image to be displayed with the item. HDI_ORDER - The iOrder member is valid and specifies the order value for the item. |
int cxy | Width or height of the item. |
LPTSTR pszText | Pointer to a zero-terminated string that specifies the text for the item. If this member is set to LPSTR_TEXTCALLBACK, the control will request text information for this item by using HDN_GETDISPINFO notification messages. |
HBITMAP hbm | Handle to the bitmap that should be displayed with the item. |
int cchTextMax | Length of the item text in characters. |
int fmt | Set of bit flags that specify the item's format. These are the same as the format flags defined for the HD_ITEM structure. |
LPARAM lParam | 32-bit application-defined value. |
int iImage | Zero-based index of an image within the image list. The specified image will be displayed with the header item, but does not take the place of the one specified in the hbm field. If iImage is set to I_IMAGECALLBACK, the control will request the image information for this item by using HDN_GETDISPINFO notification messages. |
int iOrder | Specifies the order in which the item appears within the header control, from left to right. That is, the value for the far left item is 0, the value for the next item to the right is 1, and so on. |
Figure 8 NMHDDISPINFO Stucture
Member | Description |
NMHDR hdr | An NMHDR structure containing information about the notification message. |
int iItem | The zero-based index of the item in the header control. |
UINT mask | A set of bit flags specifying which members of the structure are being requested by the control. This value can be a combination of the following values: |
HDI_TEXT - The pszText member must be filled in. | |
HDI_IMAGE - The iImage member must be filled in. | |
HDI_LPARAM - The lParam member must be filled in. | |
HDI_DI_SETITEM - If you add this flag to the mask member before returning from the notification, this specifies that the header control should store the item information and not ask for it again. | |
LPTSTR pszText | Pointer to a zero-terminated string that contains the text that will be displayed for the header item. When processing the notification, you should copy the string to this location, making sure not to copy more than cchTextMax characters into the buffer. |
int cchTextMax | Size of the buffer pointed to by pszText. |
int iImage | Zero-based index of the image that should be displayed with the item. |
LPARAM lParam | 32-bit application-defined data. |