找回密码
 加入
搜索
查看: 9236|回复: 18

[AU3基础] [已解决]使用_AddArray 做成的 ListView 如何用 _SortItems来排序??

  [复制链接]
发表于 2012-8-24 01:23:41 | 显示全部楼层 |阅读模式
本帖最后由 kk_lee69 于 2012-8-24 21:37 编辑

使用_GUICtrlListView_AddArray 做成的 ListView 如何用 _GUICtrlListView_SortItems來排序??

如下例子....

已經研究出來.....感謝 athland5013 兄 大力的幫忙.....

結論是  系統原生自帶的 _GUICtrlListView_AddArray  在加入 LISTVIEW 的過程中....沒有加入 Param
而 GUICtrlListView_Sort是排序的主体,再看看他工作原理,是要 DllStructSetData($tInfo, "Param", $nItem1)
所以 LISTVIEW  沒有 Param  就無法排序.....  所以 在 athland5013 兄 的幫忙下 改了 原本的 _GUICtrlListView_AddArray

換個名子.....當然要用的時候 可以直接加在主程式裡面  不過 不要忘記 #include <GuiListView.au3>

代碼如下:....

Func _ListViewAddArray($hWnd, ByRef $aItems)
        If $Debug_LV Then __UDF_ValidateClassName($hWnd, $__LISTVIEWCONSTANT_ClassName)

        Local $fUnicode = _GUICtrlListView_GetUnicodeFormat($hWnd)

        Local $tItem = DllStructCreate($tagLVITEM)
        Local $pItem = DllStructGetPtr($tItem)
        Local $tBuffer
        If $fUnicode Then
                $tBuffer = DllStructCreate("wchar Text[4096]")
        Else
                $tBuffer = DllStructCreate("char Text[4096]")
        EndIf
        Local $pBuffer = DllStructGetPtr($tBuffer)
        
        DllStructSetData($tItem, "Text", $pBuffer)
        DllStructSetData($tItem, "TextMax", 4096)
        Local $iLastItem = _GUICtrlListView_GetItemCount($hWnd)
        _GUICtrlListView_BeginUpdate($hWnd)
        If IsHWnd($hWnd) Then
                If _WinAPI_InProcess($hWnd, $_lv_ghLastWnd) Then
                        For $iI = 0 To UBound($aItems) - 1
                                DllStructSetData($tItem, "Mask", BitOR($LVIF_TEXT, $LVIF_PARAM))
                                DllStructSetData($tItem, "Param",  $iLastItem + $iI)
                                
                                DllStructSetData($tItem, "Item", $iI)
                                DllStructSetData($tItem, "SubItem", 0)
                                DllStructSetData($tBuffer, "Text", $aItems[$iI][0])
                                GUICtrlSendMsg($hWnd, $LVM_INSERTITEMW, 0, $pItem)
                                
                                DllStructSetData($tItem, "Mask", $LVIF_TEXT)
                                For $iJ = 1 To UBound($aItems, 2) - 1
                                        DllStructSetData($tItem, "Mask", BitOR($LVIF_TEXT))
                                        DllStructSetData($tItem, "SubItem", $iJ)
                                        DllStructSetData($tBuffer, "Text", $aItems[$iI][$iJ])
                                        GUICtrlSendMsg($hWnd, $LVM_SETITEMW, 0, $pItem)
                                Next
                        Next
                Else
                        Local $iBuffer = DllStructGetSize($tBuffer)
                        Local $iItem = DllStructGetSize($tItem)
                        Local $tMemMap
                        Local $pMemory = _MemInit($hWnd, $iItem + $iBuffer, $tMemMap)
                        Local $pText = $pMemory + $iItem
                        DllStructSetData($tItem, "Text", $pText)
                        For $iI = 0 To UBound($aItems) - 1
                                DllStructSetData($tItem, "Item", $iI + $iLastItem)
                                DllStructSetData($tItem, "SubItem", 0)
                                DllStructSetData($tBuffer, "Text", $aItems[$iI][0])
                                _MemWrite($tMemMap, $pItem, $pMemory, $iItem)
                                _MemWrite($tMemMap, $pBuffer, $pText, $iBuffer)
                                If $fUnicode Then
                                        GUICtrlSendMsg($hWnd, $LVM_INSERTITEMW, 0, $pMemory)
                                Else
                                        GUICtrlSendMsg($hWnd, $LVM_INSERTITEMA, 0, $pMemory)
                                EndIf
                                For $iJ = 1 To UBound($aItems, 2) - 1
                                        DllStructSetData($tItem, "SubItem", $iJ)
                                        DllStructSetData($tBuffer, "Text", $aItems[$iI][$iJ])
                                        _MemWrite($tMemMap, $pItem, $pMemory, $iItem)
                                        _MemWrite($tMemMap, $pBuffer, $pText, $iBuffer)
                                        If $fUnicode Then
                                                GUICtrlSendMsg($hWnd, $LVM_SETITEMW, 0, $pMemory)
                                        Else
                                                GUICtrlSendMsg($hWnd, $LVM_SETITEMA, 0, $pMemory)
                                        EndIf
                                Next
                        Next
                        _MemFree($tMemMap)
                EndIf
        Else
                For $iI = 0 To UBound($aItems) - 1
                        DllStructSetData($tItem, "Mask", BitOR($LVIF_TEXT, $LVIF_PARAM))
                        DllStructSetData($tItem, "Param",  $iLastItem + $iI)
                        DllStructSetData($tItem, "Item", $iI + $iLastItem)
                        DllStructSetData($tItem, "SubItem", 0)
                        DllStructSetData($tBuffer, "Text", $aItems[$iI][0])
                        If $fUnicode Then
                                GUICtrlSendMsg($hWnd, $LVM_INSERTITEMW, 0, $pItem)
                        Else
                                GUICtrlSendMsg($hWnd, $LVM_INSERTITEMA, 0, $pItem)
                        EndIf
                        DllStructSetData($tItem, "Mask", $LVIF_TEXT)
                        For $iJ = 1 To UBound($aItems, 2) - 1
                                DllStructSetData($tItem, "SubItem", $iJ)
                                DllStructSetData($tBuffer, "Text", $aItems[$iI][$iJ])
                                If $fUnicode Then
                                        GUICtrlSendMsg($hWnd, $LVM_SETITEMW, 0, $pItem)
                                Else
                                        GUICtrlSendMsg($hWnd, $LVM_SETITEMA, 0, $pItem)
                                EndIf
                        Next
                Next
        EndIf
        _GUICtrlListView_EndUpdate($hWnd)
