Jump to content

Partial sorting for Listview


Go to solution Solved by Melba23,

Recommended Posts

Hi everybody,

I am new in this forum. Just would like to ask solution of my problem.

Let say if I have made a GUI with Listview in it and I have a button to click which will sort the items of listview.

Description of listview :

It contains 4 columns.(name, gender, type, score)

Let say the items are:

Abc Male Adult 85

Asd Male Teenage 97

Cde Female Teenage 80

DEF Male Adult 90

Ghi Female Kid 50

Jkl Male Kid 70

Mno Female Teenage 60

Sorting will base on this:

First, it will sort by gender (male first, followed by female)

Next, it will sort by type (adult first, followed by teenage and last is kid)

Next, it will sort by score.

End result will be like this :

DEF Male Adult 90

Abc Male Adult 85

Asd Male Teenage 97

Jkl Male Kid 70

Cde Female Teenage 80

Mno Female Teenage 60

Ghi Female Kid 50

I've Been trying to solve it using array, but still no result of my many hours trying.

Any solution guys?

Btw, hope u all could understand what I tried to achieve.

Link to comment
Share on other sites

Sort it in sections.  Sort all of the items by gender.  Then by type.  Finally sort those by their scores. 

The males are put into their own array. Then put all of the adult males into their own array.  Same for kids, etc.  Then sort those by their scores.  Do the same for females.  At the end, combine all of the arrays into one.

Link to comment
Share on other sites

Thank you jaberwocky6669 for the fast reply.

Sorry that I can not really understand your explanation. And also I forgot to mention something that user can input their data.

Following is sample of the script :

#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#include <EditConstants.au3>

Global $msg, $mainGUI ,$hListView
Global $edit1,$edit2,$edit3,$edit4
Global $addButton,$mainButton,$column1,$column2,$column3,$column4

Opt('MustDeclareVars', 1)

Example1()


Func Example1()


Global $msg, $mainGUI ,$hListView

Global $edit1,$edit2,$edit3,$edit4
Global $addButton,$mainButton,$column1,$column2,$column3,$column4


$mainGUI = GUICreate("Test LV auto sort",340,400)
$addButton = GUICtrlCreateButton("ADD DATA", 100, 280, 140, 40)
$mainButton = GUICtrlCreateButton("Sort It", 100, 340, 140, 40)

$hListView = GUICtrlCreateListView("Name|Gender|Type|Score", 10, 12, 318, 230,BitOR($LVS_EDITLABELS,$LVS_SINGLESEL),BitOR($LVS_EX_FULLROWSELECT,$LVS_EX_GRIDLINES))

_GUICtrlListView_SetExtendedListViewStyle($hListView, BitOR($LVS_EX_GRIDLINES, $LVS_EX_FULLROWSELECT))

$edit1 = GUICtrlCreateEdit("",12,250,100,20, $ES_RIGHT)
$edit2 = GUICtrlCreateEdit("",114,250,80,20, $ES_RIGHT)
$edit3 = GUICtrlCreateEdit("",196,250,80,20, $ES_RIGHT)
$edit4 = GUICtrlCreateEdit("",278,250,48,20, $ES_RIGHT)

$column1 = _GUICtrlListView_SetColumn($hListView ,0,"Name",100,2)
$column2 = _GUICtrlListView_SetColumn($hListView ,1,"Gender",80,2)
$column3 = _GUICtrlListView_SetColumn($hListView ,2,"Type",80,2)
$column4 = _GUICtrlListView_SetColumn($hListView ,3,"Score",50,2)

GUICtrlCreateListViewItem("ABC|Male|Adult|85", $hListView)
GUICtrlCreateListViewItem("ASD|Male|Teenage|97", $hListView)
GUICtrlCreateListViewItem("CDE|Female|Teenage|80", $hListView)
GUICtrlCreateListViewItem("DEF|Male|Adult|90", $hListView)
GUICtrlCreateListViewItem("GHI|Female|Kid|50", $hListView)
GUICtrlCreateListViewItem("JKL|Male|Kid|70", $hListView)
GUICtrlCreateListViewItem("MNO|Female|Teenage|60", $hListView)

GUISetState()

While 1
$msg = GUIGetMsg()
Select
Case $msg = $GUI_EVENT_CLOSE
ExitLoop
Case $msg = $addButton
Call("adddata")
Case $msg = $mainButton
Call("sort")
EndSelect
WEnd
GUIDelete()
EndFunc

Func adddata()
GUICtrlCreateListViewItem(GUICtrlRead($edit1) &"|" &GUICtrlRead($edit2) &"|" &GUICtrlRead($edit3) &"|" &GUICtrlRead($edit4), $hListView)
EndFunc

Func sort()
;Still confusion in here
EndFunc
Now, a problem will occurs if some users entered another type of data:

Example :

User 1 entered :

JFK | Unknown | Adult | 85

Hhh | Unknown |Teenage | 86

User 2 entered :

Ggg | Male | No data | 90

Jjjj | male | No data | 50

Lkm | Female | No data | 60

User 3 entered :

Asz | NIL | kid | 70

Jjjj | NIL | Adult | 50

Fjjj | NIL | Adult | 60

User 4 entered :

Lkm | Male | No history | 40

Ers |Male |No history | 89

Users ARE ALLOWED to enter any type of data, except the score is number.

So that the final result is like this:

Ggg | Male | No data | 90

Jjjj | male | No data | 50

Lkm | Male | No history | 89

