Jump to content

_GUICtrlListViewSort - Part 2


 Share

Recommended Posts

I had the problem, that my ListViewItems are connected to an event, but after sorting the conection was broken. So I implement the possibility to combine the sorted ListViewItems again to an event:

Func _GUICtrlListViewSort(ByRef $h_listview, ByRef $v_descending, $i_sortcol, $s_Title = "", $s_text = "", $event = "")
    Local $X, $Y, $b_desc, $columns, $items, $v_item, $temp_item
    If _GUICtrlListViewGetItemCount($h_listview) Then
        If (StringLen($s_Title) == 0) Then
            $s_Title = WinGetTitle("")
        EndIf
        If (IsArray($v_descending)) Then
            $b_desc = $v_descending[$i_sortcol]
        Else
            $b_desc = $v_descending
        EndIf
        $columns = _GUICtrlListViewGetSubItemsCount($h_listview, $s_Title, $s_text)
        $items = _GUICtrlListViewGetItemCount($h_listview)
        For $X = 1 To $columns
            $temp_item = $temp_item & " |"
        Next
        $temp_item = StringTrimRight($temp_item, 1)
        If ($columns > 1) Then
            Local $a_lv[$items][$columns]
            For $X = 0 To UBound($a_lv) - 1 Step 1
                For $Y = 0 To UBound($a_lv, 2) - 1 Step 1
                    $v_item = _GUICtrlListViewGetItemText($h_listview, $X, $Y, $s_Title, $s_text)
                    If (StringIsFloat($v_item) Or StringIsInt($v_item)) Then
                        $a_lv[$X][$Y] = Number($v_item)
                    Else
                        $a_lv[$X][$Y] = $v_item
                    EndIf
                Next
            Next
            _GUICtrlListViewDeleteAllItems($h_listview)
            _ArraySort($a_lv, $b_desc, 0, 0, $columns, $i_sortcol)
            For $X = 0 To UBound($a_lv) - 1 Step 1
                Local $items = GUICtrlCreateListViewItem($temp_item, $h_listview)
                If IsDeclared ( "event" ) Then
                    GuiCtrlSetOnEvent($items, $event)
                EndIf
                For $Y = 0 To UBound($a_lv, 2) - 1 Step 1
                    _GUICtrlListViewSetItemText($h_listview, $X, $Y, $a_lv[$X][$Y])
                Next
            Next
        Else
            Local $a_lv[$items]
            For $X = 0 To UBound($a_lv) - 1 Step 1
                $v_item = _GUICtrlListViewGetItemText($h_listview, $X, -1, $s_Title, $s_text)
                If (StringIsFloat($v_item) Or StringIsInt($v_item)) Then
                    $a_lv[$X] = Number($v_item)
                Else
                    $a_lv[$X] = $v_item
                EndIf
            Next
            _GUICtrlListViewDeleteAllItems($h_listview)
            _ArraySort($a_lv, $b_desc)
            For $X = 0 To UBound($a_lv) - 1 Step 1
                GUICtrlCreateListViewItem(" ", $h_listview)
                Local $items = GUICtrlCreateListViewItem(" ", $h_listview)
                If IsDeclared ( "event" ) Then
                    GuiCtrlSetOnEvent($items, $event)
                EndIf
                _GUICtrlListViewSetItemText($h_listview, $X, 0, $a_lv[$X])
            Next
        EndIf
        If (IsArray($v_descending)) Then
            $v_descending[$i_sortcol] = Not $b_desc
        Else
            $v_descending = Not $b_desc
        EndIf
    EndIf
EndFunc;==>_GUICtrlListViewSort

I don't check if it's useful for other Functions in this UDF, too.

Edited by SnowOfIce
Link to comment
Share on other sites

I already used gafrost newer version, but here are my version, where I originally implented the change. So if I make an error during implemention to gafrost's version, look here:

This Version is NOT recommended! Use version above, or at least gafrost's final

