带有 NM_CUSTOMDRAW 的 Listview 项目闪烁

Posted

技术标签:

【中文标题】带有 NM_CUSTOMDRAW 的 Listview 项目闪烁【英文标题】:Listview item with NM_CUSTOMDRAW is flickering 【发布时间】:2014-09-26 14:35:31 【问题描述】:

每个人。 http://i.stack.imgur.com/ugfY4.jpg

我有这种列表视图颜色编辑器,每个项目代表不同的颜色。 因此,用户单击 COLOR_CODE 子项,颜色选择器更新为选定的 HSV 值,然后用户将颜色选择器光标拖到托盘上,COLOR_CODE 子项应实时更新以及颜色 ID 文本。 大多数情况下,更新执行得非常流畅,但有时它只是以某种方式闪烁 - ---- 它以一种非常闪烁的方式发生,就好像没有时间快速绘制它一样。

我已经开始搜索,发现很多帖子,都导致双缓冲。 好的,我已经在我的列表视图中启用了 DOUBLE BUFFERING

case WM_INITDIALOG:
ListView_SetExtendedListViewStyle(GetDlgItem(hDlg,id_listview),LVS_EX_DOUBLEBUFFER);

也试过这样

SendDlgItemMessage(hWnd,id_listview,LVM_SETEXTENDEDLISTVIEWSTYLE,NULL,(LPARAM)LVS_EX_DOUBLEBUFFER);

但这并没有帮助。 这是我的自定义绘图程序 它基本上采用 ID subItem 中写入的任何字符串 - 例如 0xffb400 并将其转换为 COLORREF,然后将子项 2 的 BG 颜色设置为结果颜色;

case WM_NOTIFY:
if(((LPNMHDR)lParam)->code == NM_CUSTOMDRAW)
        
            SetWindowLong(hDlg, DWL_MSGRESULT, (LONG)ProcessCustomDraw(lParam,hDlg));
            return TRUE;
        
        break;

LRESULT colorEditor::ProcessCustomDraw (LPARAM lParam,HWND hDlg)

    LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)lParam;

    switch(lplvcd->nmcd.dwDrawStage) 
    
        case CDDS_PREPAINT:
            return CDRF_NOTIFYITEMDRAW;
        case CDDS_ITEMPREPAINT: 
            return CDRF_NOTIFYSUBITEMDRAW;
        case CDDS_ITEMPREPAINT|CDDS_SUBITEM: //Before an item is drawn//
            if (lplvcd->iSubItem==2)
            
                item_redraw.iItem=lplvcd->nmcd.dwItemSpec;
                SendDlgItemMessageA(hWnd,id_listview,LVM_GETITEM,0,(LPARAM)&item_redraw);
                lplvcd->clrTextBk = colorrefFromString(item_redraw.pszText);
            
            return CDRF_NEWFONT;
    
    return CDRF_DODEFAULT;

以防万一您认为 colorrefFromString 是我提供的清单:

COLORREF colorEditor::colorrefFromString(wchar_t *color)

    COLORREF res_color;
    unsigned short i=0,di=0;
    int digits[6];
    int h_digits[3];
    if (color[i]=='0'&&(color[i+1]=='x'||color[i+1]=='X')) i=2;
    int ix=0;

    while (color[(ix++)+i]!='\0')
    if (--ix!=5) while((ix++)<5)
        digits[di++]=0;

    while (color[i]!='\0')
    
        if (color[i]>47&&color[i]<58) digits[di++]=color[i]-48;
        else if (color[i]>64&&color[i]<71) digits[di++]=color[i]-65+10;
        else if (color[i]>96&&color[i]<103) digits[di++]=color[i]-97+10;
        i++;
    
    h_digits[0]=digits[0]*16+digits[1];
    h_digits[1]=digits[2]*16+digits[3];
    h_digits[2]=digits[4]*16+digits[5];
    res_color=0x00000000|(h_digits[2]<<16)|(h_digits[1]<<8)|h_digits[0];
    return res_color;

现在是问题: 为什么我有闪烁?

【问题讨论】:

好吧,我不确定这是否是解决问题的好方法, 好吧,我完全忘记了在选色时在 mousemove 消息中使用的另一个函数。它是发送到当前项目的 LVM_REDRAWITEMS。而不是发送这条使所有项目行变为白色的消息 - 我只是找出 COLOR_CODE 子项目的矩形并用当前颜色填充它。问题是我得到了带有偏移的子项矩形。所以我需要手动设置 OffsetRect(13,13)。然后一切看起来都很完美,但我手工做的事实看起来是错误的! 【参考方案1】:

乍一看,我看不出闪烁的真正原因。

但是尝试自己在这里完成所有绘图。,也许这行得通。

只计算颜色。使用给定的 dc 在项目矩形上调用 FillRect 并返回 CDRF_SKIPDEFAULT。

【讨论】:

好吧,我已经做了一些步骤调试。这是我注意到的。首先我发送 CDRF_NOTIFYITEMDRAW 以获取 CDDS_ITEMPREPAINT 阶段,然后我返回 CDRF_NOTIFYSUBITEMDRAW 以获取 CDDS_ITEMPREPAINT|CDDS_SUBITEM。当我收到最后一条通知时,我的子项已经被绘制为白色/已擦除。即使我在该步骤中使用某种颜色填充矩形,它也已经闪烁,因为在 ITEM PREPAINT 执行擦除过程之前。我现在正试图真正抓住擦除。 case CDDS_ITEMPREERASE 不知何故没有捕捉到任何东西。任何更多的建议都会很棒

以上是关于带有 NM_CUSTOMDRAW 的 Listview 项目闪烁的主要内容,如果未能解决你的问题,请参考以下文章

Flutter 有状态的代码问题。在 setstate 中放啥?

ListView 没有向我显示包含数据库名称的列表。我使用 SimpleCursorAdapter

Clistctrl 项目文本颜色

ClistCtrl 设置项目的颜色

VC控件自绘制三步曲

CustomDraw 中的 SetWindowLong 导致未处理的异常