Ers | Male | No history | 40

Lkm | Female | No data | 60

Fjjj | NIL | Adult | 60

Jjjj | NIL | Adult | 50

Asz | NIL | kid | 70

JFK | Unknown | Adult | 85

Hhh | Unknown |Teenage | 86

Which means, I could not prepare an array for the gender nor type as I don't know what an user might inputed (NIL / no history / unknown / N/A / etc...) or I COULD ?

If only has someting like this :

_GUICtrlListView_SimpleSort($hListView, $B_DESCENDING, #column index, #starting subitem index, #end subitem index)

Many thanks in advance ;)

Edited by Melba23
Link to comment
Share on other sites

  • Moderators

cloudofxyz,

When you post code please use Code tags - see here how to do it. Then you get a scrolling box and syntax colouring as you can see above now I have added the tags. ;)

Next, rather than let your users enter anything at all, why not limit their choices for certain elements by using a combo? Than you will have a defined set of values that you will find in the "Gender" and "Age group" elements which will greatly simplify matters. :)

As to sorting - I would pull all the data from the ListView into an array. You can then do the sorting in the array (_ArraySort allows you to sort on subitems and in a specific range) or split the array as required, sort each section and then recreate the main array for reloading into the ListView. I will see if I can come up with something later today to show the principle. ;)

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

Thanks melba23 for the tips of using of code tags. And help me to code tagged it for me ;)

A limitation would be great, but I prefer users able to enter data when they not sure yet what the complete data is, but they've known partial of data. Eg. Not sure either male or female, but for sure it is an adult with 80 points.

After reading carefully the suggestion from jaberwocky6669 and your explanation, Now I understand what is solution using those arrays. Thanks for both of you. Btw, may I know which command can be used for reloading that main (2D) array back to Listview? ( sorry , seldom using array :( )

Link to comment
Share on other sites

  • Moderators

cloudofxyz,

You can have an "Unknown" in a combo - I will look at the data insertion aspect later. ;)

Here is some code to sort the data as you wish - the _ArrayDisplay dialogs show how it is progressing as is runs:

#include <Array.au3>

Global $aData[][] = [ _
    ["Ggg", "Male", "Teenage", 90], _
    ["Jjjj", "Male", "Unknown", 50], _
    ["Lkm", "Male", "Adult", 89], _
    ["Ers", "Male", "Unknown", 55], _
    ["Lkm", "Female", "Unknown", 60], _
    ["Fjjj", "Unknown", "Kid", 60], _
    ["Jppp", "Unknown", "Adult", 50], _
    ["Asz", "Female", "Kid", 70], _
    ["JFK", "Unknown", "Adult", 85], _
    ["Hhh", "Female", "Teenage", 86]]

$iTopIndex = UBound($aData) - 1


; First change the element titles to get the correct sort order
For $i = 0 To UBound($aData) - 1
    ; Gender
    If $aData[$i][1] = "Male" Then
        $aData[$i][1] = "1-Male"
    ElseIf $aData[$i][1] = "Female" Then
        $aData[$i][1] = "2-Female"
    Else
        $aData[$i][1] = "3-Unknown"
    EndIf
    ; Age
    If $aData[$i][2] = "Adult" Then
        $aData[$i][2] = "1-Adult"
    ElseIf $aData[$i][2] = "Teenage" Then
        $aData[$i][2] = "2-Teenage"
    ElseIf $aData[$i][2] = "Kid" Then
        $aData[$i][2] = "3-Kid"
    Else
        $aData[$i][2] = "4-Unknown"
    EndIf
Next

; First sort on gender
_ArraySort($aData, 0, 0, 0, 1)

_ArrayDisplay($aData, "Gender") ; Just for display

; Now look for 3 gender options and sort the 3 sections on age
$iFemale_Start = _ArrayScan(0, $iTopIndex, "1-Male")
If $iFemale_Start > 1 Then ; Sorting 0 to 0 means the whole array which we do not want
    _ArraySort($aData, 0, 0, $iFemale_Start - 1, 2)
EndIf
$iUnknown_Start = _ArrayScan($iFemale_Start, $iTopIndex, "2-Female")
If $iUnknown_Start > 1 Then
    _ArraySort($aData, 0, $iFemale_Start, $iUnknown_Start - 1, 2)
EndIf
_ArraySort($aData, 0, $iUnknown_Start, 0, 2)

_ArrayDisplay($aData, "Age") ; Just for display

; Now we sort on the scores
$iMale_Teen_Start = _ArrayScan(0, $iTopIndex, "1-Male", "1-Adult")
If $iMale_Teen_Start > 1 Then
    _ArraySort($aData, 1, 0, $iMale_Teen_Start - 1, 3)
EndIf
$iMale_Kid_Start = _ArrayScan($iMale_Teen_Start, $iTopIndex, "1-Male", "2-Teenage")
If $iMale_Kid_Start > 1 Then
    _ArraySort($aData, 1, $iMale_Teen_Start, $iMale_Kid_Start - 1, 3)
EndIf
$iMale_Unknown_Start = _ArrayScan($iMale_Kid_Start, $iTopIndex, "1-Male", "3-Kid")
If $iMale_Unknown_Start > 1 Then
    _ArraySort($aData, 1, $iMale_Kid_Start, $iMale_Unknown_Start - 1, 3)
