Skip to content

[Feature Request] Filter and Sort by column in the grid #76

Description

@bencz

I would like to use the filter system by column and sorting in the grid

Here, I have a small sample of how to use the ListView Filter:

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <commctrl.h>
#include <string.h>
#include <stdbool.h>
#define WND_CLASS_NAME "CSVVIEW"
#define ID_LISTVIEW 0x8801
char* filename;
HWND hList, hHeader;
static NMLISTVIEW* nmListView;
static NMHEADER* nmHeader;
int rgb(int r, int g, int b) { return r + (g << 8) + (b << 16); }
bool startsWith(const char* pre, const char* str)
{
size_t lenpre = strlen(pre),
lenstr = strlen(str);
return lenstr < lenpre ? false : memcmp(pre, str, lenpre) == 0;
}
void onCreate(HWND hWnd, LPARAM lParam) {
LVCOLUMN col;
LVITEM item;
int iCol, iCount, dwStyle, dwHeaderStyle;
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)ID_LISTVIEW, lp->hInstance, NULL);
dwStyle = SendMessage(hList, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
dwStyle = dwStyle | LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_HEADERDRAGDROP | LVS_EX_FLATSB;
SendMessage(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, dwStyle);
col.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
nmListView = (NMLISTVIEW*)hList;
// TEST HEADER
hHeader = ListView_GetHeader(hList);
SetWindowLong(hHeader, GWL_ID, ID_LISTVIEW + 1);
Header_SetFilterChangeTimeout(hHeader, 1000);
dwHeaderStyle = (GetWindowLongPtr(hHeader, GWL_STYLE) | HDS_FILTERBAR) & ~HDS_BUTTONS;
SetWindowLong(hHeader, GWL_STYLE, dwHeaderStyle);
nmHeader = (NMHEADER*)hHeader;
// END TEST
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;
}
}
switch (pnmhdr->code)
{
case HDN_FILTERCHANGE:
{
HDITEM hditem;
HDTEXTFILTER hdTFilter;
TCHAR text[260];
LRESULT size;
NMLISTVIEW* nmListView = (NMLISTVIEW*)GetDlgCtrlID(pnmhdr->hwndFrom);
//HWND hHeaderTmp = ListView_GetHeader(hList);
for (int i = 0; i < SendMessageW(hHeader, HDM_GETITEMCOUNT, 0, 0); i++) {
memset(&hditem, 0, sizeof(HDITEM));
memset(text, 0, 260);
hditem.mask = (HDI_FILTER);
hdTFilter.pszText = text;
hdTFilter.cchTextMax = 260;
hditem.type = HDFT_ISSTRING;
hditem.pvFilter = &hdTFilter;
SendMessageW(hHeader, HDM_GETITEM, i, (LPARAM)&hditem);
if (strlen(text) > 0)
{
char buf[256];
char* field;
LVCOLUMN col;
LVITEM item;
ListView_DeleteAllItems(hList);
FILE* 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); // pula a primeira linha...
item.mask = LVIF_TEXT;
for (int iCount = 0; fgets(buf, 255, fp) != NULL; iCount++)
{
char* resultTok = strtok(buf, ",");
if (!startsWith(text, resultTok))
continue;
item.pszText = resultTok;
item.iItem = iCount;
item.iSubItem = 0;
SendMessage(hList, LVM_INSERTITEM, 0, (LPARAM)&item);
for (int iCol = 1; (field = strtok(NULL, ",\n")) != NULL; iCol++) {
item.pszText = field;
item.iItem = iCount;
item.iSubItem = iCol;
SendMessage(hList, LVM_SETITEM, 0, (LPARAM)&item);
}
}
break;
}
}
}
break;
case HDN_FILTERBTNCLICK:
//MessageBox(hWnd, "otro_oi", "Error", MB_OK);
break;
default:
break;
}
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;
//char bufs[256];
//sprintf(bufs, "%d %x", LVM_GETHEADER);
//MessageBox(hWnd, bufs, "Error", MB_OK);
while (GetMessage(&msg, NULL, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions