【问题标题】:Move all selected items below specific one with LVM_SORTITEMSEX使用 LVM_SORTITEMSEX 将所有选定项目移动到特定项目之下
【发布时间】:2015-06-06 02:58:34
【问题描述】:

简介:

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

浏览列表视图文档时我遇到了LVM_SORTITEMSEX message

问题:

如何使用上面的信息来实现我的目标。

我为解决这个问题所做的努力:

到目前为止,通过使用此消息,我能够将所有选定的项目移动到列表的底部 -> 列表视图的排序方式是未选定的项目在选定的项目之前。

我只是不知道如何实现将所选项目移动到某个项目下方。

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

左图显示了我使用下面提交的代码时得到的结果,右图显示了我想要的结果。

这里是相关代码sn-ps:

// 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);

我已将列表视图句柄作为第三个参数传递给ListView_SortItemsEx,因此我可以在CompareFunc 中使用ListView_GetItem

【问题讨论】:

  • Visual C++ 的标签有点模糊,它有点指编译器的名称,或特定于它的问题。您可能应该将您的问题标记为CC++,或两者兼有(对我来说C++ 通常包括C,但我知道什么)。另外我认为sort 标签指的是qsortmerge-sort 之类的东西,这不是你感兴趣的,因此无关紧要。
  • @BarmakShemirani:根据您的建议更正了标签。

标签: c++ c listview winapi


【解决方案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);
}

【讨论】:

    【解决方案2】:

    简介:

    • 对于LVM_SORTITEMSEX,所有项目必须具有唯一的lParam's
    • 要将多个参数传递给排序回调,请创建一个结构并将指针传递给它。
    • 一旦您开始排序,项目的原始顺序就会丢失,如果没有保存在某个地方,您将无法再参考它。
    • 如果可以重复移动排序物品的操作,那么精心打造的lParam也不足以知道物品的原始顺序。
    • 您可以乱用lParam,而不是单独准备所需的项目顺序,但这很脏而且容易出错。

    通用解决方案

    • 确保所有项目都有唯一的lParam's
    • 在调用LVM_SORTITEMSEX 之前,按所需顺序准备lParam 的向量:
      1. 枚举列表中从开始到“红色标记”项的项目,将它们的lParam 添加到向量中。
      2. 枚举列表中从“红色标记”项到列表末尾的项,如果该项被选中,则将其lParam 添加到向量中。
      3. 从“红色标记”项到列表末尾枚举列表中的项,如果未选择项,则将其lParam 添加到向量中。
      4. 现在您有lParam 的顺序:列表的开头,然后选择的项目保留其原始顺序,然后未选择的项目保留其原始顺序。
    • 将该向量传递给排序回调
    • 在其中查找两个lParam在向量中的位置,并根据该位置做出回答。例如,如果您发现第一个位置小于第二个,则返回一个负数。典型的方法是return (firstPos - secondPos),它将在一行代码中处理firstPossecondPos 的所有相关顺序。
    • 这将使您的排序回调将准备好的项目顺序应用到列表中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-27
      • 1970-01-01
      • 2014-05-19
      相关资源
      最近更新 更多