2

I'm doing some research and I would like to know how I can implement a column filter in a ListView using purely win32 api.

Something like this:

enter image description here

I wrote a simple test code, to generate a List View to show the CSV content.

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <commctrl.h>
#include <string.h>

#define WND_CLASS_NAME "CSVVIEW"

char* filename;
HWND  hList;

int rgb(int r, int g, int b) { return r + (g << 8) + (b << 16); }

void onCreate(HWND hWnd, LPARAM lParam) {
    LVCOLUMN col;
    LVITEM item;
    int iCol, iCount, dwStyle;
    CREATESTRUCT* lp = (CREATESTRUCT*)lParam;
    FILE* fp;
    char buf[256];
    char* field;

    memset(&item, 0, sizeof(item));
    hList = CreateWindowEx(0, WC_LISTVIEW, 0,
        WS_CHILD | WS_VISIBLE | LVS_REPORT,
        0, 0, 100, 100, hWnd, (HMENU)1, lp->hInstance, NULL);
    dwStyle = SendMessage(hList, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
    dwStyle = dwStyle | LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT |
        LVS_EX_GRIDLINES | LVS_EX_HEADERDRAGDROP;
    SendMessage(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, dwStyle);
    col.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;

    fp = fopen(filename, "r");
    if (fp == NULL) {
        sprintf(buf, "Fail to open the file...", filename);
        MessageBox(hWnd, buf, "Error", MB_OK);
        exit(1);
    }
    fgets(buf, 255, fp);
    field = strtok(buf, ",");
    for (iCol = 0; field != NULL; iCol++) {
        if (field[1] != ':') { col.fmt = LVCFMT_LEFT; }
        else if (field[0] == 'l') { col.fmt = LVCFMT_LEFT;   field += 2; }
        else if (field[0] == 'c') { col.fmt = LVCFMT_CENTER; field += 2; }
        else if (field[0] == 'r') { col.fmt = LVCFMT_RIGHT;  field += 2; }
        col.cx = strlen(field) * 13;
        col.iSubItem = iCol;
        col.pszText = field;
        SendMessage(hList, LVM_INSERTCOLUMN, iCol, (LPARAM)&col);
        field = strtok(NULL, ",\n");
    }

    item.mask = LVIF_TEXT;
    for (iCount = 0; fgets(buf, 255, fp) != NULL; iCount++) {
        item.pszText = strtok(buf, ",");
        item.iItem = iCount;
        item.iSubItem = 0;
        SendMessage(hList, LVM_INSERTITEM, 0, (LPARAM)&item);
        for (iCol = 1; (field = strtok(NULL, ",\n")) != NULL; iCol++) {
            item.pszText = field;
            item.iItem = iCount;
            item.iSubItem = iCol;
            SendMessage(hList, LVM_SETITEM, 0, (LPARAM)&item);
        }
    }
}

void onSize(HWND hwnd, WPARAM wp, LPARAM lp) {
    RECT rc;
    GetClientRect(hwnd, &rc);
    MoveWindow(hList, 0, 0, rc.right - rc.left, rc.bottom - rc.top, TRUE);
}

int onNotify(HWND hwnd, WPARAM wp, LPARAM lp) {
    NMHDR* pnmhdr = (NMHDR*)lp;
    if (pnmhdr->code == NM_CUSTOMDRAW) {
        NMLVCUSTOMDRAW* lpCustomDraw = (NMLVCUSTOMDRAW*)pnmhdr;
        switch (lpCustomDraw->nmcd.dwDrawStage) {
        case CDDS_PREPAINT:
            return CDRF_NOTIFYITEMDRAW;
        case CDDS_ITEMPREPAINT:
            if (lpCustomDraw->nmcd.dwItemSpec % 2 == 1)
                lpCustomDraw->clrTextBk = rgb(209, 240, 179);
            else
                lpCustomDraw->clrTextBk = rgb(250, 250, 250);
            return CDRF_NEWFONT;
        }
    }
    return DefWindowProc(hwnd, WM_NOTIFY, wp, lp);
}

LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
    case WM_CREATE:  onCreate(hWnd, lParam);  break;
    case WM_SIZE:    onSize(hWnd, wParam, lParam);  break;
    case WM_NOTIFY:  return onNotify(hWnd, wParam, lParam);
    case WM_DESTROY: PostQuitMessage(0);  break;
    default: return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    char buf[256];
    HWND hWnd;
    WNDCLASS wcl;
    MSG msg;

    filename = lpCmdLine;
    if (filename == NULL) return FALSE;
    InitCommonControls();

    memset(&wcl, 0, sizeof(wcl));
    wcl.hInstance = hInstance;
    wcl.lpszClassName = WND_CLASS_NAME;
    wcl.lpfnWndProc = WindowProc;
    wcl.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcl.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    if (!RegisterClass(&wcl)) return FALSE;

    wsprintf(buf, "%s - %s", "CSV View", lpCmdLine);
    hWnd = CreateWindowEx(0, WND_CLASS_NAME, buf,
        WS_OVERLAPPEDWINDOW | WS_VISIBLE, 10, 10, 900, 300, NULL, NULL, hInstance, NULL);
    if (!hWnd) return FALSE;

    while (GetMessage(&msg, NULL, 0, 0) > 0) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}

CSV test file:

COL 1,COL 2,COL 3,COL 4
CA_002,CB_002,CB_002,CB_002
CA_003,CB_003,CB_003,CB_003

What is necessary to change in the code so that it is possible to create the search fields in the list view header?

How to capture the events for each text field in the Header?

3
  • 4
    Add the HDS_FILTERBAR style to your listview's header control. Last time I did this (about a month ago), I wasn't able to get the filter bar to use Visual Styles, and it looked fairly out-of-place. I didn't invest a lot of time to find out why. Commented Mar 5, 2020 at 13:39
  • @IInspectable thanks!! now I have some questions... How to get the text from the filter ? Commented Mar 5, 2020 at 16:24
  • 3
    When the filter expression changes in response to user input, a HDN_FILTERCHANGE notification is sent to the header control's parent window. This allows you to observe and respond to the updated filter. If you need to get the filter data at any other time you can send an HDM_GETITEM message to the header control yourself. Commented Mar 5, 2020 at 16:45

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.