EndIf
$iFemale_Adult_Start = _ArrayScan($iMale_Unknown_Start, $iTopIndex, "1-Male", "4-Unknown")
If $iFemale_Adult_Start > 1 Then
    _ArraySort($aData, 1, $iMale_Unknown_Start, $iFemale_Adult_Start - 1, 3)
EndIf

_ArrayDisplay($aData, "Males fully sorted") ; Just for display

$iFemale_Teen_Start = _ArrayScan($iFemale_Adult_Start, $iTopIndex, "2-Female", "1-Adult")
If $iFemale_Teen_Start > 1 Then
    _ArraySort($aData, 1, $iFemale_Adult_Start, $iFemale_Teen_Start - 1, 3)
EndIf
$iFemale_Kid_Start = _ArrayScan($iFemale_Teen_Start, $iTopIndex, "2-Female", "2-Teenage")
If $iFemale_Kid_Start > 1 Then
    _ArraySort($aData, 1, $iFemale_Teen_Start, $iFemale_Kid_Start - 1, 3)
EndIf
$iFemale_Unknown_Start = _ArrayScan($iFemale_Kid_Start, $iTopIndex, "2-Female", "3-Kid")
If $iFemale_Unknown_Start > 1 Then
    _ArraySort($aData, 1, $iFemale_Kid_Start, $iFemale_Unknown_Start - 1, 3)
EndIf
$iUnknown_Adult_Start = _ArrayScan($iFemale_Unknown_Start, $iTopIndex, "2-Female", "4-Unknown")
If $iUnknown_Adult_Start > 1 Then
    _ArraySort($aData, 1, $iFemale_Unknown_Start, $iUnknown_Adult_Start - 1, 3)
EndIf

_ArrayDisplay($aData, "Females fully sorted") ; Just for display

$iUnknown_Teen_Start = _ArrayScan($iUnknown_Adult_Start, $iTopIndex, "3-Unknown", "1-Adult")
If $iUnknown_Teen_Start > 1 Then
    _ArraySort($aData, 1, $iUnknown_Adult_Start, $iUnknown_Teen_Start - 1, 3)
EndIf
$iUnknown_Kid_Start = _ArrayScan($iUnknown_Teen_Start, $iTopIndex, "3-Unknown", "2-Teenage")
If $iUnknown_Kid_Start > 1 Then
    _ArraySort($aData, 1, $iUnknown_Teen_Start, $iUnknown_Kid_Start - 1, 3)
EndIf
$iUnknown_Unknown_Start = _ArrayScan($iUnknown_Kid_Start, $iTopIndex, "3-Unknown", "3-Kid")
If $iUnknown_Unknown_Start > 1 Then
    _ArraySort($aData, 1, $iUnknown_Kid_Start, $iUnknown_Unknown_Start - 1, 3)
EndIf
_ArraySort($aData, 1, $iUnknown_Unknown_Start, 0, 3)

_ArrayDisplay($aData, "Unknowns fully sorted") ; Just for display

; Now reset the element titles
For $i = 0 To UBound($aData) - 1
    ; Gender
    If $aData[$i][1] = "1-Male" Then
        $aData[$i][1] = "Male"
    ElseIf $aData[$i][1] = "2-Female" Then
        $aData[$i][1] = "Female"
    Else
        $aData[$i][1] = "Unknown"
    EndIf
    ; Age
    If $aData[$i][2] = "1-Adult" Then
        $aData[$i][2] = "Adult"
    ElseIf $aData[$i][2] = "2-Teenage" Then
        $aData[$i][2] = "Teenage"
    ElseIf $aData[$i][2] = "3-Kid" Then
        $aData[$i][2] = "Kid"
    Else
        $aData[$i][2] = "Unknown"
    EndIf
Next

_ArrayDisplay($aData, "Final sorted array")

Func _ArrayScan($iStartIndex, $iEndIndex, $sGender, $sAge = "")

    If $sAge Then ConsoleWrite($sGender & " - " & $sAge & @CRLF)

    For $i = $iStartIndex To $iEndIndex
        If $sAge Then
            If Not ($aData[$i][1] = $sGender And $aData[$i][2] = $sAge) Then ExitLoop
        Else
            If $aData[$i][1] <> $sGender Then ExitLoop
        EndIf
    Next

    Return $i

EndFunc
I hope the code is clear, but please do ask if you have any questions. :)

M23

Edited by Melba23
Added function

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

  • Moderators

cloudofxyz,

Sorry, I missed the _ArrayScan function when I pasted the code - it is there now. :)

If you look at the GUILIstViewEx UDF in my sig it has several functions for getting the data from ListViews and reloading them. Feel free to modify any of that code to fit your specific case. ;)

M23

Edit:

And here is my suggestion for the user input section of your code - now you can only have the specific values used in the sort function: ;)

$edit1 = GUICtrlCreateEdit("", 12, 250, 100, 20, $ES_RIGHT)
$edit2 = GUICtrlCreateCombo("", 114, 250, 80, 20)
GUICtrlSetData($edit2, "Male|Female|Unknown", "Unknown")
$edit3 = GUICtrlCreateCombo("", 196, 250, 80, 20)
GUICtrlSetData($edit3, "Adult|Teenage|Kid|Unknown", "Unknown")
$edit4 = GUICtrlCreateEdit("", 278, 250, 48, 20, $ES_RIGHT)
Edited by Melba23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

Melba23,

The array sorting is tried and works perfectly.

I've just downloaded your UDF and read how to use it. However, think it would take me a while before I figure it out how to reload it to Listview. Anyway, I will post it once I figured it out. Thanks for your time.