Func _GUICtrlListViewSort(ByRef $h_listview, ByRef $v_descending, $i_sortcol, $s_Title = "", $s_text = "", $event = "")
    Local $X, $Y, $b_desc, $columns, $items, $v_item, $temp_item
    If (StringLen($s_Title) == 0) Then
        $s_Title = WinGetTitle("")
    EndIf
    If (IsArray($v_descending)) Then
        $b_desc = $v_descending[$i_sortcol]
    Else
        $b_desc = $v_descending
    EndIf
    $columns = _GUICtrlListViewGetSubItemsCount($h_listview, $s_Title, $s_text)
    $items = _GUICtrlListViewGetItemCount($h_listview)
    For $X = 1 To $columns
        $temp_item = $temp_item & " |"
    Next
    $temp_item = StringTrimRight($temp_item, 1)
    If ($columns > 1) And ($items > 1) Then
        Local $a_lv[$items][$columns]
        For $X = 0 To UBound($a_lv) - 1 Step 1
            For $Y = 0 To UBound($a_lv, 2) - 1 Step 1
                $v_item = _GUICtrlListViewGetItemText($h_listview, $X, $Y, $s_Title, $s_text)
                If (StringIsFloat($v_item) Or StringIsInt($v_item)) Then
                    $a_lv[$X][$Y] = Number($v_item)
                Else
                    $a_lv[$X][$Y] = $v_item
                EndIf
            Next
        Next
        _GUICtrlListViewDeleteAllItems($h_listview)
        _ArraySort($a_lv, $b_desc, 0, 0, $columns, $i_sortcol)
        For $X = 0 To UBound($a_lv) - 1 Step 1
            local $items = GUICtrlCreateListViewItem($temp_item, $h_listview)
            If IsDeclared ( "event" ) Then
                GuiCtrlSetOnEvent($items, $event)
            EndIf

            For $Y = 0 To UBound($a_lv, 2) - 1 Step 1
                _GUICtrlListViewSetItemText($h_listview, $X, $Y, $a_lv[$X][$Y])
            Next
        Next
    ElseIf ($items > 1) Then
        Local $a_lv[$items]
        For $X = 0 To UBound($a_lv) - 1 Step 1
            $v_item = _GUICtrlListViewGetItemText($h_listview, $X, -1, $s_Title, $s_text)
            If (StringIsFloat($v_item) Or StringIsInt($v_item)) Then
                $a_lv[$X] = Number($v_item)
            Else
                $a_lv[$X] = $v_item
            EndIf
        Next
        _GUICtrlListViewDeleteAllItems($h_listview)
        _ArraySort($a_lv, $b_desc)
        For $X = 0 To UBound($a_lv) - 1 Step 1
            Local $items = GUICtrlCreateListViewItem(" ", $h_listview)
            If IsDeclared ( "event" ) Then
                GuiCtrlSetOnEvent($items, $event)
            EndIf
            _GUICtrlListViewSetItemText($h_listview, $X, 0, $a_lv[$X])
        Next
    EndIf
    If (IsArray($v_descending)) Then
        $v_descending[$i_sortcol] = Not $b_desc
    Else
        $v_descending = Not $b_desc
    EndIf
EndFunc  ;==>_GUICtrlListViewSort
Edited by SnowOfIce
Link to comment
Share on other sites

Here's an example.

It's the "Process list and window controls tester" from TuMbLeWeEd with the ability to Sort the columns.

The original you could find here:

TuMbLeWeEd's Process list and window controls tester

I changed that stuff with the negative conditions. As I became adepted, the option with IsDeclared is however possible!

s_Process_list_and_window_controls_tester.zip

GuiListView.au3

Edited by SnowOfIce
Link to comment
Share on other sites

I found a wired behaviour. If you start the macro with Scite, it run. But if I compile it and run an exe-file I require a more specific If-Case:

If IsDeclared ( "event" ) Then

hast to be changed to

If IsDeclared ( "event" ) And Not ( $event = "" ) Then

And another problem: Sometimes I have strings there are actually numbers, but I want to hold the beginning zeros (Hex-numbers for example).

On other hand, if I just compare strings, a 1111 would be "smaller" than a 4.

A possible solution is to change the following If-cases:

If (StringIsFloat($v_item) Or StringIsInt($v_item)) And Not ( StringLeft($v_item, 1) ="0") Then
      $a_lv[$X] = Number($v_item)       ;numbers like 4 , 3465, 5.34 , 345.5
ElseIf StringIsFloat($v_item) And StringLeft($v_item, 2) ="0." Then
      $a_lv[$X] = Number($v_item)       ;numbers like 0.346
Else
      $a_lv[$X] = $v_item      ;strings like "qwe" , "q23" , "000013"
EndIf
Edited by SnowOfIce
Link to comment
Share on other sites

I'm thinking this will work better, but I'll have to do more testing

If (StringIsFloat($v_item) Or StringIsInt($v_item)) And (Not StringLeft($v_item, 1) ="0") Then
                    $a_lv[$X] = Number($v_item)
                ElseIf (StringIsFloat($v_item) And Not StringRight($v_item, 1) ="0") Then
                    $a_lv[$X] = Number($v_item)
                Else
                    $a_lv[$X] = $v_item
                EndIf
Edited by gafrost

SciTE for AutoItDirections for Submitting Standard UDFs

 

Don't argue with an idiot; people watching may not be able to tell the difference.

 

Link to comment
Share on other sites

Didn't like the results

keeping the current conditions

If (StringIsFloat($v_item) Or StringIsInt($v_item)) Then
                    $a_lv[$X][$Y] = Number($v_item)
                Else
                    $a_lv[$X][$Y] = $v_item
                EndIf

if the number is 0.3456 it's not changed it's still 0.3456

however if a number is a fraction and ends with 0 the zero is dropped

personally i can live with that, for example 4.50 becomes 4.5 or 4.0 becomes 4

I'll look into the event param more, i'll have to make a smaller example to to test with.

Gary

SciTE for AutoItDirections for Submitting Standard UDFs

 

Don't argue with an idiot; people watching may not be able to tell the difference.

 

