找回密码
 加入
搜索
查看: 2407|回复: 8

GUICtrlRegisterListViewSort排序问题:如何使某一列按数字的大小排列?

  [复制链接]
发表于 2009-11-23 18:54:52 | 显示全部楼层 |阅读模式
本帖最后由 hlzxcjx 于 2009-11-24 12:31 编辑
#include <GUIConstants.au3>

;Global Const $LVFI_PARAM           = 0x0001
;Global Const $LVIF_TEXT                = 0x0001
;Global Const $LVM_FIRST                = 0x1000
Global Const $LVM_GETITEM           = $LVM_FIRST + 5
;Global Const $LVM_FINDITEM         = $LVM_FIRST + 13
;Global Const $LVM_SETSELECTEDCOLUMN    = $LVM_FIRST + 140

Dim $nCurCol    = -1
Dim $nSortDir   = 1
Dim $bSet       = 0
Dim $nCol       = -1

$hGUI   = GUICreate("Test", 300, 200)

$lv     = GUICtrlCreateListView("Column1|Col2|Col3", 10, 10, 280, 180)
GUICtrlRegisterListViewSort(-1, "LVSort") ; Register the function "SortLV" for the sorting callback

$lvi1   = GUICtrlCreateListViewItem("ABC|666|10.05.2004", $lv)
GUICtrlSetImage(-1, "shell32.dll", 7)
$lvi2   = GUICtrlCreateListViewItem("DEF|5|11.05.2005", $lv)
GUICtrlSetImage(-1, "shell32.dll", 12)
$lvi3   = GUICtrlCreateListViewItem("CDE|31|12.05.2004", $lv)
GUICtrlSetImage(-1, "shell32.dll", 3)

GUISetState()

While 1
    $msg = GUIGetMsg()
    Switch $msg
        Case $GUI_EVENT_CLOSE
            ExitLoop
            
        Case $lv
            $bSet = 0
            $nCurCol = $nCol
            GUICtrlSendMsg($lv, $LVM_SETSELECTEDCOLUMN, GUICtrlGetState($lv), 0)
            DllCall("user32.dll", "int", "InvalidateRect", "hwnd", GUICtrlGetHandle($lv), "int", 0, "int", 1)
    EndSwitch
WEnd

Exit


; Our sorting callback funtion
Func LVSort($hWnd, $nItem1, $nItem2, $nColumn)
    Local $nSort
    
    ; Switch the sorting direction
    If $nColumn = $nCurCol Then
        If Not $bSet Then
            $nSortDir = $nSortDir * -1
            $bSet = 1
        EndIf
    Else
        $nSortDir = 1
    EndIf
    $nCol = $nColumn
        
    $val1   = GetSubItemText($lv, $nItem1, $nColumn)
    $val2   = GetSubItemText($lv, $nItem2, $nColumn)
    
    ; If it is the 3rd colum (column starts with 0) then compare the dates
    If $nColumn = 2 Then
        $val1 = StringRight($val1, 4) & StringMid($val1, 4, 2) & StringLeft($val1, 2)
        $val2 = StringRight($val2, 4) & StringMid($val2, 4, 2) & StringLeft($val2, 2)
    EndIf
        
    $nResult = 0        ; No change of item1 and item2 positions
    
    If $val1 < $val2 Then
        $nResult = -1   ; Put item2 before item1
    ElseIf  $val1 > $val2 Then
        $nResult = 1    ; Put item2 behind item1
    EndIf

    $nResult = $nResult * $nSortDir
    
    Return $nResult
EndFunc