Link to comment
Share on other sites

  • Moderators

cloudofxyz,

Excellent! :D

I am thinking about producing a generic sort function to do the same thing - you feed it an array and the details of the sort criteria and it returns a sorted array. I will let you know how I get on. :)

And please ask if you have any questions about the read and reload functions within the UDF. Remember that you do not need all the code - just enough to do the job. ;)

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

Melba23,

I tried to use your udf with the function of _GUIListviewEx_ReWriteLV, but since there is no example of using it (I can't find it in example 1,example 2, example 3, and example 4), I still having difficulties in implementing it. Sorry, I am quite poor in this array thing.

If you have free time, could you please give me an example of using it?

Thank you.

Link to comment
Share on other sites

  • Moderators

cloudofxyz,

I said I would look into a stand-alone function to sort arrays on several levels - and here it is:

#include <Array.au3>

Global $aArray[][] = [ _
    ["Ggg", "Male", "Teenage", 90], _
    ["Jjjj", "Male", "Unknown", 50], _
    ["Lkm", "Male", "Adult", 89], _
    ["Ers", "Male", "Unknown", 55], _
    ["Lkm", "Female", "Unknown", 60], _
    ["Fjjj", "Unknown", "Kid", 60], _
    ["Jppp", "Unknown", "Adult", 50], _
    ["Asz", "Female", "Kid", 70], _
    ["JFK", "Unknown", "Adult", 85], _
    ["Hhh", "Female", "Teenage", 86]]

; Sort requirement:
; Column then either 0/1 (Ascending/Descending) or string with required order (anything else comes after these)
Global $aSortData[3][2] = [ _
    [1, "Male,Female"], _
    [2, "Adult,Teenage,Kid"], _
    [3, 1]]

_ArrayDisplay($aArray, "Unsorted")

_ArrayMultiSort($aArray, $aSortData) ; Sort the array as required by the $aSortData parameters

_ArrayDisplay($aArray, "Sorted")

; ==================================================================================

Func _ArrayMultiSort(ByRef $aArray, $aSortData, $iStart = 0, $iEnd = 0)

    ; Set default End value
    If $iEnd = 0 Then
        $iEnd = UBound($aArray) - 1
    EndIf

    ; Sort first column
    __AMS_SortChunk($aArray, $aSortData, 0, $aSortData[0][0], $iStart, $iEnd)
    ; Now sort other columns
    For $iSortData_Row = 1 To UBound($aSortData) - 1
        ; Determine column to sort
        $iCurrCol = $aSortData[$iSortData_Row][0]
        ; Create arrays to hold data from previous columns
        Local $aBaseValue[$iSortData_Row]
        ; Set base values
        For $i = 0 To $iSortData_Row - 1
            $aBaseValue[$i] = $aArray[$iStart][$aSortData[$i][0]]
        Next
        ; Set start of this chunk
        $iChunk_Start = $iStart
        ; Now work down through array
        For $iRow = $iStart + 1 To $iEnd
            ; Match each column
            For $k = 0 To $iSortData_Row - 1
                $iMatchCol = $aSortData[$k][0]
                ; See if value in each has changed
                If $aArray[$iRow][$iMatchCol] <> $aBaseValue[$k] Then
                    ; If so and row has advanced
                    If $iChunk_Start < $iRow -1 Then
                        ; Sort this chunk
                        __AMS_SortChunk($aArray, $aSortData, $iSortData_Row, $iCurrCol, $iChunk_Start, $iRow - 1)
                    EndIf
                    ; Set new base value
                    $aBaseValue[$k] = $aArray[$iRow][$iMatchCol]
                    ; Set new chunk start
                    $iChunk_Start = $iRow
                EndIf
            Next
        Next
        ; Sort final section
        If $iChunk_Start < $iRow -1 Then
            __AMS_SortChunk($aArray, $aSortData, $iSortData_Row, $iCurrCol, $iChunk_Start, $iRow - 1)
        EndIf
    Next

EndFunc

Func __AMS_SortChunk(ByRef $aArray, $aSortData, $iRow, $iColumn, $iChunkStart, $iChunkEnd)

    ; Set default sort direction
    $iSortDirn = 0
    ; Need to prefix elements?
    If IsString($aSortData[$iRow][1]) Then
        ; Split elements
        $aSortOrder = StringSplit($aSortData[$iRow][1], ",")
        ; Add prefix to each element
        For $i = $iChunkStart To $iChunkEnd
            For $j = 1 To $aSortOrder[0]
                If $aArray[$i][$iColumn] = $aSortOrder[$j] Then
                    $aArray[$i][$iColumn] = StringFormat("%02i-", $j) & $aArray[$i][$iColumn]
                    ExitLoop
                EndIf
            Next
            ; Deal with anything that does not match
            If $j > $aSortOrder[0] Then
                $aArray[$i][$iColumn] = StringFormat("%02i-", $j) & $aArray[$i][$iColumn]
            EndIf
        Next
    Else
        ; Set required sort direction if no list
        $iSortDirn = $aSortData[$iRow][1]
    EndIf
    ; Sort the chunk
    _ArraySort($aArray, $iSortDirn, $iChunkStart, $iChunkEnd, $iColumn)
    ; Remove any prefixes
    If IsString($aSortData[$iRow][1]) Then
        For $i = $iChunkStart To $iChunkEnd
            $aArray[$i][$iColumn] = StringTrimLeft($aArray[$i][$iColumn], 3)
        Next
    EndIf

EndFunc
I will try and produce an example of getting the data from a ListView and reloading it now. ;)

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

  • Moderators
  • Solution

