sashoalm
sashoalm

Reputation: 79467

Move an item up or down in a list box

I have a CListBox, and I want to have a Move Up/Move Down buttons, which move the currently selected item up or down.

Right now I think the only solution is to delete the item and then insert it the new position.

Is there a more efficient way to do it?

Upvotes: 0

Views: 3820

Answers (3)

KungPhoo
KungPhoo

Reputation: 774

A bit late, but here's a working solution for a MFC CListBox.
It supports multi-selection and avoids re-sorting selected items when they reach the top/bottom.


// --------------------------------------------------------------- //
// Move item with index 'item' one place up
// --------------------------------------------------------------- //
void CListBox_MoveItemUp(CListBox& box, int item) {
    if(item <= 0) { return; }
    CString oldstring;
    box.GetText(item, oldstring);
    DWORD_PTR olddata = box.GetItemData(item);
    int oldsel = box.GetSel(item);

    box.DeleteString(item);
    item = box.InsertString(item-1, oldstring);
    box.SetItemData(item, olddata);
    box.SetSel(item, oldsel);
}

// --------------------------------------------------------------- //
// Move all items one place up, if there is space to move
// --------------------------------------------------------------- //
void CListBox_MoveSelectedItemsUp(CListBox& box, std::vector<INT> sels) {
    std::sort(sels.begin(), sels.end());

    // if 0 is selected, it might block all next selected items, too.
    for(int i=0; !sels.empty(); ++i) {
        if(sels.front() == i) {
            sels.erase(sels.begin());
        } else {
            break;
        }
    }

    for(int isel = 0; isel < int(sels.size()); ++isel) {
        int item = int(sels[isel]);
        CListBox_MoveItemUp(box, item);
    }
}

// --------------------------------------------------------------- //
// Move item with index 'item' one place down
// --------------------------------------------------------------- //
void CListBox_MoveItemDown(CListBox& box, int item) {
    if(item+1 >= box.GetCount()) { return; }
    CString oldstring;
    box.GetText(item, oldstring);
    DWORD_PTR olddata = box.GetItemData(item);
    int oldsel = box.GetSel(item);

    box.DeleteString(item);
    item = box.InsertString(item+1, oldstring);
    box.SetItemData(item, olddata);
    box.SetSel(item, oldsel);
}

// --------------------------------------------------------------- //
// Move all items one place down, if there is space to move
// --------------------------------------------------------------- //
void CListBox_MoveSelectedItemsDown(CListBox& box, std::vector<INT> sels) {
    std::sort(sels.begin(), sels.end());

    // if last is selected, it might block all previous selected items, too.
    for(int i=box.GetCount()-1; !sels.empty(); --i) {
        if(sels.back() == i) {
            sels.pop_back();
        } else {
            break;
        }
    }

    for(int isel = int(sels.size())-1; isel>=0; --isel) {
        int item = int(sels[isel]);
        CListBox_MoveItemDown(box, item);
    }
}


//---------------------------------------------------------------//
// Move selected items up in the listbox
//---------------------------------------------------------------//
void MyDialog::OnBnClickedMoveUp() {
    int nsel = m_MyListBox.GetSelCount();
    if(!nsel) { return; }
    std::vector<INT> selectedItems;
    selectedItems.resize(nsel);
    m_MyListBox.GetSelItems(nsel, &selectedItems[0]);
    CListBox_MoveSelectedItemsUp(m_MyListBox, selectedItems);
}


//---------------------------------------------------------------//
// Move selected items down in the listbox
//---------------------------------------------------------------//
void MyDialog::OnBnClickedMoveDown() {
    int nsel = m_MyListBox.GetSelCount();
    if(!nsel) { return; }
    std::vector<INT> selectedItems;
    selectedItems.resize(nsel);
    m_MyListBox.GetSelItems(nsel, &selectedItems[0]);
    CListBox_MoveSelectedItemsDown(m_MyListBox, selectedItems);
}

Upvotes: 0

Pabitra Dash
Pabitra Dash

Reputation: 1513

The following code is working for Move Up.

   void CStreamTable::OnBnClickedMoveUp()
   {
      int item = m_InputStreamListControl.GetNextItem(-1, LVNI_SELECTED);
      if (item == -1)
        return;

      if (item > 0)
      {
          CString name, befehl;
          name = m_InputStreamListControl.GetItemText(item, 0);
          befehl = m_InputStreamListControl.GetItemText(item, 1);
          m_InputStreamListControl.DeleteItem(item);
          m_InputStreamListControl.InsertItem(item - 1, name);
          m_InputStreamListControl.SetItemText(item - 1, 1, befehl);
          m_InputStreamListControl.SetItemState(item - 1, LVNI_SELECTED, LVIS_SELECTED);
       }
    }

Upvotes: 0

dwo
dwo

Reputation: 3636

Here is a snippet I made 10 years ago. It uses delete and add to switch positions, but I think that's the only way.

void CKnoepfeDlg::OnDown() 
{
    int item = m_list.GetNextItem(-1,LVNI_SELECTED);
    if(item == -1) 
        return;

    if(item < m_list.GetItemCount() - 1)
    {
        CString name,befehl;
        name = m_list.GetItemText(item,0);
        befehl = m_list.GetItemText(item,1);
        m_list.DeleteItem(item);
        m_list.InsertItem(item + 1,name);
        m_list.SetItemText(item + 1,1,befehl);
        m_list.SetItemState(item + 1,LVNI_SELECTED,LVIS_SELECTED);
    }
}

Upvotes: 3

Related Questions