EndFunc   ;==>_ListViewAddArray
发表于 2012-8-24 07:32:04 | 显示全部楼层
兄弟,都说了原版自带的<GuiListView.au3>里面 AddArray不能用SortItems排序的,需要修改一下的

你试试用AddItem,AddsubItem函数就可以排序,~~~~~~~~~~原因是:

你打开<GuiListView.au3>仔细看一下AddItem,AddsubItem,AddArray,SortItems,_RegisterSortCallBack,__GUICtrlListView_Sort里面的工作原理,你了解了就会明白 AddArray添加的item为什么在SortItems时不工作了


关键词:Param


另外在ListView排序是很慢的,如果上千上万条你会砸机的,还不如在sql里面干脆~~~~
发表于 2012-8-24 08:17:02 | 显示全部楼层
我也想知道,等高人
 楼主| 发表于 2012-8-24 11:43:06 | 显示全部楼层
本帖最后由 kk_lee69 于 2012-8-24 11:44 编辑

回复 2# athland5013

我知道你回過我

但_GUICtrlListView_AddArray不能用_GUICtrlListView_SortItems排序
要排序需要
修改 DllStructSetData($tItem, "Mask", BitOR($LVIF_TEXT, $LVIF_PARAM))
添加 DllStructSetData($tItem, "Param", _SendMessage($hWnd, $LVM_GETITEMCOUNT) + 11111111)


但是 這段話我琢磨了好久....也改了很多地方....就沒成功的....

老實說我的功力不夠 我看了他們的工作原理 但是 對於  DllStructSetData 這樣的東西  老實說看不懂.....P.S 本身不是寫程式出身的

所以只能用錯誤嘗試法....將您的提示 改在我認為的地方....但是老是不行.....所以又上來提問的 .....感謝回覆

在LISTVIEW 排序 在某些情況下 還是會用到 所以想研究出來 看看如何改的
发表于 2012-8-24 12:05:20 | 显示全部楼层
本帖最后由 athland5013 于 2012-8-24 12:22 编辑

把你修改的_GUICtrlListView_AddArray贴来看看,我跟你再探讨一下,授鱼不如授渔嘛

还有论坛某位大师说过,了解UDF的工作原理对你的提高有莫大的帮助
 楼主| 发表于 2012-8-24 12:33:31 | 显示全部楼层
回复 5# athland5013
感謝 !!

