You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Win32 API下ListView子项颜色填充失效问题排查

解决Win32 ListView单元格根据值变色的问题

核心问题及修改点

  1. WM_NOTIFY消息处理逻辑错误

    • 原代码错误地将NM_CUSTOMDRAW消息的参数转换为LPNMLISTVIEW,实际应该使用LPNMLVCUSTOMDRAW结构。
    • 不能用SetWindowLong存储绘制结果,必须直接返回ProcessCustomDraw的返回值,否则自定义绘制的通知不会被系统正确处理。
  2. 自定义绘制函数缺少默认返回值

    • ProcessCustomDraw中如果没有匹配到任何绘制阶段,必须返回CDRF_DODEFAULT,确保系统执行默认绘制流程。
  3. 未根据单元格值动态设置颜色

    • 需要通过ListView_GetItem获取当前子项的文本,判断是"0"还是"1",分别设置红色/绿色背景。
  4. ListView项插入错误

    • 原代码调用LVM_INSERTITEM时一直传入0作为插入位置,导致所有行都覆盖到第一行,应传入循环变量i来插入多行。

修改后的完整代码

#pragma once
#include <Windows.h>
#include <string>
#include <commctrl.h>
#define WIN32_LEAN_AND_MEAN

int wWrkPls = 655;
int hWrkPls = 200;

static HWND Matrix = NULL;
static HINSTANCE hInst;

LRESULT CALLBACK MainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp);

void CreateMatrix(HWND hWnd) {
    Matrix = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTVIEW, L"", 
        WS_CHILD | WS_VISIBLE | LVS_REPORT, 
        0, 0, wWrkPls - 18, hWrkPls - 38, 
        hWnd, NULL, NULL, NULL);

    DWORD dwStyle = SendMessage(Matrix, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
    dwStyle |= LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT;
    SendMessageW(Matrix, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, dwStyle);

    LVCOLUMN lvColumn;
    lvColumn.mask = LVCF_TEXT | LVCF_WIDTH;
    for (int i = 0; i < 5; i++) {
        lvColumn.cx = 30;
        lvColumn.pszText = (LPWSTR)L" ";
        SendMessage(Matrix, LVM_INSERTCOLUMN, i, (LPARAM)&lvColumn);
    }

    LVITEM lvItem;
    lvItem.mask = LVIF_TEXT;
    lvItem.stateMask = 0;

    for (int i = 0; i < 5; i++) {
        lvItem.iSubItem = 0;
        lvItem.iItem = i;
        lvItem.pszText = (i % 2 == 0) ? (LPWSTR)L"1" : (LPWSTR)L"0";
        SendMessage(Matrix, LVM_INSERTITEM, i, (LPARAM)&lvItem);
    
        for (int j = 1; j < 5; j++) {
            lvItem.iSubItem = j;
            lvItem.pszText = (j % 2 == 0) ? (LPWSTR)L"1" : (LPWSTR)L"0";
            SendMessage(Matrix, LVM_SETITEM, 0, (LPARAM)&lvItem);
        }
    }
}

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPr, LPSTR args, int ncmdshow) {
    WNDCLASS WindowClass = { 0 };
    WindowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    WindowClass.hInstance = hInst;
    WindowClass.lpszClassName = L"MainWindClass";
    WindowClass.lpfnWndProc = MainProc;

    ::hInst = hInst;

    if (!RegisterClassW(&WindowClass)) {
        return -1;
    }

    int wCntr = GetSystemMetrics(SM_CXSCREEN) / 2;
    int hCntr = GetSystemMetrics(SM_CYSCREEN) / 2;

    HWND MainWindow = CreateWindowW(L"MainWindClass", L"ListView Color Test", 
        WS_OVERLAPPEDWINDOW | WS_VISIBLE, 
        wCntr - (wWrkPls / 2), hCntr - (hWrkPls / 2), 
        wWrkPls, hWrkPls, NULL, NULL, NULL, NULL);

    MSG MainMsg = { 0 };
    while (GetMessage(&MainMsg, NULL, NULL, NULL)) {
        TranslateMessage(&MainMsg);
        DispatchMessage(&MainMsg);
    }

    return 0;
}

LRESULT ProcessCustomDraw(LPARAM lp) {
    LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)lp;

    switch (lplvcd->nmcd.dwDrawStage) {
        case CDDS_PREPAINT:
            return CDRF_NOTIFYITEMDRAW;

        case CDDS_ITEMPREPAINT:
            return CDRF_NOTIFYSUBITEMDRAW;

        case CDDS_SUBITEM | CDDS_ITEMPREPAINT: {
            WCHAR itemText[16] = {0};
            LVITEM lvItem = {0};
            lvItem.mask = LVIF_TEXT;
            lvItem.iItem = lplvcd->iItem;
            lvItem.iSubItem = lplvcd->iSubItem;
            lvItem.pszText = itemText;
            lvItem.cchTextMax = sizeof(itemText)/sizeof(WCHAR);
            
            ListView_GetItem(lplvcd->nmcd.hdr.hwndFrom, &lvItem);

            if (wcscmp(itemText, L"1") == 0) {
                lplvcd->clrTextBk = RGB(0, 255, 0);
            } else if (wcscmp(itemText, L"0") == 0) {
                lplvcd->clrTextBk = RGB(255, 0, 0);
            }
            lplvcd->clrText = RGB(255, 255, 255);
            return CDRF_NEWFONT;
        }
    }

    return CDRF_DODEFAULT;
}

LRESULT CALLBACK MainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) {
    switch (msg) {
        case WM_NOTIFY: {
            LPNMHDR pnmh = (LPNMHDR)lp;
            if (pnmh->hwndFrom == Matrix && pnmh->code == NM_CUSTOMDRAW) {
                return ProcessCustomDraw(lp);
            }
            break;
        }

        case WM_CREATE:
            CreateMatrix(hWnd);
            break;

        case WM_DESTROY:
            PostQuitMessage(0);
            break;

        default:
            return DefWindowProc(hWnd, msg, wp, lp);
    }
    return 0;
}

额外说明

  • 统一使用宽字符API替换原有的CreateWindowA,避免编码不一致问题。
  • 插入项时设置了交替的0和1值,方便直接测试颜色效果。
  • 使用ListView_GetItem读取单元格内容,确保能正确获取当前子项的文本值。

内容的提问来源于stack exchange,提问作者Orange Wagon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 14:47:04