none
Powershell form - procedurally creating buttons? RRS feed

  • Question

  • Hi all,

    Can anyone give me a pointer on where I'm going wrong with this? I'm rewriting a powershell form which has a panel full of buttons in. I thought in the new version I'd be a bit smarter about the buttons, rather than copy-pasting the code for creating the button, and changing the name, location, etc, I wanted to do it procedurally.

    By this I mean, I have an array of button names. I loop through these with a while that uses a loop counter. I use the loop counter to work out the position of the button - rounding it and multiplying by various offsets. I use the loop counter to index the array of button names and get what this button is supposed to be called. Then I put in an add_click, which tells the button to call a function, supplying the name of the button.

    So what I hope for is an easy, quick and scalable way to take a simple list of button names and generate the buttons from it. So far so good, apart from one problem: the buttons work and appear as expected, but they all share the same click function! When it's called, it just performs the function of the last button to be added.

    I tried adding a clear-variable for the temporary button object used in each loop iteration, but that didn't help.

    Thanks for reading

    Aled


    • Edited by Aled_L Friday, March 14, 2014 4:21 PM
    Friday, March 14, 2014 4:20 PM

Answers

  • If you point all of them at the same function they will all have the same code.

    $thisbutton.Add_Click({
    do_function $thisbuttonname
    })

    Don't use a function.

    $this is the current control.  NOT $thisbuttonname.

    Try this:

    $thisbutton.Add_Click({
         do_function $this.Name
     
    })



    ¯\_(ツ)_/¯

    • Marked as answer by Aled_L Tuesday, March 18, 2014 4:19 PM
    Monday, March 17, 2014 3:58 PM

All replies

  • Here's my code:

    $buttons_functionslist=@( "Func1", "Func2", "Func3" ) $buttons_functionbuttoncount = $buttons_functionslist.count $loop = 0 while($loop -lt $buttons_functionbuttoncount) { $thisbutton = New-Object System.Windows.Forms.Button [string]$thisbuttonname = $buttons_functionslist[$loop] $thisbutton.Text = $thisbuttonname $thisbutton.size = New-Object System.Drawing.Size($buttons_width,$buttons_height) ## Code that sets xloc and yloc removed for brevity $thisbutton.Location = New-Object System.Drawing.Size($thisbutton_xloc,$thisbutton_yloc) $thisbutton.Add_Click({ do_function $thisbuttonname })

    $functionspanel.Controls.Add($thisbutton)

    $loop += 1 }

    And then of course I have a function do_function which accepts the name of the function to perform.

    
    
    
    • Edited by Aled_L Friday, March 14, 2014 4:36 PM
    Friday, March 14, 2014 4:35 PM
  • Place a FlowPanel on your form and set its behaviors.  After that just generate buttons. They will auto locate themselves.  I place a default button then the loop just copies the properties to a new button.  The flow panel automatically positions them according to the flow rules.

    http://msdn.microsoft.com/en-us/library/system.windows.forms.flowlayoutpanel(v=vs.110).aspx


    ¯\_(ツ)_/¯

    Friday, March 14, 2014 8:11 PM
  • Hi JRV,

    Thanks for the helpful reply, as ever. FlowLayoutPanel looks like a really neat object to use. I can't find any good examples from a powershell point of view. Can you give me any more pointers about defining the default controls?

    I've added a FlowLayoutPanel in to my form, in place of the old panel. It's allowed me to add the button controls without specifying their locations, and has added them automatically, which is very handy. However, I still have the same problem that without creating a distinct, named object for each button, I can't seem to give them their own click methods - all of the buttons seem to just use the click method from the last button created.

    It's a bit counterintuitive really because my understanding is that variables created within loops in powershell are scoped to only survive for that loop iteration, but this behaviour indicates otherwise.

    Thanks

    Aled

    Monday, March 17, 2014 2:36 PM
  • If you point all of them at the same function they will all have the same code.

    $thisbutton.Add_Click({
    do_function $thisbuttonname
    })

    Don't use a function.

    $this is the current control.  NOT $thisbuttonname.

    Try this:

    $thisbutton.Add_Click({
         do_function $this.Name
     
    })



    ¯\_(ツ)_/¯

    • Marked as answer by Aled_L Tuesday, March 18, 2014 4:19 PM
    Monday, March 17, 2014 3:58 PM
  • Hi JRV,

    Thanks very much! That's done the trick. I had assumed that $thisbutton was being created and destroyed by each iteration of the loop, but it doesn't seem that's the case.

    Using $this works just fine though. I don't define Name for the button object yet, so just using $this.text works now.

    Again, thanks.

    Aled

    Tuesday, March 18, 2014 4:18 PM
  • Hi, hoping you can help. I've run into the same issue with this piece of code (pretty similar to the OP),

    and I've now drawn a mental blank:

    ------

    # Drop the respective site buttons onto the form using a loop.

    $i=0

    while($i -lt $count1)
     {
      #Label each button with site name.
      $Text = $sites[$i] | ForEach {$_.Name}
     
      $SiteButton = New-Object System.Windows.Forms.Button
      $SiteButton.Location = New-Object System.Drawing.Size(15,$yloc)
      $SiteButton.Size = New-Object System.Drawing.Size(100,23)
      $SiteButton.Text = $Text
      $SiteButton.Add_Click({$outputBox.Text=$SiteButton.Text})
      $objForm.Controls.Add($SiteButton)
      $i+=1
      $yloc=$yloc+$yloc_incr
     }

    I click on any of the buttons that are created (with the right array names), but

    it returns the name of the very last button each time into the outputbox. I've tried

    a number of things without success to return the name of the actual button.

    Ultimately I'd like to call a function also, but my function even returns the last button's text.


    • Edited by shades4321 Tuesday, June 16, 2015 8:57 AM
    Tuesday, June 16, 2015 8:56 AM
  • Please start you own topic.  This one has been closed for over a year.   You can post a link to this thread if it is needed.

    \_(ツ)_/

    Tuesday, June 16, 2015 9:40 AM