今天想做一个可编辑单元格的 listview,样式是 LVS_REPORT 与 LVS_EDITLABELS
网上搜索了一些相关资料,照葫芦画瓢写了一个,可测试的时候发现,当从第2列开始编辑的时候,第1列的内容就显示不出来。
网上搜索了一下,有一个网友和我遇到的问题一样: https://stackoverflow.com/questions/8658128/subclassing-list-view-to-edit-only-its-subitems?rq=1
下面是他贴出来的代码:
WNDPROC wpOrigEditProc; RECT rcSubItem; LRESULT CALLBACK WndProcEditList(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_WINDOWPOSCHANGING: { WINDOWPOS *pos = (WINDOWPOS*) lParam; pos->x = rcSubItem.left; // 定位 listview 编辑框的位置 pos->cx = rcSubItem.right; } break; default: return CallWindowProc(wpOrigEditProc, hWnd, uMsg, wParam, lParam); } return 1; } LRESULT CALLBACK WndProcList(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { static HWND hEdit; static RECT rc; static LVITEM lvI; static unsigned char bEditing = 0; switch (uMsg) { case WM_NOTIFY: switch (((NMHDR*) lParam)->code) { case NM_CLICK: lvI.iItem = ((NMITEMACTIVATE*) lParam)->iItem; lvI.iSubItem = ((NMITEMACTIVATE*) lParam)->iSubItem; break; case NM_DBLCLK: SendMessage(hWnd, LVM_EDITLABEL, lvI.iItem, 0); break; case LVN_BEGINLABELEDIT: { char text[32]; bEditing = 1; hEdit = (HWND) SendMessage(hWnd, LVM_GETEDITCONTROL, 0, 0); rcSubItem.top = lvI.iSubItem; rcSubItem.left = LVIR_LABEL; SendMessage(hWnd, LVM_GETSUBITEMRECT, lvI.iItem, (long) &rcSubItem); rcSubItem.right = SendMessage(hWnd, LVM_GETCOLUMNWIDTH, lvI.iSubItem, 0); wpOrigEditProc = (WNDPROC) SetWindowLong(hEdit, GWL_WNDPROC, (long) WndProcEditList); lvI.pszText = text; lvI.cchTextMax = 32; SendMessage(hWnd, LVM_GETITEMTEXT, lvI.iItem, (long) &lvI); SetWindowText(hEdit, lvI.pszText); } break; case LVN_ENDLABELEDIT: bEditing = 0; SetWindowLong(hEdit, GWL_WNDPROC, (long) wpOrigEditProc); if (!lvI.iSubItem) return 1; lvI.pszText = ((NMLVDISPINFO*) lParam)->item.pszText; if (!lvI.pszText) return 1; SendMessage(hWnd, LVM_SETITEMTEXT, lvI.iItem, (long) &lvI); break; default: return CallWindowProc((WNDPROC) GetClassLong(hWnd, GCL_WNDPROC), hWnd, uMsg, wParam, lParam); } break; case WM_PAINT: if (bEditing) { RECT rcItem; if (lvI.iSubItem > 0) { rcItem.left = LVIR_LABEL; if (SendMessage(hWnd, LVM_GETITEMRECT, lvI.iItem, (long) &rcItem)) ValidateRect(hWnd, &rcItem); } } default: return CallWindowProc((WNDPROC) GetClassLong(hWnd, GCL_WNDPROC), hWnd, uMsg, wParam, lParam); } return 0; } LRESULT CALLBACK WndProcMain(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { static HWND hList; static RECT rc; switch (uMsg) { case WM_NOTIFY: switch (((NMHDR*) lParam)->code) { case NM_CLICK: case NM_DBLCLK: case LVN_BEGINLABELEDIT: case LVN_ENDLABELEDIT: return CallWindowProc(WndProcList, ((NMHDR*) lParam)->hwndFrom, uMsg, wParam, lParam); } break; case WM_CREATE: { LVCOLUMN lvc; LVITEM lvI; unsigned int i; float vertex; char text[32]; hList = CreateWindow(WC_LISTVIEW, 0, WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_EDITLABELS, rc.left, rc.top, rc.right, rc.bottom, hWnd, 0, hInstance, 0); SendMessage(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES); SetWindowLong(hList, GWL_WNDPROC, (long) WndProcList); lvc.mask = LVCF_WIDTH; lvc.cx = 30; SendMessage(hList, LVM_INSERTCOLUMN, 0, (LPARAM) &lvc); lvc.mask = LVCF_TEXT; lvc.pszText = "Vertex"; SendMessage(hList, LVM_INSERTCOLUMN, 1, (LPARAM) &lvc); SendMessage(hList, LVM_SETCOLUMNWIDTH, 1, LVSCW_AUTOSIZE_USEHEADER); lvI.mask = LVIF_TEXT; lvI.pszText = text; for (i = 0; i < 10; i++) { vertex = (float) i; lvI.iItem = i; lvI.iSubItem = 0; sprintf(text, "%d", i); SendMessage(hList, LVM_INSERTITEM, 0, (LPARAM) &lvI); lvI.iSubItem = 1; sprintf(text, "%f, %f, %f", vertex - 1, vertex, vertex + 1); SendMessage(hList, LVM_SETITEM, 0, (LPARAM) &lvI); } } break; case WM_SIZE: GetClientRect(hWnd, &rc); MoveWindow(hList, rc.left, rc.top, rc.right, rc.bottom, 1); SendMessage(hList, LVM_SETCOLUMNWIDTH, 1, LVSCW_AUTOSIZE_USEHEADER); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, uMsg, wParam, lParam); } return 0; }
至于为什么当编辑第2,3,... 列时,当前行的第1列的内容不显示的原因,我还是没找到。
不过我找到了一个解决办法: 就是给 listview 添加一个空白列, 宽度设置为 0
lvc.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_FMT;
lvc.pszText = "";
lvc.cx = 0; //宽度设置为 0
lvc.fmt = LVCFMT_CENTER;
这也是不是办法的办法了,反正我没有更好的解决方案。