listviewctrl.hpp
#ifndef listviewctrlH
#define listviewctrlH
#include <windows.h>
#include <commctrl.h>
#pragma comment (lib, "ws2_32.lib")
namespace NSTS {
enum EListViewType {
eListViewIcon = LVS_ICON,
eListViewList = LVS_LIST,
eListViewSmallIcon = LVS_SMALLICON,
eListViewReport = LVS_REPORT
};
enum EAlignType{
eAlignLeft = LVCFMT_LEFT,
eAlignRight = LVCFMT_RIGHT,
eAlignCenter = LVCFMT_CENTER
};
struct ListViewColumn {
TCHAR szHeader [128];
int iWidth;
EAlignType eAlignType;
bool fCanSort;
};
#define LISTVIEW_TEXT 0x1
#define LISTVIEW_ICON 0x2
struct ListViewItem {
DWORD dwMask;
TCHAR szText [512];
HICON hIcon;
};
class CListViewCtrl {
#define SELF_VALID IsWindow (m_hSelf)
public:
CListViewCtrl (void) {
m_hSelf = m_hParent = NULL;
m_hInst = NULL;
m_imgNormal = m_imgSmall = NULL;
m_fAdjustColumnWidth = false;
m_iColumnCount = 0;
};
~CListViewCtrl (void) {
if (m_imgNormal != NULL) {
ImageList_Destroy (m_imgNormal);
m_imgNormal = NULL;
}
if (m_imgSmall != NULL) {
ImageList_Destroy (m_imgSmall);
m_imgSmall = NULL;
}
};
bool Init (HINSTANCE hInst, HWND hParent, const RECT* prc, DWORD dwStyle = LVS_SORTASCENDING | LVS_REPORT | WS_CHILD | WS_BORDER | WS_VISIBLE | LVS_SHOWSELALWAYS) {
if (hInst != NULL && IsWindow (hParent) && prc != NULL) {
INITCOMMONCONTROLSEX icex;
// Ensure that the common control DLL is loaded.
icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
icex.dwICC = ICC_LISTVIEW_CLASSES;
InitCommonControlsEx(&icex);
CoInitialize (NULL);
m_hSelf = CreateWindow (WC_LISTVIEW,
NULL,
dwStyle,
prc->left,
prc->top,
prc->right - prc->left,
prc->bottom - prc->top,
hParent,
NULL,
hInst,
NULL);
if (m_hSelf == NULL) {
return false;
}
m_hParent = hParent;
m_hInst = hInst;
m_imgNormal = ImageList_Create (32, 32, ILC_MASK, 1, 1);
if (m_imgNormal == NULL) {
Destroy ();
return false;
}
m_imgSmall = ImageList_Create (16, 16, ILC_MASK, 1, 1);
if (m_imgSmall == NULL) {
Destroy ();
return false;
}
SetFullSelected ();
SetStyleEx (GetStyleEx () | LVS_EX_SUBITEMIMAGES);
return true;
}
return false;
};
bool Init (HINSTANCE hInst, HWND hParent, const RECT* prc, ListViewColumn clns[], int iSize, DWORD dwStyle = WS_CHILD | WS_BORDER | WS_VISIBLE | LVS_REPORT | LVS_SHOWSELALWAYS) {
if (!Init (hInst, hParent, prc, dwStyle)) {
return false;
}
if (!InsertColumns (clns, iSize)) {
Destroy ();
return false;
}
return true;
};
bool Init (HINSTANCE hInst, HWND hParent, const RECT* prc, ListViewItem items[], int iSize, DWORD dwStyle = WS_CHILD | WS_BORDER | WS_VISIBLE | LVS_SHOWSELALWAYS) {
if (!Init (hInst, hParent, prc, dwStyle)) {
return false;
}
if (!InsertItems (items, iSize)) {
Destroy ();
return false;
}
return true;
};
void Destroy (void) {
if (SELF_VALID) {
DestroyWindow (m_hSelf);
}
m_hSelf = m_hParent = NULL;
m_hInst = NULL;
if (m_imgNormal != NULL) {
ImageList_Destroy (m_imgNormal);
m_imgNormal = NULL;
}
if (m_imgSmall != NULL) {
ImageList_Destroy (m_imgSmall);
m_imgSmall = NULL;
}
m_iColumnCount = 0;
CoUninitialize ();
};
bool Attach (HWND hwnd) {
CoInitialize (NULL);
if (IsWindow (hwnd)) {
int i;
LVCOLUMN cln;
cln.mask = LVCF_FMT;
m_hSelf = hwnd;
m_hParent = ::GetParent (m_hSelf);
for (i = 0;; ++i) {
if (ListView_GetColumn (m_hSelf, i, &cln)) {
++m_iColumnCount;
} else {
break;
}
}
return true;
}
return false;
};
void Dettach (void) {
CoUninitialize ();
m_hSelf = m_hParent = NULL;
m_iColumnCount = 0;
};
DWORD GetStyle (void) const {
return (DWORD)GetWindowLongPtr (m_hSelf, GWL_STYLE);
};
bool SetStyle (DWORD dwStyle) {
return SetWindowLongPtr (m_hSelf, GWL_STYLE, dwStyle);
};
DWORD GetStyleEx (void) const {
return (DWORD)ListView_GetExtendedListViewStyle (m_hSelf);
};
bool SetStyleEx (DWORD dwStyleEx) {
return ListView_SetExtendedListViewStyle (m_hSelf, dwStyleEx);
};
bool SetView (EListViewType eType) {
DWORD dwStyle = GetStyle ();
dwStyle &= ~LVS_REPORT;
dwStyle &= ~LVS_ICON;
dwStyle &= ~LVS_SMALLICON;
dwStyle &= ~LVS_LIST;
dwStyle |= eType;
return SetStyle (dwStyle);
};
public:
void SetImageList (void) {
ListView_SetImageList (m_hSelf, m_imgNormal, LVSIL_NORMAL);
ListView_SetImageList (m_hSelf, m_imgSmall, LVSIL_SMALL);
};
bool ShowLine (bool fShow = true) {
return SetStyleEx (GetStyleEx () | LVS_EX_GRIDLINES);
};
bool SetItemLParam (int iItem, int iIndex, const void* pLparam) {
LVITEM item;
item.mask = LVIF_PARAM;
item.iItem = iItem;
item.iSubItem = iIndex;
item.lParam = (LPARAM)pLparam;
return ListView_SetItem (m_hSelf, &item);
};
void* GetItemLParam (int iItem, int iIndex) {
LVITEM item;
item.mask = LVIF_PARAM;
item.iItem = iItem;
item.iSubItem = iIndex;
if (ListView_GetItem (m_hSelf, &item)) {
return (void*)item.lParam;
}
return NULL;
};
bool DeleteAllItems (void) {
if (ListView_DeleteAllItems (m_hSelf)) {
return true;
}
return false;
};
int GetSelectedItemCount (void) const {
return ListView_GetSelectedCount (m_hSelf);
};
int GetItemCount (void) const {
return ListView_GetItemCount (m_hSelf);
};
int GetSelectedItem (void) const {
return ListView_GetSelectionMark (m_hSelf);
};
bool GetSelectedText (int iIndex, TCHAR* pszText) const {
int iSelected = GetSelectedItem ();
if (iSelected != -1) {
return GetItemText (iSelected, iIndex, pszText);
}
return false;
};
bool GetItemText (int iPos, int iIndex, TCHAR* pszText) const {
if (pszText) {
ListView_GetItemText (m_hSelf, iPos, iIndex, pszText, 511);
return true;
}
return false;
};
bool InsertItems (ListViewItem items [], int iSize, int iPos = -1) {
if (items != NULL && iSize >= 0) {
int i;
for (i = 0; i < iSize; ++i) {
if (!InsertItem (&items [i], iPos)) {
return false;
}
}
return true;
}
return false;
};
bool InsertItem (ListViewItem* pitem, int iPos = -1) {
if (pitem != NULL) {
bool fRet = true;
int iCorrectPos = (iPos == -1 ? GetItemCount () : iPos);
LVITEM item;
item.mask = 0;
item.iItem = iCorrectPos;
item.iSubItem = 0;
item.iImage = iCorrectPos;
if (pitem->dwMask & LISTVIEW_TEXT) {
item.mask |= LVIF_TEXT;
item.pszText = pitem->szText;
item.cchTextMax = lstrlen (pitem->szText);
}
if (pitem->dwMask & LISTVIEW_ICON) {
item.mask |= LVIF_IMAGE;
ImageList_AddIcon (m_imgNormal, pitem->hIcon);
ImageList_AddIcon (m_imgSmall, pitem->hIcon);
}
if (-1 == ListView_InsertItem (m_hSelf, &item)) {
fRet = false;
}
return fRet;
}
return false;
};
bool InsertItem (const TCHAR* pszText, int iPos = -1) {
if (pszText != NULL) {
ListViewItem item;
item.dwMask = LISTVIEW_TEXT;
lstrcpy (item.szText, pszText);
return InsertItem (&item, iPos);
}
return false;
};
bool SetItemText (TCHAR* pszText, int iPos, int iIndex) {
if (pszText != NULL) {
LVITEM item;
item.mask = LVIF_TEXT;
item.pszText = pszText;
item.cchTextMax = lstrlen (pszText);
item.iItem = iPos;
item.iSubItem = iIndex;
return ListView_SetItem (m_hSelf, &item);
}
return false;
};
bool SetItemIcon (HICON hIcon, int iPos, int iIndex = -1) {
return (SetItemNormalIcon (hIcon, iPos, iIndex) &&
SetItemSmallItem (hIcon, iPos, iIndex));
};
bool SetItemNormalIcon (HICON hIcon, int iPos, int iIndex = -1) {
LVITEM item;
item.mask = LVIF_IMAGE;
item.iItem = iPos;
item.iSubItem = iIndex;
item.iImage = ImageList_AddIcon (m_imgNormal, hIcon);
return ListView_SetItem (m_hSelf, &item);
};
bool SetItemSmallItem (HICON hIcon, int iPos, int iIndex = -1) {
LVITEM item;
item.mask = LVIF_IMAGE;
item.iItem = iPos;
item.iSubItem = iIndex;
item.iImage = ImageList_AddIcon (m_imgSmall, hIcon);
return ListView_SetItem (m_hSelf, &item);
};
bool RemoveItem (int iItem) {
if (ListView_DeleteItem (m_hSelf, iItem)) {
return true;
}
return false;
};
bool SetTextColor (COLORREF clrText) {
return ListView_SetTextColor (m_hSelf, clrText);
};
bool SetTextBkColor (COLORREF clrBk) {
return ListView_SetTextBkColor (m_hSelf, clrBk);
};
bool SetLineColor (COLORREF clrLine) {
if (SELF_VALID) {
ListView_SetOutlineColor (m_hSelf, clrLine);
return true;
}
return false;
};
public:
/* report */
int GetColumnCount (void) const { return m_iColumnCount; };
bool InsertColumns (ListViewColumn clns [], int iSize, int iPos = -1) {
if (clns && iSize >= 0) {
LVCOLUMN lvCln;
int i;
int iTruePos;
lvCln.mask = LVCF_TEXT | LVCF_FMT | LVCF_WIDTH;
lvCln.cchTextMax = 127;
iTruePos = (iPos == -1 ? GetColumnCount () : iPos);
for (i = 0; i < iSize; ++i) {
lvCln.pszText = clns [i].szHeader;
lvCln.cx = clns [i].iWidth;
lvCln.fmt = (int)clns [i].eAlignType;
if (ListView_InsertColumn (m_hSelf, iTruePos, &lvCln) == -1) {
return false;
}
++iTruePos;
++m_iColumnCount;
}
return true;
}
return false;
};
bool InsertColumn (ListViewColumn* pcln, int iPos = -1) {
if (pcln) {
int iTruePos;
LVCOLUMN lvCln;
lvCln.mask = LVCF_TEXT | LVCF_FMT | LVCF_WIDTH;
lvCln.cchTextMax = 127;
lvCln.pszText = pcln->szHeader;
lvCln.cx = pcln->iWidth;
lvCln.fmt = (int)pcln->eAlignType;
iTruePos = (iPos == -1 ? GetColumnCount () : iPos);
if (ListView_InsertColumn (m_hSelf, iTruePos, &lvCln) != -1) {
DWORD dwStyle = GetStyle ();
if (pcln->fCanSort) {
dwStyle |= LVS_SORTASCENDING;
} else {
dwStyle &= ~LVS_SORTASCENDING;
}
++m_iColumnCount;
return SetStyle (dwStyle);
}
}
return false;
};
bool InsertColumn (const TCHAR* pszText, int iWidth = 100, int iPos = -1) {
ListViewColumn cln;
int iTruePos;
lstrcpy (cln.szHeader, pszText);
cln.iWidth = iWidth;
cln.eAlignType = eAlignLeft;
iTruePos = (iPos == -1 ? GetColumnCount () : iPos);
return InsertColumn (&cln, iTruePos);
};
bool RemoveColumn (int iCln) {
if (ListView_DeleteColumn (m_hSelf, iCln)) {
--m_iColumnCount;
return true;
}
return false;
};
bool SetColumnWidth (int iCln, int iWidth) {
return ListView_SetColumnWidth (m_hSelf, iCln, iWidth);
};
int GetColumnWidth (int iCln) {
return ListView_GetColumnWidth (m_hSelf, iCln);
};
bool SetColumnAlignType (int iCln, EAlignType eType) {
LVCOLUMN cln;
cln.mask = LVCF_FMT;
cln.fmt = (int)eType;
return ListView_SetColumn (m_hSelf, iCln, &cln);
};
void AdjustColumnWidth (bool fAdjust = true) {
m_fAdjustColumnWidth = fAdjust;
};
bool PromptHideText (bool fPrompt = true) {
if (fPrompt) {
return SetStyleEx (GetStyleEx () | LVS_EX_LABELTIP);
} else {
return SetStyleEx (GetStyleEx () & ~LVS_EX_LABELTIP);
}
/** unreachable */
while (1);
return false;
};
bool EnableDragColumns (bool fEnable = true) {
if (fEnable) {
return SetStyleEx (GetStyleEx () | LVS_EX_HEADERDRAGDROP);
} else {
return SetStyleEx (GetStyleEx () & ~LVS_EX_HEADERDRAGDROP);
}
/** unreachable */
while (1);
return false;
}
bool InsertRow (const TCHAR* pszText, int iPos = -1) {
return InsertItem (pszText, iPos);
};
bool SetRowText (TCHAR* pszText, int iPos, int iIndex) {
return SetItemText (pszText, iPos, iIndex);
};
bool RemoveRow (int iRow) {
return RemoveItem (iRow);
};
bool InsertRowHwnd (HWND hwnd) {
/** unimplemented */
return false;
};
bool RemoveRowHwnd (int iRow, int iIndex) {
/** unimplemented */
return false;
};
bool SetSelectedRowBk (COLORREF clrSelectedBk) {
/** unimplemented */
return false;
};
bool SetMouseOnRowBk (COLORREF clrMouseOnBk) {
/** unimplemented */
return false;
};
bool SetSelectedRowTextColor (COLORREF clrSelectedText) {
/** unimplemented */
return false;
};
bool SetMouseOnRowTextColor (COLORREF clrMouseOnText) {
/** unimplemented */
return false;
};
bool SetRowBk (COLORREF clrRowBk) {
/** unimplemented */
return false;
};
bool SetRowTextColor (COLORREF clrRowText) {
/** unimplemented */
return false;
};
bool SetFullSelected (bool fFull = true) {
if (fFull) {
return SetStyleEx (GetStyleEx () | LVS_EX_FULLROWSELECT);
} else {
return SetStyleEx (GetStyleEx () & ~LVS_EX_FULLROWSELECT);
}
/** unreachable */
while (1);
return false;
};
public:
bool UseCheckBox (bool fCb = true) {
if (fCb) {
return SetStyleEx (GetStyleEx () | LVS_EX_CHECKBOXES);
} else {
return SetStyleEx (GetStyleEx () & ~LVS_EX_CHECKBOXES);
}
while (1);
return false;
};
bool UseEditBox (bool fEb = true) {
if (fEb) {
return SetStyle (GetStyle () | LVS_EDITLABELS);
} else {
return SetStyle (GetStyle () & ~LVS_EDITLABELS);
}
while (1);
return false;
};
bool IsItemSelected (int iItem) const {
LVITEM item;
item.mask = LVIF_STATE;
if (ListView_GetItem (m_hSelf, &item)) {
return item.state == LVIS_SELECTED;
}
return false;
}
bool IsItemChecked (int iItem) const {
if (GetStyleEx () & LVS_EX_CHECKBOXES == LVS_EX_CHECKBOXES) {
return ListView_GetCheckState (m_hSelf, iItem);
}
};
bool SetBkColor (COLORREF clrBk) {
return ListView_SetBkColor (m_hSelf, clrBk) && SetTextBkColor (clrBk);
};
bool SetBkBitmap (TCHAR* pszBmp) {
LVBKIMAGE lvbk;
lvbk.ulFlags = LVBKIF_STYLE_TILE | LVBKIF_SOURCE_URL;
lvbk.pszImage = pszBmp;
return ListView_SetBkImage (m_hSelf, &lvbk);
};
bool SetColumnIcon (HICON hIcon, int iCln) {
/***** 未实现 */
LVCOLUMN lvcn;
lvcn.mask = LVCF_IMAGE;
lvcn.iImage = 0;
ImageList_AddIcon (m_imgSmall, hIcon);
ImageList_AddIcon (m_imgNormal, hIcon);
if (lvcn.iImage == -1) {
return false;
}
return ListView_SetColumn (m_hSelf, iCln, &lvcn);
};
bool SetColumnText (TCHAR* pszText, int iCln) {
LVCOLUMN lvcn;
lvcn.mask = LVCF_TEXT;
lvcn.pszText = pszText;
lvcn.cchTextMax = 511;
return ListView_SetColumn (m_hSelf, iCln, &lvcn);
};
struct SortStruct {
CListViewCtrl* plst;
int iColumn;
bool fAscending;
};
bool SortItems (int iCln, bool fAscending = true) {
SortStruct ss = { this, iCln, fAscending };
return ListView_SortItemsEx (m_hSelf, CompareFunc, (LPARAM)&ss);
}
int FindItem (TCHAR* pszText, int iStart = 0) {
LVFINDINFO lvfi;
lvfi.flags = LVFI_STRING | LVFI_WRAP;
lvfi.psz = pszText;
return ListView_FindItem (m_hSelf, iStart, &lvfi);
};
bool SelectItem (int iItem) {
if (SELF_VALID) {
ListView_SetItemState (m_hSelf, iItem, LVIS_SELECTED, LVIS_SELECTED);
return true;
}
return false;
}
bool PointToItem (const POINT* ppt, int* piItem, int* piSubItem) {
if (ppt) {
RECT rc;
int i;
for (i = 0; i < GetItemCount (); ++i) {
if (!ListView_GetItemRect (m_hSelf, i, &rc, LVIR_BOUNDS)) {
return false;
}
if (PtInRect (&rc, *ppt)) {
if (piItem) {
*piItem = i;
}
if (piSubItem) {
int j;
RECT rcSub;
rcSub.left = 0;
rcSub.top = rc.top;
rcSub.bottom = rc.bottom;
rcSub.right = 0;
for (j = 0; j < GetColumnCount (); ++j) {
rcSub.left += rcSub.right;
rcSub.right += GetColumnWidth (j);
if (PtInRect (&rcSub, *ppt)) {
*piSubItem = j;
}
}
}
return true;
}
}
return false;
}
return false;
};
private:
static int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) {
TCHAR sz1 [512], sz2 [512];
SortStruct* ss = (SortStruct*)lParamSort;
int iRet;
if (ss == NULL || ss->plst == NULL) {
return 0;
}
ss->plst->GetItemText (lParam1, ss->iColumn, sz1);
ss->plst->GetItemText (lParam2, ss->iColumn, sz2);
iRet = lstrcmpi (sz1, sz2);
return (ss->fAscending ? iRet : -iRet);
};
public:
HWND GetSelf (void) const { return m_hSelf; };
HWND GetParent (void) const { return m_hParent; };
private:
HWND m_hSelf;
HWND m_hParent;
HINSTANCE m_hInst;
HIMAGELIST m_imgNormal;
HIMAGELIST m_imgSmall;
bool m_fAdjustColumnWidth;
int m_iColumnCount;
};
}
#endif // listviewctrlH
Usage:
WM_INIT:
RECT rclv = { 50, 50, 300, 200};
assert (g_lv1.Init (hInst, hwndDlg, &rclv));
assert (g_lv1.InsertColumn (TEXT ("H1"), 50));
assert (g_lv1.InsertColumn (TEXT ("H2"), 80));
assert (g_lv1.InsertRow (TEXT ("吃")));
g_lv1.PromptHideText ();
g_lv1.SetRowText (TEXT ("啊"), 1, 1);
g_lv1.InsertRow (TEXT ("啵"));
g_lv1.SetRowText (TEXT ("佛"), 0, 1);
g_lv1.SetTextColor (RGB (255, 255, 255));
g_lv1.SetFullSelected ();
g_lv1.ShowLine ();
g_lv1.SetImageList ();
g_lv1.EnableDragColumns ();
g_lv1.UseCheckBox ();
g_lv1.UseEditBox ();
g_lv1.SetColumnText (TEXT ("WHAT"), 1);
g_lv1.SetColumnWidth (1, 200);
g_lv1.SetBkColor (RGB (128, 128, 128));
// assert (g_lv1.SetBkBitmap (TEXT ("D:\\A.BMP")));
HICON h1 = LoadIcon (hInst, MAKEINTRESOURCE (IDI_ICON1));
HICON h2 = LoadIcon (hInst, MAKEINTRESOURCE (IDI_ICON2));
g_lv1.InsertRow (TEXT ("aa"));
g_lv1.SetRowText (TEXT ("啊a"), 0, 1);
g_lv1.SetRowText (TEXT ("的"), 2, 1);
g_lv1.SetItemIcon (h1, 0);
g_lv1.SetItemIcon (h1, 0);
g_lv1.SetItemIcon (h2, 1, 1);
g_lv1.SetItemIcon (h2, 1);
g_lv1.SetItemIcon (h1, 2);
g_lv1.SetColumnAlignType (1, NSTS::eAlignCenter);
assert (g_lv1.SetColumnIcon (h1, 0));
DestroyIcon (h1);
DestroyIcon (h2);
case WM_NOTIFY:
{
if (wParam == 0)
{
LPNMHDR pnmh = (LPNMHDR) lParam;
if (pnmh->code == NM_RCLICK) {
POINT pt, pt2;
int iItem, iSubItem;
TCHAR szWhat [128] = TEXT ("not in");
GetCursorPos (&pt);
pt2.x = pt.x;
pt2.y = pt.y;
ScreenToClient (g_lv1.GetSelf (), &pt2);
if (g_lv1.PointToItem (&pt2, &iItem, &iSubItem)) {
wsprintf (szWhat, TEXT ("in. item: %d, subitem:%d"), iItem, iSubItem);
}
MessageBox (hwndDlg, szWhat, NULL, MB_OK);
}
}
}
break;
// Find Item
TCHAR szFind [512];
GetDlgItemText (hwndDlg, IDC_EDIT1, szFind, 511);
int i = g_lv1.FindItem (szFind);
g_lv1.SelectItem (i);
// Sort Item
static bool fsort = true;
fsort = !fsort;
g_lv1.SortItems (1, fsort);
return TRUE;
// set view
assert (g_lv1.SetView (NSTS::eListViewSmallIcon));