Skip to content

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

@bencz

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;
}

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions