Jump to content
Sign in to follow this  
blindwig

UDF: _ArrayBox()

Recommended Posts

blindwig

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
blindwig

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
blindwig

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
FuryCell

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
blindwig

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
blindwig

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
FuryCell

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
blindwig

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
Wus

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
blindwig

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  

×