Link to comment
Share on other sites

No. I mean it like I wrote it.

ElseIf StringIsFloat($v_item) And StringLeft($v_item, 2) ="0." Then

So I wanted to catch all float numbers with a leading zero followed by a point. If I write a float number like "000.123" then there migth be a reason not to write "0.123".

Ending zeros on the rigth - there are you totally correct - are uninteresting and would be caugth by the first If-Case if there are no leading zeros.

Link to comment
Share on other sites

No. I mean it like I wrote it.

ElseIf StringIsFloat($v_item) And StringLeft($v_item, 2) ="0." Then

So I wanted to catch all float numbers with a leading zero followed by a point. If I write a float number like "000.123" then there migth be a reason not to write "0.123".

Ending zeros on the rigth - there are you totally correct - are uninteresting and would be caugth by the first If-Case if there are no leading zeros.

<{POST_SNAPBACK}>

What your suggesting would break the sort for all other users that might put whole numbers and floats in same column, thus making the column contain strings and whole numbers, or strings, whole, and floats, and strings are sorted differently than numbers, character by character, where number is < or >

Gary

SciTE for AutoItDirections for Submitting Standard UDFs

 

Don't argue with an idiot; people watching may not be able to tell the difference.

 

Link to comment
Share on other sites

suggest if the generic sort doesn't fit your needs, couple things you could do

1: if all the numbers in the column have the same # of digits on each side of the decimal than put a space at the end of the number, should be treated as string then.

2: or create a custom sort to fit your needs.

SciTE for AutoItDirections for Submitting Standard UDFs

 

Don't argue with an idiot; people watching may not be able to tell the difference.

 

Link to comment
Share on other sites

Here's an example.

It's the "Process list and window controls tester" from TuMbLeWeEd with the ability to Sort the columns.

The original you could find here:

TuMbLeWeEd's Process list and window controls tester

I changed that stuff with the negative conditions. As I became adepted, the option with IsDeclared is however possible!

<{POST_SNAPBACK}>

Currently there are no click events for ListView items in autoit, so the event param is useless at this point.

SciTE for AutoItDirections for Submitting Standard UDFs

 

Don't argue with an idiot; people watching may not be able to tell the difference.

 

Link to comment
Share on other sites

What your suggesting would break the sort for all other users that might put whole numbers and floats in same column, thus making the column contain strings and whole numbers, or strings, whole, and floats, and strings are sorted differently than numbers, character by character, where number is < or >

Gary

<{POST_SNAPBACK}>

Exactly because of this I suggest to change your code. If I write a number different than normal, so with leading zeros, than there is a particular reason, and this is not an example, that mayby sometimes somehow migth happen. In particular if I sort Hex-formatted numbers than I want to leave them as a string.

My code did exactly what it should, I think:

1 , 2 , 3 , 4 , 567 ... => Numbers (1)

1.0 , 2.40 , 5.456 ... => Numbers ending zero migth be deleted, but it migth be ok (1)

0.1 , 0.45 , 0.6 ... => Numbers (2)

word , test , qwe ... => String (3)

0004F4 , 034d34 ... => String (contains also letter) (3)

043404 , 000034 ... => String (It's pretty sure, that the leading zero is reasonable, for example a Hex-Format) (3)

00.34 , 000.24 ... => String, there migth be a particular reason, why I add additional zeros at the beginning (but I don,t know any special case, where I could use this) (3)

If (StringIsFloat($v_item) Or StringIsInt($v_item)) And Not ( StringLeft($v_item, 1) ="0") Then
      $a_lv[$X] = Number($v_item)      ; (1)
ElseIf StringIsFloat($v_item) And StringLeft($v_item, 2) ="0." Then
      $a_lv[$X] = Number($v_item)      ; (2)
Else
      $a_lv[$X] = $v_item              ; (3)
EndIf

Onliest weakness:

430023 , 00FF00 ... => Both Hex-Numbers, first will be converted to a number, second to a string

But mayby there exist a way around: Don't save the converted values in the array, but create an additional array, where you note which kind of values are in the column-array. For example: S => string, I => Int, H => Hex (combine if necessary IH=> Hex and Int), so if there are Ints and Hex-numbers in the array, it's supposable that all values are Hex-Values, if not you could convert them anyway.

You could also check if the length of all values are constant, then there is no matter, if you compare strings or numbers.

Edited by SnowOfIce
Link to comment
Share on other sites

Sorry, but I don't see where it could break anything. Floats will still converted to a number just as how Ints.

The onliest "Numbers" won't be converted are numbers, they are not formated like numbers.

Nobody will write a number with leading zeros except he want it like this. But in this case it's no longer a number, because a number has no leading zeros. So it must be a string and should be handled like one. The same with floats with leading zeros!

And all other numbers will still converted into numbers, exactly like in your original!

But, Ok! It's your UDF, so I close this discussion from my side, and just change my UDF-Version for myself manualy.

If I figured out a precise way to fix the weakness that will be my last post in this discussion.

Edited by SnowOfIce
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...