WinAPI、TreeView:TVIS_CUT 的灰色项目

WinAPI, TreeView: a gray item by TVIS_CUT

我想让一个项目变成灰色。根据docs我在stateMaskmask中设置了TVIS_CUT
但它不起作用(该项目像往常一样是黑色的)。 TVIS_BOLD 完美。

我使用 CodeBlocks17 (gcc)/Win7x64。我还尝试了 VS2005 和另一个 OS (WinXP),结果相同。
我错过了什么?

#define _UNICODE
#define UNICODE

#include <windows.h>
#include <commctrl.h>

LRESULT CALLBACK cbMain (HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow) {
    MSG msg;
    WNDCLASSEX wc{0};

    wc.hInstance = hInstance;
    wc.lpszClassName = TEXT("MyAppClass");
    wc.lpfnWndProc = cbMain;
    wc.style = CS_DBLCLKS;
    wc.cbSize = sizeof (WNDCLASSEX);
    wc.hIcon = LoadIcon(0, IDC_ICON);
    wc.hCursor = LoadCursor (NULL, IDC_ARROW);
    wc.lpszMenuName = 0;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

    if (!RegisterClassEx (&wc))
        return EXIT_FAILURE;

    HWND hMainWnd = CreateWindowEx (0, TEXT("MyAppClass"), NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 500, 600, 160, 300, HWND_DESKTOP, NULL, hInstance, NULL);
    HWND hTreeWnd = CreateWindowEx(0, WC_TREEVIEW, NULL, WS_VISIBLE | WS_CHILD | TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT  | TVS_EDITLABELS, 0, 0, 150, 200, hMainWnd, (HMENU)100, hInstance,  NULL);

    TVITEM tvi{0};
    tvi.mask = TVIF_TEXT | TVIF_STATE;
    tvi.pszText = TEXT("Item");
    tvi.cchTextMax = 40;
    tvi.stateMask = TVIS_CUT;
    tvi.state = TVIS_CUT;

    TVINSERTSTRUCT tvins{0};
    tvins.item = tvi;
    tvins.hInsertAfter = TVI_ROOT;
    tvins.hParent = TVI_ROOT;
    SendMessage(hTreeWnd, TVM_INSERTITEM, 0, (LPARAM)(LPTVINSERTSTRUCT)&tvins);

    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return msg.wParam;
}

LRESULT CALLBACK cbMain (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
    switch (message) {
        case WM_DESTROY:
            PostQuitMessage (0);
            break;

        default:
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}

我用了 Custom Draw 正如乔纳森·波特所说。

这里有一个陷阱:当前项目发生变化时,旧项目在 pCustomDraw->nmcd.uItemState 成员中有 CDIS_FOCUSCDIS_SELECTED 标志,而新项目没有。所以 pCustomDraw->clrText = (pNMTVCD->nmcd.uItemState & CDIS_FOCUS) == CDIS_FOCUS) ? ... 会有点奇怪。我改为检查 pCustomDraw->clrTextBk 。但是当用户使用自定义主题时它可能会被破坏。

我使用 this article and an applied code 构建示例。

#define _UNICODE
#define UNICODE
#define _WIN32_WINNT 0x0501
#define _WIN32_IE 0x0500

#include <windows.h>
#include <commctrl.h>

#define IDC_TREEVIEW 100

LRESULT CALLBACK cbMain (HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow) {
    MSG msg;
    WNDCLASSEX wc{0};

    wc.hInstance = hInstance;
    wc.lpszClassName = TEXT("MyAppClass");
    wc.lpfnWndProc = cbMain;
    wc.style = CS_DBLCLKS;
    wc.cbSize = sizeof (WNDCLASSEX);
    wc.hIcon = LoadIcon(0, IDC_ICON);
    wc.hCursor = LoadCursor (NULL, IDC_ARROW);
    wc.lpszMenuName = 0;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

    if (!RegisterClassEx (&wc))
        return EXIT_FAILURE;

    HWND hMainWnd = CreateWindowEx (0, TEXT("MyAppClass"), NULL, WS_OVERLAPPED | WS_VISIBLE | WS_SYSMENU, 500, 600, 160, 300, HWND_DESKTOP, NULL, hInstance, NULL);
    HWND hTreeWnd = CreateWindowEx(0, WC_TREEVIEW, NULL, WS_VISIBLE | WS_CHILD | TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT  | TVS_EDITLABELS, 0, 0, 150, 200, hMainWnd, (HMENU)IDC_TREEVIEW, hInstance,  NULL);

    TVITEM tvi{0};
    TVINSERTSTRUCT tvins{0};
    tvi.mask = TVIF_TEXT | TVIF_STATE;
    tvi.pszText = TEXT("Item1");
    tvi.cchTextMax = 40;
    tvi.stateMask = 0;
    tvi.state = 0;

    tvins.item = tvi;
    tvins.hInsertAfter = TVI_ROOT;
    tvins.hParent = TVI_ROOT;
    SendMessage(hTreeWnd, TVM_INSERTITEM, 0, (LPARAM)(LPTVINSERTSTRUCT)&tvins);

    tvi.pszText = TEXT("Item2");
    tvins.item = tvi;
    SendMessage(hTreeWnd, TVM_INSERTITEM, 0, (LPARAM)(LPTVINSERTSTRUCT)&tvins);

    tvi.stateMask = TVIS_CUT;
    tvi.state = TVIS_CUT;
    tvi.pszText = TEXT("Item3");
    tvins.item = tvi;
    SendMessage(hTreeWnd, TVM_INSERTITEM, 0, (LPARAM)(LPTVINSERTSTRUCT)&tvins);

    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return msg.wParam;
}

LRESULT CALLBACK cbMain (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    switch (message) {
        case WM_DESTROY: {
            PostQuitMessage (0);
        }
        break;

        case WM_NOTIFY: {
            NMHDR* pHdr = (LPNMHDR)lParam;
            if (pHdr->idFrom == IDC_TREEVIEW && pHdr->code == NM_CUSTOMDRAW) {
                LPNMTVCUSTOMDRAW pCustomDraw = (LPNMTVCUSTOMDRAW)lParam;
                if (pCustomDraw->nmcd.dwDrawStage == CDDS_PREPAINT)
                    return CDRF_NOTIFYITEMDRAW;

                if (pCustomDraw->nmcd.dwDrawStage == CDDS_ITEMPREPAINT) {
                    BOOL isCut = TreeView_GetItemState(pHdr->hwndFrom, (HTREEITEM)pCustomDraw->nmcd.dwItemSpec, TVIS_CUT) & TVIS_CUT;
                    pCustomDraw->clrText = pCustomDraw->clrTextBk != RGB( 255, 255, 255) ? RGB( 255, 255, 255) :
                        isCut ? RGB( 128, 128, 128 ) : RGB( 0, 0, 0);
                }

                return CDRF_DODEFAULT;
            }
        }
        break;

        default:
            return DefWindowProc (hWnd, message, wParam, lParam);
    }

    return 0;
}