Variable inside variable?

Tagged: 

This topic contains 6 replies, has 3 voices, and was last updated by Profile photo of Troy Oosterwijk Troy Oosterwijk 1 year, 11 months ago.

  • Author
    Posts
  • #24906
    Profile photo of Troy Oosterwijk
    Troy Oosterwijk
    Participant

    Hi all,

    Please take a look at the following code I oh-so-cleverly cooked up:

    foreach [$GameFile in $GameFiles]
    $Counter = 1
    {
    $Button = "Button$Counter"
    $ButtonAction = $GameFile |%{$_.FullPath}
    $GameIcon = $GameFile |%{$_.IconLocation}
    $GameExe = $GameFile |%{$_.TargetPath}
    $Button = New-Object System.Windows.Forms.Button
    (some more things...)
    }
    $Counter++

    I'm trying to generate some buttons for every gamefile in my variable.
    Ofcourse I thought I could outsmart the system by creating a unique variable for the button every time by using a counter.
    This way I wouldn't have to make a button for every game by hand, instead I loop through the whole creation thing.

    Silly me though, that apparantly this will never work.
    Sure [b]$Button = "Button$Counter"[/b] gives me a nice [b]Button1[/b] output. But later on, oblivious of this error, I simply overwrite it with the Form Button creation part.

    So my question basicially:
    Is it possible to create some sort of variable in a variable? Letting it increase through a counter so it will work fine in a loop?

    Regards & forever in your variable debt,

    T.O.

    (by the way, is it possible your site has issue with Firefox? Can't seem to login properly, works fine with IE though)

  • #24908
    Profile photo of Daniel Krebs
    Daniel Krebs
    Participant

    Check out below. You want to store and keep track of the button objects you are creating.

    $Buttons = @{} # Hashtable to store your button objects
    $Counter = 1
    foreach ($GameFile in $GameFiles) {
    
        $ButtonName = "Button$Counter"
        $ButtonAction = $GameFile |%{$_.FullPath}
        $GameIcon = $GameFile |%{$_.IconLocation}
        $GameExe = $GameFile |%{$_.TargetPath}
    
        $Button = New-Object System.Windows.Forms.Button
        (some more things)
    
        $Buttons[$ButtonName] = $Button
    
        $Counter++
    }
    

    I hope above helps.

  • #24909
    Profile photo of Troy Oosterwijk
    Troy Oosterwijk
    Participant

    Thanks Daniel for you fast reply!

    I've tried your solution, but I'm getting this error:
    [i]Cannot index into a null array.[/i]

    What I'm aiming to achieve here, is to create several buttons like this:
    [i]$Button1 = New-Object System.Windows.Forms.Button
    *morebutton code stuff, which I actually got working*
    $Button2 = New-Object System.Windows.Forms.Button
    *morebutton code stuff, which I actually got working again*
    $Button3 = New-Object System.Windows.Forms.Button[/i]
    *morebutton code stuff, which I actually got working even again*

    My code gives me a nice looking form, with every button there is for the entries in the[b] foreach[/b] statement.
    But the problem is, I can't assign a personal click action, because the loop overwrites all the button statements.
    Does that make sense? Cause I think my head is hurting right now. . .

    T.O.

  • #24911
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    Anytime you're thinking of naming variables "$Button1", "$Button2", etc, it's a pretty good indication that what you really want is a collection of some sort. That way you can refer to them individually, if you want ($Buttons[0], $Buttons[1], etc), or you can use things like a foreach loop. In this case, your original code can be easily tweaked like this:

    $Buttons = @(
        foreach ($GameFile in $GameFiles)
        {
            $ButtonAction = $GameFile.FullPath
            $GameIcon = $GameFile.IconLocation
            $GameExe = $GameFile.TargetPath
            
            $Button = New-Object System.Windows.Forms.Button
            (some more things...)
    
            # This line is to make sure the button object is output from the foreach
            # loop, and winds up in the $Buttons collection that's being assigned.
            
            $Button
        }
    )
    
  • #24912
    Profile photo of Troy Oosterwijk
    Troy Oosterwijk
    Participant

    Thanks Dave for your reply!

    I've tried your suggestion, but still can't seem to make it work.
    I'm afraid I'm a bit of a slow learner.

    Let me take the liberty to place the entire code, so perhaps we can pinpoint what I'm doing wrong here:

    $Buttons = @(
    $DrawPoint = 12
    
    foreach ($GameFile in $GameFiles)
    {
    $ButtonAction = $GameFile |%{$_.FullPath}
    $GameIcon = $GameFile |%{$_.IconLocation}
    $GameExe = $GameFile |%{$_.TargetPath}
    
    $Button = New-Object System.Windows.Forms.Button
    $Button.Location = New-Object System.Drawing.Point[20, $DrawPoint]
    $Button.Size = New-Object System.Drawing.Size[32, 32]
    $Button.TabIndex = 0
    $Button.Text = ""
    $Button.UseVisualStyleBackColor = $true
    if [$GameIcon -notlike "*.ico"] {$Button.Image = [System.Drawing.Icon]::ExtractAssociatedIcon["$GameExe"]}
    else {$Button.Image = [System.Drawing.Image]::FromFile["$GameIcon"]}
    $Button.Add_Click[{Write-Host "$GameIcon is being started"}]
    # Write-Host "$GameIcon is being started"
    # pause
    $Button
    $Form1.Controls.Add[$Button]
    $DrawPoint = $DrawPoint + 36
    }
    ]
    

    As you can see, I wrote a check in there to see which action is being taken with the Write Host.
    When executing the whole script, inside the foreach loop I get the proper ButtonClick actions returned on screen, as they should.
    But ofcourse (and here is where it goes horribly wrong) out of the foreach loop, ONLY the last $Button.Add_Click is valid.
    So for each button I created, they now all share the same $Button.Add_Click value. Which kinda makes it useless because assigning individual actions doesn't seem possible this way.

    Thanks again for all your help and patience with this!

  • #24916
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    Most of your code looks fine to me. There are some square brackets where there should be parentheses, but I assume that's our forum software trying to be helpful.

    However, as you pointed out, your Click events are going to all output the same value. This is because the value of $GameIcon is evaluated when the click happens, not when you add the event handler. There are a few ways you could deal with this. Inside your event handler, you should have access to a variable called $this, which will refer to the Button object on which the event was fired. Depending on what your code is doing, you could use the $this variable to get the information you need from each button.

    Another option is to create a script block which evaluates the value of the $GameIcon variable at the time the script block is created. That would look something like this:

    $Button.Add_Click([scriptblock]::Create("Write-Host '$GameIcon is being started'"))
    

    When you do it that way, the value of $GameIcon is expanded inside the string, and that string (with the already-expanded value) is used to create a new ScriptBlock object.

  • #24924
    Profile photo of Troy Oosterwijk
    Troy Oosterwijk
    Participant

    And that did the trick! Thanks a million guys for your amazing help here.
    So if anyone here ever needs a script which pops up a form view with buttons to play old dos games, let me know.

    Thanks again and regards,

    T.O.

You must be logged in to reply to this topic.