基 础 函 数 参 考


GUICtrlRegisterListViewSort

注册 ListView 控件内部排序的自定义回调函数.

GUICtrlRegisterListViewSort ( 控件ID, "函数" )

参 数

控件ID Listview 控件ID.
函数 排序回调函数的名称.

返 回 值

成功: 1
失败: 0

备 注

!!! 要使用户定义函数能正常工作, 必须定义它最多 4 个参数, 否则函数将不能被调用 !!!
例如:
Func MySortFunction($nListViewID, $LParam1, $LParam2, $nColumn)
...
EndFunc



Func MySortFunction($nListViewID, $LParam1, $LParam2)
...
EndFunc

当用户函数被调用时, 这 4 个参数具有下列值:


位置 Parameter 参数
1 controlID 回调函数使用的 listview 控件 ID.
2 lParam1 第一个项目的 lParam 值.(默认为该项目的控件 ID).
3 lParam2 第二个项目的 lParam 值.(默认为该项目的控件 ID).
4 column 点击排序的列.(第一列为 0).

下列值是改变排序状态后的返回值:


返回值 意义
-1 第一个项目在第二个前面.
0 无变化.
1 第一个项目在第二个后面.

排序 GUI 自身创建的项目参见排序示例.

相 关 函 数

GUICtrlCreateListView

函 数 示 例


#include <GUIConstantsEx.au3>
#include <ListViewConstants.au3>

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

Example1()
Example2()

; *******************************************************
; 示例  1 - 排序 3 列的数据
; *******************************************************
Func Example1()
    Local $lv, $msg

    GUICreate("测试", 300, 200)

    $lv = GUICtrlCreateListView("列1|列2|列3", 10, 10, 280, 180)
    GUICtrlRegisterListViewSort(-1, "LVSort") ; 注册排序回调函数 "SortLV"

    GUICtrlCreateListViewItem ("ABC|666|10.05.2004", $lv)
    GUICtrlSetImage(-1, "shell32.dll", 7)
    GUICtrlCreateListViewItem ("DEF|444|11.05.2005", $lv)
    GUICtrlSetImage(-1, "shell32.dll", 12)
    GUICtrlCreateListViewItem ("CDE|444|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

    GUIDelete()
EndFunc   ;==>Example1

; 自定义排序回调函数
Func LVSort($hWnd, $nItem1, $nItem2, $nColumn)
    Local $val1, $val2, $nResult

    ; 切换排序方向
    If $nColumn = $nCurCol Then
        If Not $bSet Then
            $nSortDir = $nSortDir * - 1
            $bSet = 1
        EndIf
    Else
        $nSortDir = 1
    EndIf
    $nCol = $nColumn

    $val1 = GetSubItemText($hWnd, $nItem1, $nColumn)
    $val2 = GetSubItemText($hWnd, $nItem2, $nColumn)

    ; 如果排序第 3 列 (列从0开始计算), 则比较日期
    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 ; 项目 1 和项目 2 的位置没有改变

    If $val1 < $val2 Then
        $nResult = -1 ; 将第 2 项放到第 1 项之前
    ElseIf $val1 > $val2 Then
        $nResult = 1 ; 将第 2 项放到第 1 项后面
    EndIf

    $nResult = $nResult * $nSortDir

    Return $nResult
EndFunc   ;==>LVSort


; 检索 ListView 指定列的项目文本
Func GetSubItemText($nCtrlID, $nItemID, $nColumn)
    Local $stLvfi = DllStructCreate("uint;ptr;int;int[2];int")
    Local $nIndex, $stBuffer, $stLvi, $sItemText

    DllStructSetData($stLvfi, 1, $LVFI_PARAM)
    DllStructSetData($stLvfi, 3, $nItemID)

    $stBuffer = DllStructCreate("char[260]")

    $nIndex = GUICtrlSendMsg($nCtrlID, $LVM_FINDITEM , -1, DllStructGetPtr($stLvfi));

    $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_GETITEMA, 0, DllStructGetPtr($stLvi));

    $sItemText = DllStructGetData($stBuffer, 1)

    $stLvi = 0
    $stLvfi = 0
    $stBuffer = 0

    Return $sItemText
EndFunc   ;==>GetSubItemText


