Sign in to follow this  
Followers 0
blindwig

UDF: _ArrayBox()

11 posts in this topic

I wanted a better way to display an array than _ArrayDisplay. It's 2 biggest limitations were that since it's using a messagebox, really big arrays will be too big to fit the box on the screen, and secondly that it doesn't show 2-dimensional arrays.

My function handles 1d and 2d arrays, and also 0-based and 1-based arrays. It creates a GUI Form (that is sizable and maximizable) with a listview on it that displays the array with the index numbers listed down the side.

CODE

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

;

; Function Name: _ArrayBox()

; Description: Shows an array in a GUI window. Improved version of _ArrayDisplay

; Parameter(s): $Array - An array, 1d or 2d, 0-based or 1-based

; $ArrayBase - 1 or 0 - tells what base the array is

; $sTitle - the title to put on the output window

; $Width, $Height, $Left, $Top - Set the size and position of the output window

; Requirement(s): $Array must be 1d or 2d. If 1-based, then arraysize is assumed to be $Array[0] or $Array[0][0]

; Return Value(s): -1 = $Array is not an array, error=1

; Author(s): Mike Ratzlaff <mike@ratzlaff.org>

; Revision: 20050620A

;

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

;

Func _ArrayBox(ByRef $Array, $ArrayBase = 1, $sTitle = 'Array Box', $Width = 200, $Height = 200, $Left = -1, $Top = -1)

Dim $AllDone = 0, $msg, $i, $j, $ArrayDimensions = UBound($Array, 0)

Dim $hndForm_Main, $hndListView_Display

If $ArrayDimensions = 0 Then

SetError(1)

Return -1

EndIf

;Setup

If $ArrayBase <> 0 Then $ArrayBase = 1

If $ArrayBase Then

Select

Case $ArrayDimensions = 1

$ArrayMax = $Array[0]

Case $ArrayDimensions = 2

$ArrayMax = $Array[0][0]

EndSelect

Else

$ArrayMax = UBound($Array, 1) - 1

EndIf

;Create GUI

If $Height < 100 Then $Height = 100

If $Width < 100 Then $Width = 100

$hndForm_Main = GUICreate($sTitle, $Width, $Height, $Left, $Top, BitOR($WS_POPUP, $WS_CAPTION, $WS_SIZEBOX, $WS_MAXIMIZEBOX, $WS_EX_DLGMODALFRAME))

;Create List Box

If $ArrayDimensions = 1 Then

$sTemp = 'Index|Value'

ElseIf $ArrayDimensions = 2 Then

$sTemp = 'Index'

For $i = 0 To UBound($Array, 2) - 1

$sTemp = $sTemp & '|' & $i

Next

EndIf

$hndListView_Display = GUICtrlCreateListView($sTemp, 0, 0, $Width, $Height-24, BitOR($LVS_SHOWSELALWAYS, $LVS_SINGLESEL))

GUICtrlSetResizing($hndListView_Display, BitOR($GUI_DockLeft, $GUI_DockTop, $GUI_DockRight, $GUI_DockBottom))

;Create Controls, Show GUI

$hndButton_Close = GUICtrlCreateButton('&Close',$Width-80,$Height-24,80,24)

GUICtrlSetResizing($hndButton_Close, BitOR($GUI_DockRight, $GUI_DockBottom, $GUI_DockSize))

GUICtrlSetState($hndButton_Close, $GUI_DefButton)

GUISetState (@SW_SHOW, $hndForm_Main)

;Display Array

Select

Case $ArrayDimensions = 1 ;1-Dimensional Array

For $i = $ArrayBase To $ArrayMax

GUICtrlCreateListViewItem($i & '|' & $Array[$i], $hndListView_Display)

Next ;$i

Case $ArrayDimensions = 2 ;2-Dimensional Array

For $i = $ArrayBase To $ArrayMax

$sTemp=$Array[$i][0]

for $j = 1 To UBound($Array, 2) - 1

$sTemp = $sTemp & '|' & $Array[$i][$j]

Next ;$j

GUICtrlCreateListViewItem('[' & $i & ']|' & $sTemp, $hndListView_Display)

Next ;$i

Case Else ;Unhandled Type

EndSelect

;Wait for user to close box

Do

$msg = GUIGetMsg()

Select

Case $msg = $GUI_EVENT_CLOSE

$AllDone = 1

Case $msg = $hndButton_Close

$AllDone = 1

EndSelect

Until $AllDone

GUIDelete($hndForm_Main)

Return 0

EndFunc

Tell me what you think!

Share this post


Link to post
Share on other sites



Oh, I forgot to say - It's called _ArrayBox because it's going to be part of a new UDF set I'm writing for displaying complex types (stuff that doesn't display right in a MsgBox). I'm calling my functions _*Box after the MsgBox and InputBox functions.