; Retrieve the text of a listview item in a specified column
Func GetSubItemText($nCtrlID, $nItemID, $nColumn)
    Local $stLvfi       = DllStructCreate("uint;ptr;int;int[2];int")
    DllStructSetData($stLvfi, 1, $LVFI_PARAM)
    DllStructSetData($stLvfi, 3, $nItemID)

    Local $stBuffer     = DllStructCreate("char[260]")
    
    $nIndex = GUICtrlSendMsg($nCtrlID, $LVM_FINDITEM, -1, DllStructGetPtr($stLvfi));
    
    Local $stLvi        = DllStructCreate("uint;int;int;uint;uint;ptr;int;int;int;int")
    
    DllStructSetData($stLvi, 1, $LVIF_TEXT)
    DllStructSetData($stLvi, 2, $nIndex)
    DllStructSetData($stLvi, 3, $nColumn)
    DllStructSetData($stLvi, 6, DllStructGetPtr($stBuffer))
    DllStructSetData($stLvi, 7, 260)

    GUICtrlSendMsg($nCtrlID, $LVM_GETITEM, 0, DllStructGetPtr($stLvi));

    $sItemText  = DllStructGetData($stBuffer, 1)

    $stLvi      = 0
    $stLvfi     = 0
    $stBuffer   = 0
    
    Return $sItemText
EndFunc
如图:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?加入

×

评分

参与人数 1金钱 +2 收起 理由
pusofalse + 2 感谢主动修改帖子分类为[已解决]。

查看全部评分

发表于 2009-11-23 20:20:59 | 显示全部楼层
LVSort 函数内部是以字符串的形式比对的,并非数字,比对数字需用 Number 转换下 $val1 和 $val2 的值~
发表于 2009-11-23 22:06:05 | 显示全部楼层
LVSort 函数内部是以字符串的形式比对的,并非数字,比对数字需用 Number 转换下 $val1 和 $val2 的值~
afan 发表于 2009-11-23 20:20



    的确是这样
If Number($val1) < Number($val2) Then
        $nResult = -1   ; Put item2 before item1
    ElseIf  Number($val1) > Number($val2) Then
        $nResult = 1    ; Put item2 behind item1
    EndIf
发表于 2009-11-23 22:31:18 | 显示全部楼层
的确是这样
bing614 发表于 2009-11-23 22:06



    是的,bing614 前辈这样改就可以达到LZ的要求了~ 不过第1列(字母)将无法排序了,呵呵~

我改的是这样,能兼顾字符串排序:
        $val_1 = Number($val1)
        If $val_1 = 0 Then $val_1 = $val1
        $val_2 = Number($val2)
        If $val_2 = 0 Then $val_2 = $val2
        If $val_1 < $val_2 Then
                $nResult = -1 ; Put item2 before item1
        ElseIf $val_1 > $val_2 Then
                $nResult = 1 ; Put item2 behind item1
        EndIf
完整代码如下:
#include <GUIConstants.au3>
#include <ListViewConstants.au3>
;Global Const $LVFI_PARAM           = 0x0001
;Global Const $LVIF_TEXT                = 0x0001
;Global Const $LVM_FIRST                = 0x1000
Global Const $LVM_GETITEM = $LVM_FIRST + 5
;Global Const $LVM_FINDITEM         = $LVM_FIRST + 13
;Global Const $LVM_SETSELECTEDCOLUMN    = $LVM_FIRST + 140

Dim $nCurCol = -1
Dim $nSortDir = 1
Dim $bSet = 0
Dim $nCol = -1

$hGUI = GUICreate("Test", 300, 200)
$lv = GUICtrlCreateListView("Column1|Col2|Col3", 10, 10, 280, 180)
GUICtrlRegisterListViewSort(-1, "LVSort") ; Register the function "SortLV" for the sorting callback
$lvi1 = GUICtrlCreateListViewItem("ABC|666|10.05.2004", $lv)
GUICtrlSetImage(-1, "shell32.dll", 7)
$lvi2 = GUICtrlCreateListViewItem("DEF|5|11.05.2005", $lv)
GUICtrlSetImage(-1, "shell32.dll", 12)
$lvi3 = GUICtrlCreateListViewItem("XYZ|31|12.05.2004", $lv)
GUICtrlSetImage(-1, "shell32.dll", 3)
GUISetState()

While 1
        $msg = GUIGetMsg()
        Switch $msg
                Case $GUI_EVENT_CLOSE
                        ExitLoop

                Case $lv
                        $bSet = 0
                        $nCurCol = $nCol
                        GUICtrlSendMsg($lv, $LVM_SETSELECTEDCOLUMN, GUICtrlGetState($lv), 0)
                        DllCall("user32.dll", "int", "InvalidateRect", "hwnd", GUICtrlGetHandle($lv), "int", 0, "int", 1)
        EndSwitch