; *******************************************************
; 示例  2 - 有 DllCall 创建项目排序
; *******************************************************
Func Example2()
    Local $hGUI, $lv, $msg

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

    $hGUI = GUICreate("测试", 300, 200)

    $lv = GUICtrlCreateListView("列1|列2|列3", 10, 10, 280, 180)
    GUICtrlRegisterListViewSort(-1, "LVSort2") ; 注册排序回调函数 "SortLV"

    MyGUICtrlCreateListViewItem ("ABC|666|10.05.2004", $lv, -1)
    MyGUICtrlCreateListViewItem ("DEF|444|11.05.2005", $lv, -1)
    MyGUICtrlCreateListViewItem ("CDE|444|12.05.2004", $lv, -1)

    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", ControlGetHandle($hGUI, "", $lv), "int", 0, "int", 1)
        EndSwitch
    WEnd
EndFunc   ;==>Example2

; 自定义排序回调函数
Func LVSort2($hWnd, $nItem1, $nItem2, $nColumn)
    Local $val1, $val2, $nResult

    ; 切换排序方向
    If $nColumn = $nCurCol Then
        If Not $bSet Then
            $nSortDir = $nSortDir * - 1
            $bSet = 1
        EndIf
    Else
        $nSortDir = 1
    EndIf
    $nCol = $nColumn

    $val1 = GetSubItemText($hWnd, $nItem1, $nColumn)
    $val2 = GetSubItemText($hWnd, $nItem2, $nColumn)

    ; 如果排序第 3 列 (列从0开始计算), 则比较日期
    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 ; 项目 1 和项目 2 的位置没有改变

    If $val1 < $val2 Then
        $nResult = -1 ; 将第 2 项放到第 1 项之前
    ElseIf $val1 > $val2 Then
        $nResult = 1 ; 将第 2 项放到第 1 项后面
    EndIf

    $nResult = $nResult * $nSortDir

    Return $nResult
EndFunc   ;==>LVSort2


; 检索 ListView 指定列的项目文本
Func GetSubItemText2($nCtrlID, $nItemID, $nColumn)
    Local $stLvfi = DllStructCreate("uint;ptr;int;int[2];int")
    Local $stBuffer, $nIndex, $stLvi, $sItemText

    DllStructSetData($stLvfi, 1, $LVFI_PARAM) ; 查找保存了索引的项目
    DllStructSetData($stLvfi, 3, $nItemID)

    $stBuffer = DllStructCreate("char[260]")

    $nIndex = GUICtrlSendMsg($nCtrlID, $LVM_FINDITEM , -1, DllStructGetPtr($stLvfi));

    $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_GETITEMA, 0, DllStructGetPtr($stLvi));

    $sItemText = DllStructGetData($stBuffer, 1)

    $stLvi = 0
    $stLvfi = 0
    $stBuffer = 0

    Return $sItemText
EndFunc   ;==>GetSubItemText2


; 直接创建和插入 ListView 项目
Func MyGUICtrlCreateListViewItem ($sText, $nCtrlID, $nIndex)
    Local $stLvItem  = DllStructCreate("uint;int;int;uint;uint;ptr;int;int;int;int;")
    Local $stText = DllStructCreate("char[260]")
    Local $arText = StringSplit($sText, "|")

    If $nIndex = -1 Then $nIndex = GUICtrlSendMsg($nCtrlID, $LVM_GETITEMCOUNT, 0, 0)

    DllStructSetData($stText, 1, $arText[1]) ; 项目的文字保存在结构中

    DllStructSetData($stLvItem , 1, BitOR($LVIF_TEXT, $LVIF_PARAM))
    DllStructSetData($stLvItem , 2, $nIndex)
    DllStructSetData($stLvItem , 6, DllStructGetPtr($stText))
    ; 设置结构的 lParam 为行索引 - 在 ListView 内是唯一的
    DllStructSetData($stLvItem , 9, $nIndex)

    $nIndex = GUICtrlSendMsg($nCtrlID, $LVM_INSERTITEMA, 0, DllStructGetPtr($stLvItem ))

    If $nIndex > -1 Then
        ; 现在插入列文本的其余部分
        For $i = 2 To $arText[0]
            DllStructSetData($stText, 1, $arText[$i])
            DllStructSetData($stLvItem , 3, $i - 1) ; 存储子项的索引

            GUICtrlSendMsg($nCtrlID, $LVM_SETITEMTEXTA, $nIndex, DllStructGetPtr($stLvItem ))
        Next
    EndIf

    $stText = 0
    $stLvItem  = 0

    ; 更改列的宽度, 以适应项目的文字
    For $i = 0 To 2
        GUICtrlSendMsg($nCtrlID, $LVM_SETCOLUMNWIDTH, $i, -1)
        GUICtrlSendMsg($nCtrlID, $LVM_SETCOLUMNWIDTH, $i, -2)
    Next
EndFunc   ;==>MyGUICtrlCreateListViewItem

provider with jb51.net (unicode)