使用LVM_SORTITEMSEX将所有选定项目移动到特定项目下方

Alw*_*uff 6 c c++ winapi listview

介绍:

为了使这篇文章尽可能简短,我只想说我需要将列表视图中的所有选定项目移动到某个(未选中)项目下方.

浏览listview文档,我发现了LVM_SORTITEMSEX消息.

题:

如何使用上面的消息来实现我的目标.

我努力解决这个问题:

到目前为止,通过使用此消息,我能够将所有选定的项目移动到列表的底部 - > listview的排序方式使得未选择的项目位于选定的项目之前.

我只是无法弄清楚如何实现在特定项目下移动所选项目.

下面是我得到的图像,以及我想要实现的目标:

在此输入图像描述

左图显示了我使用下面提交的代码时得到的结果,而右图显示了我的目标结果.

以下是相关的代码段:

// compare function -> see the documentation
int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM hwnd)
{
    LVITEM lvi1 = { 0 }, lvi2 = { 0 };
    // get selected state of the first item
    lvi1.iItem = (int)lParam1;
    lvi1.iSubItem = 0;
    lvi1.mask = LVIF_STATE;
    lvi1.stateMask = LVIS_SELECTED;
    ListView_GetItem((HWND)hwnd, &lvi1);
    // get selected state of the second item
    lvi2.iItem = (int)lParam2;
    lvi2.iSubItem = 0;
    lvi2.mask = LVIF_STATE;
    lvi2.stateMask = LVIS_SELECTED;
    ListView_GetItem((HWND)hwnd, &lvi2);
    // if first is selected and second is not selected, swap them
    if ((lvi1.state & LVIS_SELECTED) && (0 == (lvi2.state & LVIS_SELECTED)))
        return 1;

    return 0;
}

// somewhere in code, on button click for example
ListView_SortItemsEx(hwndListView, CompareFunc, hwndListView);
Run Code Online (Sandbox Code Playgroud)

我已经通过了ListView的句柄作为第三个参数ListView_SortItemsEx,所以我可以用ListView_GetItemCompareFunc.

Bar*_*ani 1

如果我理解正确的话,您希望通过拖放来重新排列项目,并且您希望排序功能来完成此操作。如果要在排序过程中完成,这可能会变得复杂。另一种解决办法是先找到安排。

  • 使用向量存储“redMark”之前的项目
  • 添加出现在“redMark”之后的选定项目
  • 添加出现在“redMark”之后的未选定项目
  • 将此订单保存至LVITEM::lParam
  • 打电话ListView_SortItems(不ListView_SortItemsEx

唯一的问题是它可能lParam被用于其他原因。我们必须保存lParam,然后在排序完成后恢复它。

另外如果ListView有的话就更好了LVS_SHOWSELALWAYS

请注意,此方法会移动“redMark”之前的项目。在您的示例中,您应该设置redMark = 3将选择移动到“Item 60”之前

int CALLBACK CompareFunc(LPARAM lp1, LPARAM lp2, LPARAM)
{
    return lp1 > lp2;
}

void sort()
{
    int redMark = 3;
    int count = ListView_GetItemCount(hwndListView);

    std::vector<int> order;
    std::vector<LPARAM> saveLParam(count);

    //add everything before redMark
    for (int i = 0; i < redMark; i++)
        order.push_back(i);

    //add highlighted items
    for (int i = redMark; i < count; i++)
        if (ListView_GetItemState(hwndListView, i, LVIS_SELECTED))
            order.push_back(i);

    //add the rest
    for (int i = redMark; i < count; i++)
        if (!ListView_GetItemState(hwndListView, i, LVIS_SELECTED))
            order.push_back(i);

    if (order.size() != count)
    {
        assert(0);
        return;
    }

    //set lParam
    for (int i = 0; i < count; i++)
    {
        LVITEM item = { 0 };
        item.iItem = order[i];
        item.mask = LVIF_PARAM;

        //save old LParam value
        ListView_GetItem(hwndListView, &item);
        saveLParam[i] = item.lParam;

        //set new lParam
        item.lParam = i;
        ListView_SetItem(hwndListView, &item);
    }

    ListView_SortItems(hwndListView, CompareFunc, 0);

    //restore old lParam
    for (int i = 0; i < count; i++)
    {
        LVITEM item = { 0 };
        item.iItem = order[i];
        item.mask = LVIF_PARAM;
        item.lParam = saveLParam[order[i]];
        ListView_SetItem(hwndListView, &item);
    }

    ::SetFocus(hwndListView);
}
Run Code Online (Sandbox Code Playgroud)