Thread: Moving items in a ListView

  1. #1
    int x = *((int *) NULL); Cactus_Hugger's Avatar
    Join Date
    Jul 2003
    Location
    Banks of the River Styx
    Posts
    902

    Moving items in a ListView

    Since it seems the ListView control had no real way to move items, I attempted to write my own. It's not working. It moves the item, but the subitems of the new item are all blank.

    Here's the code...
    Code:
    /*
     * Moves the selected list view item up or down.
     * hwnd = list view
     * change = -1 for up 1, 1 for down 1, -2 for up two, etc.
     * Returns 0 on success, nonzero on failure.
     */
    int ListView_Move(HWND hwnd, int change)
    {
    	LV_ITEM lvi = {0};
    	int iOld, iNew = -1;
    	char text_buf[1024];
    	int iColumn, nColumns, ret;
    
    	if(!change) return 1;
    	if(change > 0) ++change;
    
    	iOld = ListView_GetNextItem(hwnd, -1, LVNI_SELECTED);
    	if(iOld == -1) return 1;
    
    	lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_PARAM;
    	lvi.iItem = iOld;
    	lvi.pszText = text_buf;
    	lvi.cchTextMax = 1024;
    
    	// Create the new item, with all the info of the old...
    	ListView_GetItem(hwnd, &lvi);
    
    	lvi.iItem += change;
    	iNew = ListView_InsertItem(hwnd, &lvi);
    	// If we create an item above the old one, then the old one moves down one...
    	if(change < 0) ++iOld;
    
    	nColumns = Header_GetItemCount(ListView_GetHeader(hwnd));
    
    	sprintf(text_buf, "%d columns...", nColumns);
    	MessageBox(GetParent(hwnd), text_buf, "", 0);
    
    	// Copy all the subitems from the old to the new
    	for(iColumn = 1; iColumn < nColumns; ++iColumn)
    	{
    		ZeroMemory(&lvi, sizeof(LV_ITEM));
    
    		lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_PARAM;
    		lvi.iItem = iOld;
    		lvi.iSubItem = iColumn;
    		lvi.pszText = text_buf;
    		lvi.cchTextMax = 1024;
    		ListView_GetItem(hwnd, &lvi);
    		MessageBox(GetParent(hwnd), text_buf, "", 0);
    
    		lvi.iItem = iNew;
    		ret = ListView_SetItem(hwnd, &lvi);
    		sprintf(text_buf, "%d = ret... (iNew = %d) last_err = %d?", ret, iNew, GetLastError());
    		MessageBox(hwnd, text_buf, "", 0);
    	}
    
    	ListView_DeleteItem(hwnd, iOld);
    
    	return 0;
    }
    The message boxes are for debugging...
    The first one says there are 3 columns (correct), the second one should say what each subitem's text is (it does, so: correct), and the last tells other stuff. (The return value of ListView_SetItem, iNew (the index of the new item), and GetLastError().) The last messagebox says 0, a correct index value, and 0. GetLastError() is returning 0 (success) and ListView_SetItem is returning 0 (failure). (It apperantly doesn't call SetLastError...)

    Why, though, does ListView_SetItem fail? I'm only changing the iItem member... the rest of it was filled in by ListView_GetItem().

    Thanks in Advance for any help...
    long time; /* know C? */
    Unprecedented performance: Nothing ever ran this slow before.
    Any sufficiently advanced bug is indistinguishable from a feature.
    Real Programmers confuse Halloween and Christmas, because dec 25 == oct 31.
    The best way to accelerate an IBM is at 9.8 m/s/s.
    recursion (re - cur' - zhun) n. 1. (see recursion)

  2. #2
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    According to MSDN, sub-items do not support LVIF_STATE or LVIF_PARAM:
    Quote Originally Posted by MSDN ListView_SetItem
    You cannot set the state or lParam members for subitems because subitems do not have these attributes. In version 4.70 and later, you can set the iImage member for subitems.
    Therefore, the solution is simple, just remove these mask values when you get and set the sub-items:
    Code:
    lvi.mask = LVIF_TEXT | LVIF_IMAGE;
    You may also wish to add a call to move the focus and selection before deleting the old item:
    Code:
    	ListView_SetItemState(hwnd, iNew, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
    	ListView_DeleteItem(hwnd, iOld);
    I thought of a novel way to do this, although much less efficient than your code:
    Code:
    /*
     * ListView_Move helper function.
     */
    int CALLBACK LVMoveCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
    {
    	struct CTX { int src, trg; } *pctx = (struct CTX*) lParamSort;
    
    	if (lParam1 == pctx->src)
    		return (lParam2 >= pctx->trg ? -1 : +1);
    	else if (lParam2 == pctx->src)
    		return (lParam1 >= pctx->trg ? +1 : -1);
    	else
    		return (lParam1 >= lParam2   ? +1 : -1);
    }
    
    /*
     * Moves the selected list view item up or down.
     * hwnd = list view
     * change = -1 for up 1, 1 for down 1, -2 for up two, etc.
     * Returns TRUE on success, FALSE on failure.
     */
    BOOL ListView_Move(HWND hwnd, int change)
    {
    	struct CTX { int src, trg; } ctx;
    
    	ctx.src = ListView_GetNextItem(hwnd, -1, LVNI_SELECTED);
    	ctx.trg = ctx.src + change + (change > 0 ? 1 : 0);
    
    	return ListView_SortItemsEx(hwnd, LVMoveCompareFunc, (LPARAM) &ctx);
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. HELP!!!!emergency Problem~expert please help
    By unknowppl in forum C++ Programming
    Replies: 9
    Last Post: 08-21-2008, 06:41 PM
  2. HELP!!!!emergency ~expert please help
    By unknowppl in forum C Programming
    Replies: 1
    Last Post: 08-19-2008, 07:35 AM
  3. ListView controls - Adding items .. What the beep?
    By IceDane in forum Windows Programming
    Replies: 7
    Last Post: 04-08-2008, 12:07 PM
  4. ListView Items
    By Smoose777 in forum C# Programming
    Replies: 1
    Last Post: 06-21-2003, 12:10 PM
  5. Selected Items in a ListView
    By Lowas in forum Windows Programming
    Replies: 12
    Last Post: 09-01-2001, 07:17 PM