1

我使用任务管理器查看动态创建的控件,发现每次使用 ImageList 创建 TreeView 时,每次销毁树并再次创建时, GDI 对象计数都会增加 4。但是,ListView 从来没有问题。

我知道状态图像的TVS_CHECKBOXES问题并且已经破坏了状态图像列表,但我随后实施了:

ImageList_Destroy(TreeView_SetImageList(GetHandle(), nullptr, TVSIL_NORMAL));

现在资源泄漏已经消失了。

到目前为止,您似乎必须手动清理以下图像WM_DESTROY

Button_SetImageList() - Have to set it to switch it to `BUTTON_IMAGELIST.himl=BCCL_NOGLYPH` to clear it.
TreeView_SetImageList(LVILS_STATE) - if you set it or used `TVS_CHECKBOXES`
TreeView_SetImageList(LVILS_NORMAL) - if you set it
BM_SETIMAGE and STM_SETIMAGE - destroy your own but also set to NULL and destroy returned handle to get rid of potential hidden bitmap handle if different handle than your own.

但是 ListView 是不同的,是按设计还是我应该继续WM_DESTROY使用类似的东西:

ImageList_Destroy(ListView_SetImageList(GetHandle(), nullptr, LVSIL_STATE));
ImageList_Destroy(ListView_SetImageList(GetHandle(), nullptr, LVSIL_SMALL));
ImageList_Destroy(ListView_SetImageList(GetHandle(), nullptr, LVSIL_NORMAL));

请注意,使用WM_NCDESTROYTreeViews 为时已晚。

4

2 回答 2

3

这两个控制在这方面是不一致的。

树控件不拥有您提供给它的图像列表的所有权,因此您仍然负责释放它。

listview 控件确实拥有所有权,除非您设置LVS_SHAREIMAGELISTS窗口样式。

请注意,树控件也有一个相关的怪癖;如果你设置了TVS_CHECKBOXES样式,你有责任释放状态图像列表,即使你没有创建它。

于 2021-09-18T02:40:20.807 回答
1

您所看到的是记录在案的行为。

对于树视图:

TVM_SETIMAGELIST 消息
TreeView_SetImageList 宏

树视图控件不会破坏使用此消息指定的图像列表。当不再需要图像列表时,您的应用程序必须销毁它。

也:

树视图控件窗口样式

持续的 描述
TVS_CHECKBOXES 4.70 版。为树视图控件中的项目启用复选框。仅当图像与项目相关联时才会显示复选框。当设置为此样式时,控件有效地使用 DrawFrameControl 创建和设置包含两个图像的状态图像列表。状态图像 1 是未选中的框,状态图像 2 是选中的框。将状态图像设置为零会完全删除该复选框。有关更多信息,请参阅使用状态图像索引。

版本 5.80。即使没有图像与该项目关联,也显示一个复选框。使用此样式创建树视图控件后,无法删除该样式。相反,您必须销毁控件并在其位置创建一个新控件。销毁树视图控件不会破坏复选框状态图像列表。你必须明确地销毁它。通过向树视图控件发送消息来获取状态图像列表的句柄TVM_GETIMAGELIST。然后用 销毁图像列表ImageList_Destroy

如果要使用此样式,则必须在创建树视图控件之后和填充树之前设置TVS_CHECKBOXES样式。SetWindowLong否则,复选框可能会显示为未选中,具体取决于时间问题。

与 ListView 相比:

LVM_SETIMAGELIST 消息
ListView_SetImageList 宏

当前图像列表将在列表视图控件被销毁时被销毁,除非LVS_SHAREIMAGELISTS设置了样式。如果您使用此消息将一个图像列表替换为另一个,您的应用程序必须显式销毁除当前图像列表之外的所有图像列表。

于 2021-09-18T02:40:31.510 回答