[已解决]使用_AddArray 做成的 ListView 如何用 _SortItems来排序??
本帖最后由 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")
Else
$tBuffer = DllStructCreate("char Text")
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])
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])
_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])
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 兄弟,都说了原版自带的<GuiListView.au3>里面 AddArray不能用SortItems排序的,需要修改一下的
你试试用AddItem,AddsubItem函数就可以排序,~~~~~~~~~~原因是:
你打开<GuiListView.au3>仔细看一下AddItem,AddsubItem,AddArray,SortItems,_RegisterSortCallBack,__GUICtrlListView_Sort里面的工作原理,你了解了就会明白 AddArray添加的item为什么在SortItems时不工作了
关键词:Param
另外在ListView排序是很慢的,如果上千上万条你会砸机的,还不如在sql里面干脆~~~~ 我也想知道,等高人 本帖最后由 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 排序 在某些情況下 還是會用到 所以想研究出來 看看如何改的 本帖最后由 athland5013 于 2012-8-24 12:22 编辑
把你修改的_GUICtrlListView_AddArray贴来看看,我跟你再探讨一下,授鱼不如授渔嘛
还有论坛某位大师说过,了解UDF的工作原理对你的提高有莫大的帮助 回复 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")
Else
$tBuffer = DllStructCreate("char Text")
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])
_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])
_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])
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 本帖最后由 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])
_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])
_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执行效率差,差很多很多~~~~ 原理是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数据结构,帮助里有 回复 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])
_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
後反而所有的 陣列內容都無法出現全部出現空白.......不知道哪裡出了問題 if IsHWnd($hWnd) then
Else
???????????/// 这部分你改了吗,你确定你传递的参数$hListView是句柄还是id
EndIf if IsHWnd($hWnd) then
Else
???????????/// 这部分你改了吗,你确定你传递的参数$hListView是句柄还是id
EndIf 回复 11# athland5013
哈哈 OK 了!!..... 完全了解了 感謝幫忙
多謝您的耐心指導.... 赶快把你一楼的代码改成你能用的了,这样有你这样同样需求的,一搜,就可以得到答案! 回复 11# athland5013
哈哈 OK 了!!..... 完全了解了 感謝幫忙
多謝您的耐心指導....
如果要求极致的话,可以修改_GUICtrlListView_AddArray函数,减少不必要的判断
這句話應該是指;由于用于大量数据,
;For $iJ = 1 To UBound($aItems, 2) - 1
;这一行建议在AddArray开始时就定义为变量,假如10w条就要UBound()10w次,99999次是无用功啊
;在大量数据时_SendMessage要比GUICtrlSendMsg执行效率差,差很多很多~~~~這個部份 我會在自己研究的感謝幫忙 回复 13# happytc
收到....我會把自己的心得 公佈出來的 感謝!!
页:
[1]
2