cloudofxyz,

And here it is - a fully working script (for me at least): ;)

#include <GUIConstantsEx.au3>
#include <Constants.au3>
#include <GuiListView.au3>
#include <Array.au3>
#include <EditConstants.au3>

Global $aArray[][] = [ _
    ["Ggg", "Male", "Teenage", 90], _
    ["Jjjj", "Male", "Unknown", 50], _
    ["Lkm", "Male", "Adult", 89], _
    ["Ers", "Male", "Unknown", 55], _
    ["Lkm", "Female", "Unknown", 60], _
    ["Fjjj", "Unknown", "Kid", 60], _
    ["Jppp", "Unknown", "Adult", 50], _
    ["Asz", "Female", "Kid", 70], _
    ["JFK", "Unknown", "Adult", 85], _
    ["Hhh", "Female", "Teenage", 86]]

; Sort requirement:
; Column then either 0/1 (Ascending/Descending) or string with required order (anything else comes after these)
Global $aSortData[3][2] = [ _
    [1, "Male,Female"], _
    [2, "Adult,Teenage,Kid"], _
    [3, 1]]


; Create GUI
$hGUI = GUICreate("Test", 500, 500)
GUISetBkColor(0xC4C4C4)

$cLV = GUICtrlCreateListView("Name|Gender|Type|Score", 10, 10, 480, 400, $LVS_SINGLESEL, BitOR($LVS_EX_FULLROWSELECT, $LVS_EX_GRIDLINES))
For $i = 0 To 3
    _GUICtrlListView_SetColumnWidth($cLV, $i, 115)
Next

_LoadArrayToLV($cLV, $aArray)

$cEdit_Name = GUICtrlCreateEdit("", 10, 420, 110, 20, $ES_RIGHT)
$cCombo_Gender = GUICtrlCreateCombo("", 125, 420, 110, 20)
GUICtrlSetData($cCombo_Gender, "Male|Female|Unknown", "Unknown")
$cCombo_Type = GUICtrlCreateCombo("", 240, 420, 110, 20)
GUICtrlSetData($cCombo_Type, "Adult|Teenage|Kid|Unknown", "Unknown")
$cEdit_Score = GUICtrlCreateEdit("", 355, 420, 110, 20, BitOr($ES_RIGHT, $ES_NUMBER))

$cAddData = GUICtrlCreateButton("Add", 10, 450, 80, 30)
$cSortData = GUICtrlCreateButton("Sort", 410, 450, 80, 30)

GUISetState()

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            Exit
        Case $cAddData
            If GUICtrlRead($cEdit_Name) = "" Or GUICtrlRead($cEdit_Score) = "" Then
                MsgBox($MB_SYSTEMMODAL + $MB_ICONWARNING, "Error", "Please complete all fields")
            Else
                $sData = GUICtrlRead($cEdit_Name) & "|" & GUICtrlRead($cCombo_Gender) & "|" & GUICtrlRead($cCombo_Type) & "|" & GUICtrlRead($cEdit_Score)
                GUICtrlCreateListViewItem($sData, $cLV)
            EndIf
        Case $cSortData
            $aArray = _ReadLVToArray($cLV)
            _ArrayMultiSort($aArray, $aSortData)
            _LoadArrayToLV($cLV, $aArray)
    EndSwitch
WEnd

Func _ReadLVToArray($cLV)

    Local $aLVArray = "", $aRow

    ; Get the ListView handle
    Local $hLV = GUICtrlGetHandle($cLV)
    ; Get ListView row count
    Local $iRows = _GUICtrlListView_GetItemCount($hLV)
    ; Get ListView column count
    Local $iCols = _GUICtrlListView_GetColumnCount($hLV)
    ; Create 2D array to hold ListView content
    Local $aLVArray[$iRows][$iCols]
    ; Read ListView content into array
    For $i = 0 To $iRows - 1
        ; Read the row content
        $aRow = _GUICtrlListView_GetItemTextArray($hLV, $i)
        For $j = 1 To $aRow[0]
            ; Add to the ListView content array
            $aLVArray[$i][$j - 1] = $aRow[$j]
        Next
    Next
    ; Return array or empty string
    Return $aLVArray

EndFunc

Func _LoadArrayToLV($cLV, $aArray)

    Local $sLine

    ; Get the ListView handle
    Local $hLV = GUICtrlGetHandle($cLV)

    ; Delete existing items
    For $i = _GUICtrlListView_GetItemCount($hLV) - 1 To 0 Step -1
        GUICtrlDelete(_GUICtrlListView_GetItemParam($hLV, $i))
    Next
    ; Refill items from array
    For $i = 0 To UBound($aArray) - 1
        ; Create item text
        $sLine = ""
        For $j = 0 To UBound($aArray, 2) - 1
            $sLine &= $aArray[$i][$j] & "|"
        Next
        ; Create item
        GUICtrlCreateListViewItem(StringTrimRight($sLine, 1), $cLV)
    Next

EndFunc