WEnd
Exit

; Our sorting callback funtion
Func LVSort($hWnd, $nItem1, $nItem2, $nColumn)
        Local $nSort
        ; Switch the sorting direction
        If $nColumn = $nCurCol Then
                If Not $bSet Then
                        $nSortDir = $nSortDir * - 1
                        $bSet = 1
                EndIf
        Else
                $nSortDir = 1
        EndIf
        $nCol = $nColumn
        $val1 = GetSubItemText($lv, $nItem1, $nColumn)
        $val2 = GetSubItemText($lv, $nItem2, $nColumn)
        ; If it is the 3rd colum (column starts with 0) then compare the dates
        If $nColumn = 2 Then
                $val1 = StringRight($val1, 4) & StringMid($val1, 4, 2) & StringLeft($val1, 2)
                $val2 = StringRight($val2, 4) & StringMid($val2, 4, 2) & StringLeft($val2, 2)
        EndIf
        $nResult = 0 ; No change of item1 and item2 positions
        $val_1 = Number($val1)
        If $val_1 = 0 Then $val_1 = $val1
        $val_2 = Number($val2)
        If $val_2 = 0 Then $val_2 = $val2
        If $val_1 < $val_2 Then
                $nResult = -1 ; Put item2 before item1
        ElseIf $val_1 > $val_2 Then
                $nResult = 1 ; Put item2 behind item1
        EndIf
        $nResult = $nResult * $nSortDir
        Return $nResult
EndFunc   ;==>LVSort

; Retrieve the text of a listview item in a specified column
Func GetSubItemText($nCtrlID, $nItemID, $nColumn)
        Local $stLvfi = DllStructCreate("uint;ptr;int;int[2];int")
        DllStructSetData($stLvfi, 1, $LVFI_PARAM)
        DllStructSetData($stLvfi, 3, $nItemID)
        Local $stBuffer = DllStructCreate("char[260]")
        $nIndex = GUICtrlSendMsg($nCtrlID, $LVM_FINDITEM, -1, DllStructGetPtr($stLvfi));
        Local $stLvi = DllStructCreate("uint;int;int;uint;uint;ptr;int;int;int;int")
        DllStructSetData($stLvi, 1, $LVIF_TEXT)
        DllStructSetData($stLvi, 2, $nIndex)
        DllStructSetData($stLvi, 3, $nColumn)
        DllStructSetData($stLvi, 6, DllStructGetPtr($stBuffer))
        DllStructSetData($stLvi, 7, 260)
        GUICtrlSendMsg($nCtrlID, $LVM_GETITEM, 0, DllStructGetPtr($stLvi));
        $sItemText = DllStructGetData($stBuffer, 1)
        $stLvi = 0
        $stLvfi = 0
        $stBuffer = 0
        Return $sItemText
EndFunc   ;==>GetSubItemText
发表于 2009-11-23 23:38:06 | 显示全部楼层
学习了,收下
 楼主| 发表于 2009-11-24 09:39:57 | 显示全部楼层
用 Number 转换对于IP地址类还不能解决:
$lvi1 = GUICtrlCreateListViewItem("ABC|666|10.05.01.132", $lv)
GUICtrlSetImage(-1, "shell32.dll", 7)
$lvi2 = GUICtrlCreateListViewItem("DEF|5|10.05.01.163", $lv)
GUICtrlSetImage(-1, "shell32.dll", 12)
$lvi3 = GUICtrlCreateListViewItem("XYZ|31|10.05.01.79", $lv)
GUICtrlSetImage(-1, "shell32.dll", 3)
发表于 2009-11-24 11:34:44 | 显示全部楼层
回复 6# hlzxcjx


    修改的思路和例子都给你了,不会自己琢磨?
 楼主| 发表于 2009-11-24 12:30:39 | 显示全部楼层
自己解决了!
发表于 2011-8-28 16:30:22 | 显示全部楼层
好啊. 学习了.
您需要登录后才可以回帖 登录 | 加入

本版积分规则

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

GMT+8, 2024-10-1 17:21 , Processed in 0.088122 second(s), 25 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

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