使用Win32 API调用LVM_SORTITEMS排序时如何实现中途终止操作?
你遇到的核心原因是LVM_SORTITEMS是同步阻塞调用,你调用SendMessage(hWndLv, LVM_SORTITEMS, lParamSort, pfnMyCompare)触发排序后,整个UI线程会被阻塞,直到ListView控件内部完成全部排序逻辑才会返回。哪怕你在自定义比较函数里提前返回,控件也会执行完所有预设的比较步骤,不会中途终止,所以你会看到比较函数被反复调用。
可行的实现方案如下:
方案一(推荐):改用后台线程做异步排序
这个方案不会阻塞UI,支持用户随时中断,体验最好:
- 首先提取ListView所有项的排序依赖数据(比如每个项的
LPARAM绑定的业务属性),拷贝到独立的、工作线程可访问的数组中,不要在工作线程直接操作UI控件。 - 定义一个
volatile修饰的全局/类成员标志位,比如volatile BOOL g_isSortCanceled = FALSE;,保证多线程场景下变量修改可以实时被读取。 - 用户点击停止按钮时,UI线程直接将
g_isSortCanceled设置为TRUE即可。 - 后台线程执行排序逻辑时,每次比较前先检查
g_isSortCanceled,如果为TRUE立刻终止排序流程,退出工作线程。 - 排序结束(含主动取消场景)后,通过
PostMessage给UI线程发自定义消息通知结果:- 排序正常完成:UI线程批量更新ListView的项顺序即可,不需要再调用控件自带的排序接口。
- 排序被取消:不需要调整ListView显示,直接恢复UI状态即可。
方案二(不推荐):基于控件自带排序的快速终止
如果你不愿意修改排序逻辑到后台线程,可以用这个方案规避,但是排序过程依然会阻塞UI:
- 同样定义上述的
g_isSortCanceled停止标志位。 - 在你的自定义比较函数入口先检查该标志位,如果为
TRUE直接返回0,跳过你的耗时业务逻辑。 - 这个方案不会终止控件的排序流程,但是会让所有比较步骤跳过耗时逻辑,快速跑完所有比较调用,相当于提前结束整个
SendMessage调用。排序结束后你自行恢复ListView原来的顺序即可。
内容的提问来源于stack exchange,提问作者r webby
相关产品推荐
相关产品推荐

