无法接收ListView的所有NM_CUSTOMDRAW dwDrawStage

时间:2014-06-19 09:29:30

标签: listview winapi mdi

我有一个带有MDI框架窗口的Win32应用程序(没有mfc)。

主MDI框架窗口会产生MDICLIENT窗口。但在我的应用程序中,主框架窗口有另一个tabctrl子窗口,它在主框架的底部显示一些listview wnds:

//create the tab first, as a child of main MDI frame with 800px width and 300px height, at point (0, 600) of main frame window.
HWND hWndTabCtrl = CreateWindow(WC_TABCONTROL, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | TCS_BOTTOM, 0, 600, 800, 300, hWndMainFrame, NULL, hInstance, NULL);

//add one tab item for test:
TCITEM item;
item.mask = TCIF_TEXT;
item.pszText = L"Test List View";
TabCtrl_InsertItem(hWndTabCtrl , 0, &item);

//And then create a listview, this list view is a child window of tab ctrl (hWndTabCtrl)
HWND hWndListView = CreateWindow(WC_LISTVIEW, L"", WS_CHILD | WS_BORDER | LVS_REPORT | LVS_SHOWSELALWAYS | WS_VISIBLE, 0, 0,800, 280, hWndTabCtrl , NULL, hInstance, NULL);

//Now insert two columns:
LVCOLUMN column;
column.mask = LVCF_WIDTH | LVCF_TEXT;
column.cx = 200;
column.pszText = L"Column 0";
ListView_InsertColumn(hWndListView , 0, &column); //column for sub item 0
column.pszText = L"Column 1";
ListView_InsertColumn(hWndListView , 1, &column); //column for sub item 1

现在我想更改子项目1的文字颜色。

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    switch (message){
        case WM_NOTIFY:
            if (((LPNMHDR)lParam)->hwndFrom == hWndListView && ((LPNMHDR)lParam)->code == NM_CUSTOMDRAW){

                LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)lParam;

                switch (lplvcd->nmcd.dwDrawStage){
                    case CDDS_PREPAINT:
                        //I can receive this value 
                        return CDRF_NOTIFYITEMDRAW;
                        break;
                    case CDDS_ITEMPREPAINT:
                        //I cann't receive this value:
                        return CDRF_NOTIFYSUBITEMDRAW;
                        break;
                    case CDDS_SUBITEM | CDDS_ITEMPREPAINT:
                        //I cann't receive this value:
                        lplvcd->clrText = RGB(255,0, 0);
                        return CDRF_NEWFONT;
                        break;
                }
                return CDRF_DODEFAULT;
            }
            break;
        case ...
            ...
            break;
    default:
    return DefFrameProc(hWnd, hWndMainFrame, message, wParam, lParam);

    }
}

在WM_NOTIFY代码块的情况下,我只能接收lplvcd-> nmcd.dwDrawStage一次,其值为CDDS_PREPAINT。我相信这是因为返回值CDRF_NOTIFYITEMDRAW没有返回正确的" parent"。

是TabCtrl的问题还是MDI窗口的问题?

2 个答案:

答案 0 :(得分:0)

尽管文档说的是,返回值实际上是一个位掩码,因此您可以一次返回多个值。同样,dwDrawingStage也是一个位掩码,所以你应该寻找你感兴趣的特定位。

尝试更像这样的事情:

LPNMHDR pnmhdr = (LPNMHDR) lParam;
if ((pnmhdr->hwndFrom == hWndListView) && (pnmhdr->code == NM_CUSTOMDRAW))
{
    LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW) lParam;

    if (lplvcd->nmcd.dwDrawStage & CDDS_ITEM)
    {
        if (lplvcd->nmcd.dwDrawStage & CDDS_ITEMPREPAINT)
        {
            if (lplvcd->nmcd.dwDrawStage & CDDS_SUBITEM)
            {
                lplvcd->clrText = RGB(255,0, 0);
                ...
                return CDRF_DODEFAULT | CDRF_NEWFONT;
            }
            else
            {
                ...
                return CDRF_DODEFAULT | CDRF_NOTIFYSUBITEMDRAW;
            }
        }
        ...
    }
    else
    {
        switch (lplvcd->nmcd.dwDrawStage)
        {
            case CDDS_PREPAINT:
            {
                ...
                return CDRF_NOTIFYITEMDRAW | CDRF_NOTIFYSUBITEMDRAW;
            }
            ...
        }
    }
    return CDRF_DODEFAULT;
}

答案 1 :(得分:0)

我有一个类似的问题(Dialog中的ListView),有一个共同的因素:没有MFC。 相同的结果:接收CDDS_PREPAINT,但不接收CDDS_ITEMPREPAINT及其组合(CDDS_SUBITEM | CDDS_PREPAINT和CDDS_ITEM | CDDS_SUBITEM | CDDS_PREPAINT)。 经过3天的挖掘后,我在https://www.codeproject.com/Articles/2890/Using-ListView-control-under-Win-API找到了答案。

在我的DialogProc中,我将NM_CUSTOMDRAW的结果返回给WM_NOTIFY,如下所示:

    case WM_NOTIFY:
        NMHDR* pHdr = (NMHDR*) lParam;
        if (pHdr->idFrom == IDC_LIST_RESULTS  &&  pHdr->code == NM_CUSTOMDRAW)
        {
            SetWindowLong(hDlg, DWL_MSGRESULT, (LONG)HandleCustomDraw((NMLVCUSTOMDRAW*)pHdr));
            return TRUE;
        }
        break;

但正确的行为是将结果发送给所有者:

Comparator

希望它有所帮助!

编辑:当然现在我在另一个stackoverflow问题中找到了相同的答案:-) Virtual listview doesn't get CDDS_ITEMPREPAINT c++