1
votes

I'm using C++ under MSVC 2012 on Windows. I'm using pure Win32 w/ dialogs, no MFC.

I have the LVITEM struct for a given item. I would like to change the index of the item on the given ListView so that I can reorder the positions of the items. The .iItem property is essentially what I'm trying to change, however, I don't know how to have the change reflect in the list view.

If possible, I'd like the ListView to automatically shift the items below where I move the item, not overwrite the existing item in the new position.

3
Are you talking about when the ListView is in report (details) mode, or one of the icon views?Cody Gray
Report/detail view :)kvanbere
I don't think it's possible to move the items by changing their index. There's no LVM_SETITEMINFO message or anything like that. (Well, there is LVM_SETITEM, but that can't change the index because it uses it to identify the item.) The only way I've ever seen it done is removing the item from its current location, and re-inserting it into the new location. Hopefully someone else knows something I don't!Cody Gray
Alas, that'd destroy the subitems as far as I know, and I need to preserve the subitems :(kvanbere

3 Answers

2
votes

The index of a list view item will only change as a side-effect of manipulating the item collection. You incrementing it by inserting a new item before it, LVM_INSERTITEM. You decrement it by removing an item before it, LVM_DELETEITEM. You move an item by deleting it first, then re-inserting it at another position. Or by swapping the LVITEM properties.

Having to take care of sub-items makes this a bit awkward, but such are the hassles of writing native win32 code. Which is why there are so many class libraries available to make this easier. Recommended.

1
votes

there is a way to move listview's items without deleting/recreating them: SORTING

If you want to move an item BEFORE other reference item, this code must do the trick:

struct info {
   int item_to_move_before_reference;
   int item_reference;
};

int CALLBACK CompareFunc(LPARAM item1, LPARAM item2, info* i) {

   if(item1 == i->item_to_move_before_reference) {
      item1 = i->item_reference;
   } else if(item1 >= i->item_reference) {
      item1++;
   }

   if(item2 == i->item_to_move_before_reference) {
      item2 = i->item_reference;
   } else if(item2 >= i->item_reference) {
      item2++;
   }

   return item1 - item2;
}

bool sort_items(HWND listview, int item_to_move_before_reference, int item_reference) {
   if(item_to_move_before_reference < item_reference) return false;
   info i;
   i.item_to_move_before_reference = item_to_move_before_reference;
   i.item_reference = item_reference;
   ListView_SortItemsEx(listview, CompareFunc, &i);
   return true;
}
0
votes

Here a snippet :)

bool isUp = ...;
HWND hListWnd = ...;
int pos = ListView_GetNextItem(hListWnd, -1, LVNI_SELECTED);
if (pos == -1 || pos == 0 && isUp || pos == ListView_GetItemCount(hListWnd) - 1 && !isUp)
    return true;

pos = isUp ? pos - 1 : pos;

HWND hHeader = ListView_GetHeader(hListWnd);
for (int i = 0; i < Header_GetItemCount(hHeader); i++) {
    TCHAR buf[255]{0};
    ListView_GetItemText(hListWnd, pos, i, buf, 255);
    LVITEM lvi = {0};
    lvi.mask = LVIF_TEXT;
    lvi.iItem = pos + 2;
    lvi.iSubItem = i;
    lvi.pszText = buf;
    lvi.cchTextMax = 255;
    if (i == 0)
        ListView_InsertItem(hListWnd, &lvi);
    else
        ListView_SetItem(hListWnd, &lvi);
}

ListView_DeleteItem(hListWnd, pos);

if (!isUp)
    ListView_SetItemState (hListWnd, pos + 1, LVIS_FOCUSED | LVIS_SELECTED, 0x000F);