因為您提到了  修改 所以我找到了 DllStructSetData($tItem, "Mask", $LVIF_TEXT) 改成了
DllStructSetData($tItem, "Mask", BitOR($LVIF_TEXT, $LVIF_PARAM)) 再加上一行
DllStructSetData($tItem, "Param", _SendMessage($hWnd, $LVM_GETITEMCOUNT) + 11111111)
但是 畫面就會只剩下 第一行 然後其他的都不見了....

Func _GUICtrlListView_AddArray($hWnd, ByRef $aItems)
        If $Debug_LV Then __UDF_ValidateClassName($hWnd, $__LISTVIEWCONSTANT_ClassName)

        Local $fUnicode = _GUICtrlListView_GetUnicodeFormat($hWnd)

        Local $tItem = DllStructCreate($tagLVITEM)
        Local $pItem = DllStructGetPtr($tItem)
        Local $tBuffer
        If $fUnicode Then
                $tBuffer = DllStructCreate("wchar Text[4096]")
        Else
                $tBuffer = DllStructCreate("char Text[4096]")
        EndIf
        Local $pBuffer = DllStructGetPtr($tBuffer)
        ;DllStructSetData($tItem, "Mask", $LVIF_TEXT)
        DllStructSetData($tItem, "Mask", BitOR($LVIF_TEXT, $LVIF_PARAM))
        DllStructSetData($tItem, "Param", _SendMessage($hWnd, $LVM_GETITEMCOUNT) + 11111111)
        DllStructSetData($tItem, "Text", $pBuffer)
        DllStructSetData($tItem, "TextMax", 4096)
        Local $iLastItem = _GUICtrlListView_GetItemCount($hWnd)
        _GUICtrlListView_BeginUpdate($hWnd)
        If IsHWnd($hWnd) Then
                If _WinAPI_InProcess($hWnd, $_lv_ghLastWnd) Then
                        For $iI = 0 To UBound($aItems) - 1
                                DllStructSetData($tItem, "Item", $iI)
                                DllStructSetData($tItem, "SubItem", 0)
                                DllStructSetData($tBuffer, "Text", $aItems[$iI][0])
                                _SendMessage($hWnd, $LVM_INSERTITEMW, 0, $pItem, 0, "wparam", "ptr")
                                For $iJ = 1 To UBound($aItems, 2) - 1
                                        DllStructSetData($tItem, "SubItem", $iJ)
                                        DllStructSetData($tBuffer, "Text", $aItems[$iI][$iJ])
                                        _SendMessage($hWnd, $LVM_SETITEMW, 0, $pItem, 0, "wparam", "ptr")
                                Next
                        Next
                Else
                        Local $iBuffer = DllStructGetSize($tBuffer)
                        Local $iItem = DllStructGetSize($tItem)
                        Local $tMemMap
                        Local $pMemory = _MemInit($hWnd, $iItem + $iBuffer, $tMemMap)
                        Local $pText = $pMemory + $iItem
                        DllStructSetData($tItem, "Text", $pText)
                        For $iI = 0 To UBound($aItems) - 1
                                DllStructSetData($tItem, "Item", $iI + $iLastItem)
                                DllStructSetData($tItem, "SubItem", 0)
                                DllStructSetData($tBuffer, "Text", $aItems[$iI][0])
                                _MemWrite($tMemMap, $pItem, $pMemory, $iItem)
                                _MemWrite($tMemMap, $pBuffer, $pText, $iBuffer)
                                If $fUnicode Then
                                        _SendMessage($hWnd, $LVM_INSERTITEMW, 0, $pMemory, 0, "wparam", "ptr")
                                Else
                                        _SendMessage($hWnd, $LVM_INSERTITEMA, 0, $pMemory, 0, "wparam", "ptr")
                                EndIf
                                For $iJ = 1 To UBound($aItems, 2) - 1
                                        DllStructSetData($tItem, "SubItem", $iJ)
                                        DllStructSetData($tBuffer, "Text", $aItems[$iI][$iJ])
                                        _MemWrite($tMemMap, $pItem, $pMemory, $iItem)
                                        _MemWrite($tMemMap, $pBuffer, $pText, $iBuffer)
                                        If $fUnicode Then
                                                _SendMessage($hWnd, $LVM_SETITEMW, 0, $pMemory, 0, "wparam", "ptr")
                                        Else
                                                _SendMessage($hWnd, $LVM_SETITEMA, 0, $pMemory, 0, "wparam", "ptr")
                                        EndIf
                                Next
                        Next
                        _MemFree($tMemMap)
                EndIf
        Else
                For $iI = 0 To UBound($aItems) - 1
                        DllStructSetData($tItem, "Item", $iI + $iLastItem)
                        DllStructSetData($tItem, "SubItem", 0)
                        DllStructSetData($tBuffer, "Text", $aItems[$iI][0])
                        If $fUnicode Then
                                GUICtrlSendMsg($hWnd, $LVM_INSERTITEMW, 0, $pItem)
                        Else
                                GUICtrlSendMsg($hWnd, $LVM_INSERTITEMA, 0, $pItem)
                        EndIf
                        For $iJ = 1 To UBound($aItems, 2) - 1
                                DllStructSetData($tItem, "SubItem", $iJ)
                                DllStructSetData($tBuffer, "Text", $aItems[$iI][$iJ])
                                If $fUnicode Then
                                        GUICtrlSendMsg($hWnd, $LVM_SETITEMW, 0, $pItem)
                                Else
                                        GUICtrlSendMsg($hWnd, $LVM_SETITEMA, 0, $pItem)
                                EndIf
                        Next
                Next
        EndIf
        _GUICtrlListView_EndUpdate($hWnd)
