告诉所有者绘制列表框重绘项目的最佳方式?

Best way to tell owner draw listbox redraw an item?

我创建了一个所有者绘制列表框并将 texts 矢量绑定到它,如下所示。

vector<wchar_t*> texts;

lbHWND = CreateWindowExW(NULL, WC_LISTBOX, NULL,
        WS_CHILD | WS_BORDER | WS_VISIBLE | LBS_NODATA | 
        LBS_OWNERDRAWFIXED | LBS_NOTIFY | LBS_NOINTEGRALHEIGHT,
        0, 0, 400, 400, tkHWND, (HMENU)IDC_LISTBOX_ENTRY, hInstance, 0);

SCROLLINFO lbSi = { 0 };
lbSi.cbSize = sizeof(SCROLLINFO);
lbSi.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
lbSi.nMin = 0;
lbSi.nMax = text.size();
lbSi.nPage = 20;
lbSi.nPos = 0;
SetScrollInfo(lbHWND, SB_VERT, &lbSi, TRUE);

SendMessageW(lbHWND, LB_RESETCONTENT, 0, 0);
SendMessage(lbHWND, LB_SETCOUNT, iTotal, 0);

LRESULT CALLBACK WndProc(HWND phwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
        case WM_MEASUREITEM:
        {
            MEASUREITEMSTRUCT*  lpmis = (LPMEASUREITEMSTRUCT)lParam;
            switch (lpmis->CtlID)
            {
                case IDC_LISTBOX_ENTRY:
                    lpmis->itemHeight = 20;
                    break;
                default:
                    break;
            }
            return TRUE;
        }
        case WM_DRAWITEM:
        {
            DRAWITEMSTRUCT* lpdis = (LPDRAWITEMSTRUCT)lParam;

            if (lpdis->itemID == -1) return;
            HBRUSH hb = NULL;
            HPEN hp = NULL;

            switch (lpdis->itemAction) 
            { 
                case ODA_SELECT: 
                case ODA_DRAWENTIRE: 
                    SetBkMode(lpdis->hDC, TRANSPARENT);
                    hb = CreateSolidBrush(lpdis->itemState & ODS_SELECTED ? 0xf1f1f1 : 0xffffff);
                    hp = CreatePen(PS_SOLID, 1, lpdis->itemState & ODS_SELECTED ? 0xcfcfcf : 0xffffff);
                    SelectObject(lpdis->hDC, hp);
                    SelectObject(lpdis->hDC, hb);

                    Rectangle(lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.top, lpdis->rcItem.right, lpdis->rcItem.bottom);

                    TextOut(lpdis->hDC,
                        lpdis->rcItem.left + 5,
                        lpdis->rcItem.top + 2,
                        texts[i],
                        wcslen(texts[i]);
                    break;
            }
            if (hp) DeleteObject(hp);
            if (hb) DeleteObject(hb);
        }
    }
}

现在假设我更新了 texts 中的一个项目,你能告诉我一个告诉列表框重绘那个项目的好方法吗?

目前,我使用以下代码:

texts[2] = L"Some text";
SendMessageW(lbHWND, LB_RESETCONTENT, 0, 0);
SendMessage(lbHWND, LB_SETCOUNT, iTotal, 0);

强制列表框重绘所有项目,而不仅仅是第三个项目。有更好的方法吗?

您可以使用 LB_GETITEMRECT to retrieve the coordinates of the item and then InvalidateRect() 强制重绘 window:

的特定区域
RECT r = {};
if (SendMessage(lbHWND, LB_GETITEMRECT, index, &r) != LB_ERR)
    InvalidateRect(lbHWND, &r, 0);