Func _ArrayMultiSort(ByRef $aArray, $aSortData, $iStart = 0, $iEnd = 0)

    ; Set default End value
    If $iEnd = 0 Then
        $iEnd = UBound($aArray) - 1
    EndIf

    ; Sort first column
    __AMS_SortChunk($aArray, $aSortData, 0, $aSortData[0][0], $iStart, $iEnd)
    ; Now sort other columns
    For $iSortData_Row = 1 To UBound($aSortData) - 1
        ; Determine column to sort
        $iCurrCol = $aSortData[$iSortData_Row][0]
        ; Create arrays to hold data from previous columns
        Local $aBaseValue[$iSortData_Row]
        ; Set base values
        For $i = 0 To $iSortData_Row - 1
            $aBaseValue[$i] = $aArray[$iStart][$aSortData[$i][0]]
        Next
        ; Set start of this chunk
        $iChunk_Start = $iStart
        ; Now work down through array
        For $iRow = $iStart + 1 To $iEnd
            ; Match each column
            For $k = 0 To $iSortData_Row - 1
                $iMatchCol = $aSortData[$k][0]
                ; See if value in each has changed
                If $aArray[$iRow][$iMatchCol] <> $aBaseValue[$k] Then
                    ; If so and row has advanced
                    If $iChunk_Start < $iRow -1 Then
                        ; Sort this chunk
                        __AMS_SortChunk($aArray, $aSortData, $iSortData_Row, $iCurrCol, $iChunk_Start, $iRow - 1)
                    EndIf
                    ; Set new base value
                    $aBaseValue[$k] = $aArray[$iRow][$iMatchCol]
                    ; Set new chunk start
                    $iChunk_Start = $iRow
                EndIf
            Next
        Next
        ; Sort final section
        If $iChunk_Start < $iRow -1 Then
            __AMS_SortChunk($aArray, $aSortData, $iSortData_Row, $iCurrCol, $iChunk_Start, $iRow - 1)
        EndIf
    Next

EndFunc

Func __AMS_SortChunk(ByRef $aArray, $aSortData, $iRow, $iColumn, $iChunkStart, $iChunkEnd)

    ; Set default sort direction
    $iSortDirn = 0
    ; Need to prefix elements?
    If IsString($aSortData[$iRow][1]) Then
        ; Split elements
        $aSortOrder = StringSplit($aSortData[$iRow][1], ",")
        ; Add prefix to each element
        For $i = $iChunkStart To $iChunkEnd
            For $j = 1 To $aSortOrder[0]
                If $aArray[$i][$iColumn] = $aSortOrder[$j] Then
                    $aArray[$i][$iColumn] = StringFormat("%02i-", $j) & $aArray[$i][$iColumn]
                    ExitLoop
                EndIf
            Next
            ; Deal with anything that does not match
            If $j > $aSortOrder[0] Then
                $aArray[$i][$iColumn] = StringFormat("%02i-", $j) & $aArray[$i][$iColumn]
            EndIf
        Next
    Else
        ; Set required sort direction if no list
        $iSortDirn = $aSortData[$iRow][1]
    EndIf
    ; Sort the chunk
    _ArraySort($aArray, $iSortDirn, $iChunkStart, $iChunkEnd, $iColumn)
    ; Remove any prefixes
    If IsString($aSortData[$iRow][1]) Then
        For $i = $iChunkStart To $iChunkEnd
            $aArray[$i][$iColumn] = StringTrimLeft($aArray[$i][$iColumn], 3)
        Next
    EndIf

EndFunc
Please ask if you have any questions. :)

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

Melba32,

Great Job ! I really like that stand alone function to sort the arrays on several levels :)

Yesterday, I also spend my several hours to figure out the code to load the array into the listview.

I just cannot believe myself that i've missed 4 lines of code only to load it back to listview.

They are :

_GUICtrlListView_DeleteAllItems($hListView)
For $i = 0 To $totaldata-1       
GUICtrlCreateListViewItem($aData[$i][0] &"|" &$aData[$i][1] &"|" &$aData[$i][2] &"|" &$aData[$i][3], $hListView)
Next
However, I have no internet connection to reply to this topic. And now, I just used the public PC for internet.

Soon as I have the Internet connection back, I will re-post the fully working script of my version also.

So..this topic is SOLVED.

Big Thanks to Melba32.

Edit :

As I promised. This is my version of fully working script :

#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#Include <string.au3>
#include <EditConstants.au3>
#include <Array.au3>

Global $msg, $mainGUI ,$hListView
Global $edit1,$edit2,$edit3,$edit4   
Global $addButton,$mainButton,$column1,$column2,$column3,$column4
Global $stringobtained ,$array1,$totaldata
Global $iTopIndex,$iFemale_Start,$iUnknown_Start,$iMale_Teen_Start,$iMale_Kid_Start,$iMale_Unknown_Start,$iFemale_Adult_Start,$iFemale_Teen_Start
Global $iFemale_Kid_Start,$iFemale_Unknown_Start,$iUnknown_Adult_Start,$iUnknown_Teen_Start,$iUnknown_Kid_Start,$iUnknown_Unknown_Start,$aData

Opt('MustDeclareVars', 1)

Example1()