EndFunc   ;==>_GUICtrlListView_AddArray
发表于 2012-8-24 18:57:23 | 显示全部楼层
本帖最后由 athland5013 于 2012-8-24 19:00 编辑

中午码了几百字, 提交时论坛居然宕机了, 气死~~~~~~~~

;

For $iI = 0 To UBound($aItems) - 1
        
        ;DllStructSetData($tItem, "Param", _SendMessage($hWnd, $LVM_GETITEMCOUNT) + 11111111)
        ;应该加在这里24-28行之间,放在你那位置Param值是相同的,所以只有一行,因为Param要求是唯一的
        ;然而上面有一句 $iLastItem = _GUICtrlListView_GetItemCount($hWnd) 等同于 _SendMessage($hWnd, $LVM_GETITEMCOUNT)
        ;所以写成以下就可以了
        DllStructSetData($tItem, "Param", $iLastItem + $iI);你可以在 $iI后面再加大数值,效果一样,反正每个item的Param都不同就是了
        
        DllStructSetData($tItem, "Item", $iI)
        DllStructSetData($tItem, "SubItem", 0)
        DllStructSetData($tBuffer, "Text", $aItems[$iI][0])
        _SendMessage($hWnd, $LVM_INSERTITEMW, 0, $pItem, 0, "wparam", "ptr")
Next
;


;

;然后你会遇到另一个问题,subitem不出来了,仔细看一下AddItem,AddsubItem的工作原理,
;AddsubItem时Mask成员只有$LVIF_TEXT,不需要$LVIF_PARAM,而AddItem是需要的

_SendMessage($hWnd, $LVM_INSERTITEMW, 0, $pItem, 0, "wparam", "ptr")
;所以在28-29行之间加一句,把Mask修改为只有$LVIF_TEXT成员
DllStructSetData($tItem, "Mask", $LVIF_TEXT)

For $iJ = 1 To UBound($aItems, 2) - 1
Next
;



;

;因为上面的修改导致Mask成员改变,所以需要把你的第16行
;DllStructSetData($tItem, "Mask", BitOR($LVIF_TEXT, $LVIF_PARAM))
;移动到24-28行之间
;即
For $iI = 0 To UBound($aItems) - 1
        DllStructSetData($tItem, "Mask", BitOR($LVIF_TEXT, $LVIF_PARAM))
        DllStructSetData($tItem, "Param", $iLastItem + $iI)
        DllStructSetData($tItem, "Item", $iI)
        DllStructSetData($tItem, "SubItem", 0)
        DllStructSetData($tBuffer, "Text", $aItems[$iI][0])
        _SendMessage($hWnd, $LVM_INSERTITEMW, 0, $pItem, 0, "wparam", "ptr")
        
        DllStructSetData($tItem, "Mask", $LVIF_TEXT)
        For $iJ = 1 To UBound($aItems, 2) - 1
                DllStructSetData($tItem, "SubItem", $iJ)
                DllStructSetData($tBuffer, "Text", $aItems[$iI][$iJ])
                _SendMessage($hWnd, $LVM_SETITEMW, 0, $pItem, 0, "wparam", "ptr")
        Next
Next



;



