win32快速实现listctrl控件的可编辑子项

1.前言

公司的一个需求要实现界面上直接编辑列表实现对内容的保存,mfc的相关资料较多,直接使用win32没有,参考了mfc的相关方法,给出解决方案

2.解决

代码片段
INT_PTR CALLBACK MainWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    static HWND hlist, hsublist;
    static HFONT hFont;
    static int snitem = -1, snsubitem = -1;
    static std::map<int, std::wstring> mapIndexValue;
    auto setlistvalue = [&](){
        if (snitem >= 0 && snsubitem >= 0)
        {
            TCHAR ptBuf[MAX_PATH] = {0};
            GetDlgItemText(hDlg, IDC_EDIT1, ptBuf, MAX_PATH);
            ListView_SetItemText(hsublist, snitem, snsubitem, ptBuf);
            SetDlgItemText(hDlg, IDC_EDIT1, TEXT(""));
            mapIndexValue[snsubitem * 1000 + snitem] = ptBuf;
            snsubitem = -1;
            snitem = -1;

            MoveWindow(GetDlgItem(hDlg, IDC_EDIT1), 0, 0, 1, 1, TRUE);
        }
    };

    auto getlistvalue = [&](int nitem, int nsubitem){
        if (nitem >= 0 && nsubitem >= 0)
        {
            std::wstring wstrvalue = mapIndexValue[snsubitem * 1000 + snitem];
            SetDlgItemText(hDlg, IDC_EDIT1, wstrvalue.c_str());
        }
    };

    switch (message)
    {
    case WM_INITDIALOG:
        {
            LOGFONT  lgf;
            GetObject(GetStockObject(DEFAULT_GUI_FONT),  sizeof(lgf),  &lgf);
            lgf.lfWeight  =  FW_THIN;
            lgf.lfHeight = 12;
            hFont  =  CreateFontIndirect(&lgf);
            SendMessage(GetDlgItem(hDlg, IDC_EDIT1), WM_SETFONT, (WPARAM)hFont, (LPARAM)TRUE);

            MoveWindow(GetDlgItem(hDlg, IDC_EDIT1), 0, 0, 1, 1, TRUE);
            SetTimer(hDlg, ID_CHEAK_FOCUS, 100, NULL);
            return (INT_PTR)TRUE;
        }
    case WM_TIMER:
        {
            if (GetFocus() != GetDlgItem(hDlg, IDC_EDIT1))
                setlistvalue();
            break;
        }
    case WM_NOTIFY:
        {
            if (((LPNMHDR) lParam)->hwndFrom == hsublist) 
            {
                switch (((LPNMHDR) lParam)->code) 
                {
                case NM_DBLCLK:
                    {
                        setlistvalue();
                        NMLISTVIEW *nmlv = (NMLISTVIEW *) lParam;
                        int nselitem = nmlv->iItem;
                        int nsubitem = nmlv->iSubItem;
                        if (nselitem >= 0 && nsubitem >= 0)
                        {
                            snitem = nselitem;
                            snsubitem = nsubitem;
                            getlistvalue(nselitem, nsubitem);

                            RECT rtItem;
                            ListView_GetItemRect(hsublist, nselitem, &rtItem, LVIR_BOUNDS);
                            POINT ptBeg;
                            ptBeg.x = rtItem.left + 25 + (nsubitem - 1) * 98;
                            ptBeg.y = rtItem.top;
                            ClientToScreen(hsublist, &ptBeg);
                            ScreenToClient(hDlg, &ptBeg);
                            MoveWindow(GetDlgItem(hDlg, IDC_EDIT1), ptBeg.x, ptBeg.y, 98, rtItem.bottom - rtItem.top, TRUE);
                            SetFocus(GetDlgItem(hDlg, IDC_EDIT1));
                        }
                        break;
                    }
                }
            }
            break;
        }
    case WM_CLOSE:
        {
            KillTimer(hDlg, ID_CHEAK_FOCUS);
            DeleteObject(hFont);
            break;
        }
    }

    return (INT_PTR)FALSE;
}
备注:基本思路都一样,获取列表的单击事件后进行文本框位置移动和覆盖,这里使用计时器来实现当文本框失去焦点时,进行列表的赋值

你可能感兴趣的:(windows)