Func Example1()
    
    

    $mainGUI = GUICreate("Test LV auto sort",340,400) 
    $addButton = GUICtrlCreateButton("ADD DATA", 100, 280, 140, 40)
    $mainButton = GUICtrlCreateButton("Sort It", 100, 340, 140, 40)

    $hListView = GUICtrlCreateListView("Name|Gender|Type|Score", 10, 12, 318, 230,BitOR($LVS_EDITLABELS,$LVS_SINGLESEL),BitOR($LVS_EX_FULLROWSELECT,$LVS_EX_GRIDLINES))

    _GUICtrlListView_SetExtendedListViewStyle($hListView, BitOR($LVS_EX_GRIDLINES, $LVS_EX_FULLROWSELECT))
    
    $edit1 = GUICtrlCreateEdit("",12,250,100,20, $ES_RIGHT)
    $edit2 = GUICtrlCreateCombo("",114,250,80,20, $ES_RIGHT)
    GUICtrlSetData(-1, "Male|Female|Unknown","Unknown")
    $edit3 = GUICtrlCreateCombo("",196,250,80,20, $ES_RIGHT)
    GUICtrlSetData(-1, "Adult|Teenage|Kid|Unknown","Unknown")
    $edit4 = GUICtrlCreateEdit("",278,250,48,20, $ES_RIGHT)
    
    $column1 = _GUICtrlListView_SetColumn($hListView ,0,"Name",100,2)
    $column2 = _GUICtrlListView_SetColumn($hListView ,1,"Gender",80,2)
    $column3 = _GUICtrlListView_SetColumn($hListView ,2,"Type",80,2)
    $column4 = _GUICtrlListView_SetColumn($hListView ,3,"Score",50,2)
    
        
    GUICtrlCreateListViewItem("Ggg|Male|Teenage|90", $hListView)
    GUICtrlCreateListViewItem("Jjjj|Male|Unknown|50", $hListView)
    GUICtrlCreateListViewItem("Lkm|Male|Adult|89", $hListView)
    GUICtrlCreateListViewItem("Ers|Male|Unknown|55", $hListView)
    GUICtrlCreateListViewItem("Lkm|Female|Unknown|60", $hListView)
    GUICtrlCreateListViewItem("Fjjj|Unknown|Kid|60", $hListView)
    GUICtrlCreateListViewItem("Jppp|Unknown|Adult|50", $hListView)
    GUICtrlCreateListViewItem("Asz|Female|Kid|70", $hListView)
    GUICtrlCreateListViewItem("JFK|Unknown|Adult|85", $hListView)
    GUICtrlCreateListViewItem("Hhh|Female|Teenage|86", $hListView)
    
    
    GUISetState()
    
    While 1
        $msg = GUIGetMsg()
        Select
            Case $msg = $GUI_EVENT_CLOSE
                ExitLoop
            Case $msg = $addButton              
                Call("adddata")
            Case $msg = $mainButton
                Call("sort")
        EndSelect
    WEnd
    GUIDelete()
EndFunc 

Func adddata()
    GUICtrlCreateListViewItem(GUICtrlRead($edit1) &"|" &GUICtrlRead($edit2) &"|" &GUICtrlRead($edit3) &"|" &GUICtrlRead($edit4), $hListView)
EndFunc

Func sort()
    
    Dim $aData[1][4]
    $totaldata = _GUICtrlListView_GetItemCount($hListView)
    
    For $j= 0 To $totaldata-1
        $stringobtained =   _GUICtrlListView_GetItemTextString($hListView, $j)  
        $array1 = _StringExplode($stringobtained, "|", 0)
    
        ReDim $aData[UBound($aData) +1][4]
            $aData[UBound($aData) -1][0] = $array1[0]
            $aData[UBound($aData) -1][1] = $array1[1]
            $aData[UBound($aData) -1][2] = $array1[2]
            $aData[UBound($aData) -1][3] = $array1[3] + 0 ; 0 is to validate as number
            
    Next
    
    
    
    
_ArrayDelete($aData, 0)


$iTopIndex = UBound($aData) - 1

; First change the element titles to get the correct sort order
For $i = 0 To UBound($aData) - 1
    ; Gender
    If $aData[$i][1] = "Male" Then
        $aData[$i][1] = "1-Male"
    ElseIf $aData[$i][1] = "Female" Then
        $aData[$i][1] = "2-Female"
    Else
        $aData[$i][1] = "3-Unknown"
    EndIf
    ; Age
    If $aData[$i][2] = "Adult" Then
        $aData[$i][2] = "1-Adult"
    ElseIf $aData[$i][2] = "Teenage" Then
        $aData[$i][2] = "2-Teenage"
    ElseIf $aData[$i][2] = "Kid" Then
        $aData[$i][2] = "3-Kid"
    Else
        $aData[$i][2] = "4-Unknown"
    EndIf
Next

; First sort on gender
_ArraySort($aData, 0, 0, 0, 1)

;~ _ArrayDisplay($aData, "Gender Sorted") ; Just for display

; Now look for 3 gender options and sort the 3 sections on age
$iFemale_Start = _ArrayScan(0, $iTopIndex, "1-Male")
If $iFemale_Start > 1 Then ; Sorting 0 to 0 means the whole array which we do not want
    _ArraySort($aData, 0, 0, $iFemale_Start - 1, 2)
EndIf
$iUnknown_Start = _ArrayScan($iFemale_Start, $iTopIndex, "2-Female")
If $iUnknown_Start > 1 Then
    _ArraySort($aData, 0, $iFemale_Start, $iUnknown_Start - 1, 2)
EndIf
_ArraySort($aData, 0, $iUnknown_Start, 0, 2)

;~ _ArrayDisplay($aData, "Age Sorted") ; Just for display

; Now we sort on the scores
$iMale_Teen_Start = _ArrayScan(0, $iTopIndex, "1-Male", "1-Adult")
If $iMale_Teen_Start > 1 Then
    _ArraySort($aData, 1, 0, $iMale_Teen_Start - 1, 3)