;由于用于大量数据,
;For $iJ = 1 To UBound($aItems, 2) - 1
;这一行建议在AddArray开始时就定义为变量,假如10w条就要UBound()10w次,99999次是无用功啊
;在大量数据时_SendMessage要比GUICtrlSendMsg执行效率差,差很多很多~~~~
发表于 2012-8-24 19:11:44 | 显示全部楼层
原理是RegisterSortCallBack函数注册了

DllCallbackRegister("__GUICtrlListView_Sort", "int", "int;int;hwnd") ; Handle of callback

GUICtrlListView_Sort是排序的主体,再看看他工作原理,是要

DllStructSetData($tInfo, "Param", $nItem1)

当你添加的item Mask成员没有Param,排序就不成功了

用AddItem,AddsubItem添加的item排序成功就是因为这个Param

详细查看一下$tagLVITEM数据结构,帮助里有
 楼主| 发表于 2012-8-24 20:33:34 | 显示全部楼层
回复 7# athland5013

感謝您 熱心的解說....這樣我就更多點了解它的運作原理..... 可是 我剛剛測試了一下.....

從觀念上說 你說的很仔細 我也看懂了...但是 實際上我 改成您的方式的話  一樣是無法使用 _SortItems 來排序...

而且 照您所說的 改成...

        If IsHWnd($hWnd) Then
                If _WinAPI_InProcess($hWnd, $_lv_ghLastWnd) Then
                        For $iI = 0 To UBound($aItems) - 1
                                DllStructSetData($tItem, "Mask", BitOR($LVIF_TEXT, $LVIF_PARAM))
                                DllStructSetData($tItem, "Param",  $iLastItem + $iI)
                                
                                DllStructSetData($tItem, "Item", $iI)
                                DllStructSetData($tItem, "SubItem", 0)
                                DllStructSetData($tBuffer, "Text", $aItems[$iI][0])
                                _SendMessage($hWnd, $LVM_INSERTITEMW, 0, $pItem, 0, "wparam", "ptr")
                                
                                DllStructSetData($tItem, "Mask", $LVIF_TEXT)
                                For $iJ = 1 To UBound($aItems, 2) - 1
                                        DllStructSetData($tItem, "SubItem", $iJ)
                                        DllStructSetData($tBuffer, "Text", $aItems[$iI][$iJ])
                                        _SendMessage($hWnd, $LVM_SETITEMW, 0, $pItem, 0, "wparam", "ptr")
                                Next
                        Next


後反而  所有的 陣列內容都無法出現  全部出現空白.......不知道哪裡出了問題
发表于 2012-8-24 21:00:25 | 显示全部楼层
if IsHWnd($hWnd) then

Else
  ???????????/// 这部分你改了吗,你确定你传递的参数$hListView是句柄还是id
EndIf
发表于 2012-8-24 21:00:41 | 显示全部楼层
if IsHWnd($hWnd) then

Else
  ???????????/// 这部分你改了吗,你确定你传递的参数$hListView是句柄还是id
EndIf
 楼主| 发表于 2012-8-24 21:07:24 | 显示全部楼层
回复 11# athland5013

哈哈 OK 了!!..... 完全了解了 感謝幫忙

多謝您的耐心指導....
发表于 2012-8-24 21:11:53 | 显示全部楼层
赶快把你一楼的代码改成你能用的了,这样有你这样同样需求的,一搜,就可以得到答案!
 楼主| 发表于 2012-8-24 21:14:25 | 显示全部楼层
回复 11# athland5013

哈哈 OK 了!!..... 完全了解了 感謝幫忙

多謝您的耐心指導....

如果要求极致的话,可以修改_GUICtrlListView_AddArray函数,减少不必要的判断


這句話應該是指
;由于用于大量数据,
;For $iJ = 1 To UBound($aItems, 2) - 1
;这一行建议在AddArray开始时就定义为变量,假如10w条就要UBound()10w次,99999次是无用功啊
;在大量数据时_SendMessage要比GUICtrlSendMsg执行效率差,差很多很多~~~~
這個部份 我會在自己研究的  感謝幫忙
 楼主| 发表于 2012-8-24 21:15:15 | 显示全部楼层
回复 13# happytc

收到....  我會把自己的心得 公佈出來的 感謝!!
您需要登录后才可以回帖 登录 | 加入

本版积分规则

QQ|手机版|小黑屋|AUTOIT CN ( 鲁ICP备19019924号-1 )谷歌 百度

GMT+8, 2024-9-29 23:24 , Processed in 0.116136 second(s), 23 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表