c++ - 如何保持 Windows ListView 控件和它们映射到的对象同步?

标签 c++ windows winapi

我有几个包含映射到同一对象数组的 ListView 控件的窗口。一切正常,直到我对其中之一进行排序。据我了解,这会更改项目的索引(尽管尝试强制 iItem 等于对象成员“id”)。问题是,如果我在更改默认排序后删除 ListView 项目,它会删除同一位置的其他控件中的项目,并且还会破坏对象之间的链接。例如,假设我拥有的默认 4 个项目最初的顺序是 A、B、C、D(在窗口 1 和窗口 2 中)。然后我将窗口 1 中的控件重新排序为 D、C、B、A 并删除 B。在窗口 2 中,项目 C 将被删除,因为它位于相同的位置。

我可以循环遍历每个项目来比较文本,但这似乎效率很低。是否有办法将 ListView 项映射到不会更改的内部 id?如果没有,有什么想法可以让这项工作在不跨越太多障碍的情况下进行吗?

提前致谢。

最佳答案

在虚拟模式下使用 ListView,并在请求时让它们从同一源数组中提取数据值。如果您需要单独对 ListView 进行排序/操作,只需为每个 ListView 创建单独的数组,并让这些数组仅包含指向主数组元素的指针(或索引)。然后,您可以根据需要对每个 ListView 数组中的项目进行排序和删除,而不会影响其他 ListView,也不会浪费内存在各处复制源数据。不要将实际数据存储在 ListView 本身中。

例如:

std::vector<std::string> MainData(4);
Main[0] = "A";
Main[1] = "B";
Main[2] = "C";
Main[3] = "D";

std::vector<int> ListView1Data(MainData.size());
for (int i = 0; i < ListView1Data.size(); ++i)
    ListView1Data[i] = i;

hListView1 = CreateWindowEx(..., LVS_OWNERDATA, ...);
ListView_SetItemCount(hListView1, ListView1Data.size()); 

...

case LVN_GETDISPINFO:
{
    NMLVDISPINFO* pdi = reinterpret_cast<NMLVDISPINFO*>(lParam);
    int index = ListView1Data[pdi->item.iItem];
    if (pdi->item.mask & LVIF_TEXT)
        strncpy(pdi->item.pszText, MainData[index].c_str(), pdi->item.cchTextMax);
    ...
    break;
}

bool CompareListItems(int a, int b)
{
    return MainData[a] < MainData[b];    
}

std::sort(ListView1Data.begin(), ListView1Data.end(), CompareListItems);
ListView_RedrawItems(hListView1, 0, ListView1Data.size());

ListView1Data.erase(ListView1Data.begin()+index);
ListView_SetItemCount(hListView1, ListView1Data.size()); 

如果您想删除一个 ListView 中的一项,并在其他 ListView 中删除相同的项,无论其本地排序如何,您也可以这样做:

int MainIndex = ListView1Data[index];

std::vector<int>::iterator iter = ListView1Data.begin()+index;
ListView2Data.erase(iter);
ListView_SetItemCount(hListView1, ListView1Data.size()); 

iter = std::find(ListView2Data.begin(), ListView2Data.end(), MainIndex);
ListView2Data.erase(iter);
ListView_SetItemCount(hListView2, ListView2Data.size()); 

iter = std::find(ListView3Data.begin(), ListView3Data.end(), MainIndex);
ListView3Data.erase(iter);
ListView_SetItemCount(hListView3, ListView3Data.size()); 

...

最棘手的部分是您是否还需要从主数组中删除相同的项目。在这种情况下,您必须根据需要使用新的指针/索引更新每个 ListView 数组。在这种情况下,为每个主数组项指定一个唯一的 ID,然后在每个 ListView 数组中跟踪该 ID 就变得有意义了。然后,每当需要访问该项目的数据时,每个 ListView 都可以在主数组中查找 ID。

关于c++ - 如何保持 Windows ListView 控件和它们映射到的对象同步?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22081357/

相关文章:

c++ - Win32 应用程序使用 printf 将输出写入控制台

c++ - 重命名为 C++ 的 C 文件在重命名后是否可以用 C++ 编译器进行编译?

c++ - 是否有理由更喜欢一个变量的多个 unordered_map 而不是一个结构?

php - 在 Windows 上使用 PHP fork /线程的最佳方法是什么?

windows - 如何在 docker-compose.yml 中包含 Docker 主机的 IP?

使用 Java 的 Windows 运行应用程序列表

java - 完全合格的路径Vs。规范路径

C++/Win32 : Keyboard input to a non-foreground window

c++ - 在 MFC 中实现缩放控件

c++ - 使用互斥锁正确编写的代码是否仍然易变?