Hello. I am trying to make a Listview (WC_LISTVIEW) arrange items in descending order at all times.
When I use the LVS_SORTDESCENDING style and I insert multiple items at once it seems to work fine, but when I add items one at a time the previously inserted items don't get re-arranged in descending order. I assume this is because LV_VIEW_ICON allows you to reposition items manually, so that is probably why it won't re-arrange previously inserted items once inserted. However, I want to have items arranged in descending order at all times because I won't allow the manual moving of items. How would I do this? By using LVM_SETITEMPOSITION after item insert? I have tried that but it seems to be very slow.
Thanks in advance.
Reproducible code:
#include <windows.h>
#include <CommCtrl.h>
#include <string>
::HINSTANCE g_hInstance = NULL;
// function fwd decls.
::HWND createWindow();
::HWND createListview(::HWND hParentWnd);
::HWND createButton(::HWND hParentWnd, int x, int y, std::string text);
int insertItem(::HWND hWndListview, std::string text);
void removeAllItems(::HWND hWndListview);
::HWND g_hWndWindow;
::HWND g_hWndListview;
::HWND g_hWndButton1;
::HWND g_hWndButton2;
::HWND g_hWndButton3;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, char* szCmdLine, int iCmdShow) {
g_hInstance = hInstance;
g_hWndWindow = createWindow();
g_hWndListview = createListview(g_hWndWindow);
g_hWndButton1 = createButton(g_hWndWindow, 440, 30, "Add 5 Items");
g_hWndButton2 = createButton(g_hWndWindow, 440, 90, "Add 10 Items");
g_hWndButton3 = createButton(g_hWndWindow, 440, 150, "Remove All Items");
MSG msg = { 0 };
while ((GetMessage(&msg, NULL, 0, 0))) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 1;
}
::LRESULT CALLBACK windowProc(::HWND hWnd, ::UINT msg, ::WPARAM wParam, ::LPARAM lParam) {
switch (msg) {
case WM_COMMAND:
{
switch (HIWORD(wParam)) {
case BN_CLICKED:
{
if (!g_hWndListview)
break;
int itemCount = ::SendMessage(g_hWndListview, LVM_GETITEMCOUNT, 0, 0);
::HWND hButtonWnd = (::HWND)lParam;
if (hButtonWnd == g_hWndButton1) {
for (int i = 0; i < 5; i++) {
insertItem(g_hWndListview, "Item " + std::to_string(itemCount + i));
}
} else if (hButtonWnd == g_hWndButton2) {
for (int i = 0; i < 10; i++) {
insertItem(g_hWndListview, "Item " + std::to_string(itemCount + i));
}
} else if (hButtonWnd == g_hWndButton3) {
removeAllItems(g_hWndListview);
}
break;
}
}
break;
}
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
::HWND createWindow() {
::WNDCLASS wndClass = { };
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hbrBackground = (::HBRUSH)::GetStockObject(GRAY_BRUSH);
wndClass.hCursor = ::LoadCursor(NULL, IDC_ARROW);
wndClass.hIcon = ::LoadIcon(NULL, IDC_ICON);
wndClass.hInstance = g_hInstance;
wndClass.lpfnWndProc = windowProc;
wndClass.lpszClassName = "Window1";
wndClass.lpszMenuName = NULL;
wndClass.style = CS_HREDRAW | CS_VREDRAW/* | CS_OWNDC | CS_PARENTDC*/;
if (!::RegisterClass(&wndClass))
return 0;
::HWND hWnd = ::CreateWindowEx(0,
"Window1",
"Window1",
WS_OVERLAPPEDWINDOW,
20, 20, 800, 800,
NULL,
(::HMENU)NULL,
g_hInstance,
0);
::ShowWindow(hWnd, SW_SHOW);
::UpdateWindow(hWnd);
return hWnd;
}
::HWND createListview(::HWND hParentWnd) {
::HWND hWnd = ::CreateWindowEx(0,
WC_LISTVIEW,
WC_LISTVIEW,
WS_CHILD | LVS_ICON | LVS_SORTDESCENDING,
20, 20, 400, 400,
hParentWnd,
(::HMENU)NULL,
g_hInstance,
0);
if (!hWnd)
return NULL;
::HIMAGELIST hImageList = ImageList_Create(32, 32, ILC_COLOR32 | ILC_MASK, 0, 0);
::SendMessage(hWnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (::LPARAM)hImageList);
ListView_SetBkColor(hWnd, RGB(0, 255, 0));
::ShowWindow(hWnd, SW_SHOW);
::UpdateWindow(hWnd);
return hWnd;
}
::HWND createButton(::HWND hParentWnd, int x, int y, std::string text) {
::HWND hWnd = ::CreateWindowEx(0,
WC_BUTTON,
text.c_str(),
WS_CHILD,
x, y, 120, 50,
hParentWnd,
(::HMENU)NULL,
g_hInstance,
0);
if (!hWnd)
return NULL;
::ShowWindow(hWnd, SW_SHOW);
::UpdateWindow(hWnd);
return hWnd;
}
int insertItem(::HWND hWndListview, std::string text) {
::LVITEM lvItem = { 0 };
lvItem.mask = LVIF_TEXT;
lvItem.pszText = (char*)text.c_str();
lvItem.cchTextMax = text.length();
lvItem.iItem = 1;
int insertedItemIndex = ::SendMessage(hWndListview, LVM_INSERTITEM, 0, (::LPARAM)&lvItem);
// Simple code to manually position items.
/*
int itemCount = ::SendMessage(g_hWndListview, LVM_GETITEMCOUNT, 0, 0);
for (int i = 0; i < itemCount; i++) {
int itemsPerRow = 5;
int x = i % itemsPerRow * 40;
int y = i / itemsPerRow * 40;
::SendMessage(hWndListview, LVM_SETITEMPOSITION, i, MAKELPARAM(x, y));
}*/
return insertedItemIndex;
}
void removeAllItems(::HWND hWndListview) {
::SendMessage(hWndListview, LVM_DELETEALLITEMS, 0, 0);
}