Share this post


Link to post
Share on other sites

Oh, and here's some sample code so you can see how it looks:

Dim $a=IniReadSectionNames('C:\windows\win.ini')
_ArrayBox($a,1,'Windows Settings')
Dim $s=$a[random(1,$a[0])], $a=IniReadSection('C:\windows\win.ini',$s)
_ArrayBox($a,1,'Windows Settings: ' & $s)

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

Nice Job. :)

Just tried it with a two dimensional array and it worked perfectly. The list view looks cool too. :evil:

There are two things i think you can do to make it even better though.

1.Make all your variables Local

2.Make $ArrayBase default to 0 so it follows the standards of the other array functions.

Edited by SolidSnake

HKTunes:Softpedia | GoogleCodeLyricToy:Softpedia | GoogleCodeRCTunes:Softpedia | GoogleCodeMichtaToolsProgrammer n. - An ingenious device that turns caffeine into code.

Share this post


Link to post
Share on other sites

Nice Job.  :)

Just tried it with a two dimensional array and it worked perfectly. The list view looks cool too.    :D

<{POST_SNAPBACK}>

Great, glad you liked it!

There are two things i think you can do to make it even better though.

1.Make all your variables Local

2.Make $ArrayBase default to 0 so it follows the standards of the other array functions.

<{POST_SNAPBACK}>

1. I think that when you use Dim inside a function, it is automatically a local variable?

2. It's always hard for me to pick the default base when writing array functions. Sometime I think maybe I shouldn't have a default and just make the user specify it everytime. I picked 1 this time because that what most of the arrays I want to display are. Most functions that I use (StringSplit, IniRead*, etc) return 1-based arrays, so that's why I made it the default. And I'm putting this in a UDF library that I'm writing that is focused on 1-based arrays, so for my purposes it's better to make it 1-based by default. But if you need to include it in a project of your own, feel free to change it to suit your needs :evil:

I just found a weird bug - if you give a string for the $ArrayBase, then it will assume that the array is 0-based and will put that string for the "name" of the first index.

I also want to figure out how to make the window modal, so that the GetMsg loop doesn't take away from other GUIs that may be running. But I haven't tested that so I don't even know if it's a problem yet.

I'm also thinking of adding a feature that if you select a line in the listview, the function will return the corresponding array element number.

Share this post


Link to post
Share on other sites

Oh, and another bug I forgot to mention:

Obviously if one of your array elements has a '|' character in it, you are going to get un desirable results.

I guess I could run StringReplace on the element before using it...

Share this post


Link to post
Share on other sites

#7 ·  Posted (edited)

I just found a weird bug - if you give a string for the $ArrayBase, then it will assume that the array is 0-based and will put that string for the "name" of the first index.

Look at this quote from the helpfile:

If a string is used as a number and it doesn't contain a valid number, it will be assumed to equal 0.  For example,

    10 * "fgh" equals the number 0.

I think that when you use Dim inside a function, it is automatically a local variable?

Yes. Just looked at the help file and you are correct. Edited by SolidSnake

HKTunes:Softpedia | GoogleCodeLyricToy:Softpedia | GoogleCodeRCTunes:Softpedia | GoogleCodeMichtaToolsProgrammer n. - An ingenious device that turns caffeine into code.

Share this post


Link to post
Share on other sites

Yeah, I need to add '$ArrayBase = $ArrayBase * 1' or '$ArrayBase = Int($ArrayBase)' right after the ';setup' line.

I also found another issue - the ListView can only hold 4095 items.

Share this post


Link to post
Share on other sites

awsome... I use _arraydisplay alot to debug, and It aalways annoys me when I try to use it with an array with 600 values... this should make it so i dont have to use roundabout methods to use big arrays..


Share this post


Link to post
Share on other sites

I guess there are some browsers out there that don't let you copy code out of a CODEBOX on this forums, so here is my latest code in a regular CODE tag:

;===============================================================================
;
; Function Name: _Array1Box()
; Description: Shows an array in a GUI window. Improved version of _Array1Display
; Parameter(s): $Array - An array, 1d or 2d, 0-based or 1-based
; $ArrayBase - 1 or 0 - tells what base the array is
; $sTitle - the title to put on the output window
; $Width, $Height, $Left, $Top - Set the size and position of the output window
; Requirement(s): $Array must be 1d or 2d. If 1-based, then arraysize is assumed to be $Array[0] or $Array[0][0]
; Return Value(s): Integer, 0 or more = 0-based index of selected item
;                 -1 = no item was selected
;                 Error=1 = $Array is not an array
; Author(s): Mike Ratzlaff <mike@ratzlaff.org>
; Revision: 20050728A
;
;===============================================================================
;
Func _Array1Box(ByRef $Array, $sTitle = 'Array Box', $ArrayBase = 1, $Width = 200, $Height = 200, $Left = -1, $Top = -1)
    Local $AllDone = 0, $msg, $i, $j, $ArrayDimensions = UBound($Array, 0), $ArrayMax, $sTemp
    Local $hndForm_Array1Box_Main, $hndListView_Array1Box_Display, $hndButton_Array1Box_Close
    
    If $ArrayDimensions = 0 Then
        SetError(1)
        Return 'Given variable is not an array'
    EndIf
    