EndIf
$iMale_Kid_Start = _ArrayScan($iMale_Teen_Start, $iTopIndex, "1-Male", "2-Teenage")
If $iMale_Kid_Start > 1 Then
    _ArraySort($aData, 1, $iMale_Teen_Start, $iMale_Kid_Start - 1, 3)
EndIf
$iMale_Unknown_Start = _ArrayScan($iMale_Kid_Start, $iTopIndex, "1-Male", "3-Kid")
If $iMale_Unknown_Start > 1 Then
    _ArraySort($aData, 1, $iMale_Kid_Start, $iMale_Unknown_Start - 1, 3)
EndIf
$iFemale_Adult_Start = _ArrayScan($iMale_Unknown_Start, $iTopIndex, "1-Male", "4-Unknown")
If $iFemale_Adult_Start > 1 Then
    _ArraySort($aData, 1, $iMale_Unknown_Start, $iFemale_Adult_Start - 1, 3)
EndIf

;~ _ArrayDisplay($aData, "Males fully sorted") ; Just for display

$iFemale_Teen_Start = _ArrayScan($iFemale_Adult_Start, $iTopIndex, "2-Female", "1-Adult")
If $iFemale_Teen_Start > 1 Then
    _ArraySort($aData, 1, $iFemale_Adult_Start, $iFemale_Teen_Start - 1, 3)
EndIf
$iFemale_Kid_Start = _ArrayScan($iFemale_Teen_Start, $iTopIndex, "2-Female", "2-Teenage")
If $iFemale_Kid_Start > 1 Then
    _ArraySort($aData, 1, $iFemale_Teen_Start, $iFemale_Kid_Start - 1, 3)
EndIf
$iFemale_Unknown_Start = _ArrayScan($iFemale_Kid_Start, $iTopIndex, "2-Female", "3-Kid")
If $iFemale_Unknown_Start > 1 Then
    _ArraySort($aData, 1, $iFemale_Kid_Start, $iFemale_Unknown_Start - 1, 3)
EndIf
$iUnknown_Adult_Start = _ArrayScan($iFemale_Unknown_Start, $iTopIndex, "2-Female", "4-Unknown")
If $iUnknown_Adult_Start > 1 Then
    _ArraySort($aData, 1, $iFemale_Unknown_Start, $iUnknown_Adult_Start - 1, 3)
EndIf

;~ _ArrayDisplay($aData, "Females fully sorted") ; Just for display

$iUnknown_Teen_Start = _ArrayScan($iUnknown_Adult_Start, $iTopIndex, "3-Unknown", "1-Adult")
If $iUnknown_Teen_Start > 1 Then
    _ArraySort($aData, 1, $iUnknown_Adult_Start, $iUnknown_Teen_Start - 1, 3)
EndIf
$iUnknown_Kid_Start = _ArrayScan($iUnknown_Teen_Start, $iTopIndex, "3-Unknown", "2-Teenage")
If $iUnknown_Kid_Start > 1 Then
    _ArraySort($aData, 1, $iUnknown_Teen_Start, $iUnknown_Kid_Start - 1, 3)
EndIf
$iUnknown_Unknown_Start = _ArrayScan($iUnknown_Kid_Start, $iTopIndex, "3-Unknown", "3-Kid")
If $iUnknown_Unknown_Start > 1 Then
    _ArraySort($aData, 1, $iUnknown_Kid_Start, $iUnknown_Unknown_Start - 1, 3)
EndIf
_ArraySort($aData, 1, $iUnknown_Unknown_Start, 0, 3)

;~ _ArrayDisplay($aData, "Unknowns fully sorted") ; Just for display

; Now reset the element titles
For $i = 0 To UBound($aData) - 1
    ; Gender
    If $aData[$i][1] = "1-Male" Then
        $aData[$i][1] = "Male"
    ElseIf $aData[$i][1] = "2-Female" Then
        $aData[$i][1] = "Female"
    Else
        $aData[$i][1] = "Unknown"
    EndIf
    ; Age
    If $aData[$i][2] = "1-Adult" Then
        $aData[$i][2] = "Adult"
    ElseIf $aData[$i][2] = "2-Teenage" Then
        $aData[$i][2] = "Teenage"
    ElseIf $aData[$i][2] = "3-Kid" Then
        $aData[$i][2] = "Kid"
    Else
        $aData[$i][2] = "Unknown"
    EndIf
Next

;~ _ArrayDisplay($aData, "Final sorted array")  ; Just for display

_GUICtrlListView_DeleteAllItems($hListView)

For $i = 0 To $totaldata-1  
    GUICtrlCreateListViewItem($aData[$i][0] &"|" &$aData[$i][1] &"|" &$aData[$i][2]  &"|" &$aData[$i][3], $hListView)
Next



EndFunc




Func _ArrayScan($iStartIndex, $iEndIndex, $sGender, $sAge = "")

;~     If $sAge Then ConsoleWrite($sGender & " - " & $sAge & @CRLF)  ;for console writing only

    For $i = $iStartIndex To $iEndIndex
        If $sAge Then
            If Not ($aData[$i][1] = $sGender And $aData[$i][2] = $sAge) Then ExitLoop
        Else
            If $aData[$i][1] <> $sGender Then ExitLoop
        EndIf
    Next

    Return $i

EndFunc
Edited by cloudofxyz
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...