;Setup
    If $ArrayBase <> 0 Then $ArrayBase = 1
    If $ArrayBase Then
        Select
            Case $ArrayDimensions = 1
                $ArrayMax = $Array[0]
            Case $ArrayDimensions = 2
                $ArrayMax = $Array[0][0]
        EndSelect
    Else
        $ArrayMax = UBound($Array, 1) - 1
    EndIf
    
;Create GUI
    If $Height < 100 Then $Height = 100
    If $Width < 100 Then $Width = 100
    $hndForm_Array1Box_Main = GUICreate($sTitle, $Width, $Height, $Left, $Top, BitOR($WS_POPUP, $WS_CAPTION, $WS_SIZEBOX, $WS_MAXIMIZEBOX, $WS_EX_DLGMODALFRAME))
    
;Create List Box
    If $ArrayDimensions = 1 Then
        $sTemp = 'Index|Value'
    ElseIf $ArrayDimensions = 2 Then
        $sTemp = 'Index'
        For $i = 0 To UBound($Array, 2) - 1
            $sTemp = $sTemp & '|' & $i
        Next
    EndIf
    If $ArrayBase Then
        GUICtrlCreateLabel('size = (' & $ArrayMax & '/' & UBound($Array) & ')', 0, 0, $Width, 16)
    Else
        GUICtrlCreateLabel('size = (' & UBound($Array) & ')', 0, 0, $Width, 16)
    EndIf
    GUICtrlSetResizing(-1, BitOR($GUI_DockLeft, $GUI_DockTop, $GUI_DockRight, $GUI_DOCKHEIGHT))
    $hndListView_Array1Box_Display = GUICtrlCreateListView($sTemp, 0, 16, $Width, $Height-40, BitOR($LVS_SHOWSELALWAYS, $LVS_SINGLESEL))
    GUICtrlSetResizing($hndListView_Array1Box_Display, BitOR($GUI_DockLeft, $GUI_DockTop, $GUI_DockRight, $GUI_DockBottom))
    
;Create Controls, Show GUI
    $hndButton_Array1Box_Close = GUICtrlCreateButton('&Close',$Width-80,$Height-24,80,24)
    GUICtrlSetResizing($hndButton_Array1Box_Close, BitOR($GUI_DockRight, $GUI_DockBottom, $GUI_DockSize))
    GUICtrlSetState($hndButton_Array1Box_Close, BitOR($GUI_DefButton, $GUI_FOCUS))
    GUISetState (@SW_SHOW, $hndForm_Array1Box_Main)
    
;Display Array
    Select
        Case $ArrayDimensions = 1;1-Dimensional Array
            For $i = 0 To $ArrayMax
            GUICtrlCreateListViewItem($i & '|' & $Array[$i], $hndListView_Array1Box_Display)
            Next;$i
        Case $ArrayDimensions = 2;2-Dimensional Array
            For $i = 0 To $ArrayMax
                $sTemp=$Array[$i][0]
                for $j = 1 To UBound($Array, 2) - 1
                    $sTemp = $sTemp & '|' & $Array[$i][$j]
                Next;$j
                GUICtrlCreateListViewItem('[' & $i & ']|' & $sTemp, $hndListView_Array1Box_Display)
            Next;$i
        Case Else;Unhandled Type
            
    EndSelect
    
;Wait for user to close box
    Do
        $msg = GUIGetMsg()
        Select
            Case $msg = $GUI_EVENT_CLOSE
                $AllDone = 1
            Case $msg = $hndButton_Array1Box_Close
                $AllDone = 1
        EndSelect
    Until $AllDone
    
;Destroy GUI, Return index of selected item
    $i = ControlListView(WinGetTitle($sTitle), '', $hndListView_Array1Box_Display, "GetSelected")
    If $i='' Then $i = -1
    GUIDelete($hndForm_Array1Box_Main)
    Return $i
EndFunc

I've added the feature that if you select an item, that item's index is returned (otherwise -1 is returned)

Share this post


Link to post
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
Sign in to follow this  
Followers 0