locked
Form GUI Progress Bar Not Working Properly RRS feed

  • Question

  • I have an application that I have had to implement a progress bar into.  This is my first real attempt at doing so.  There are two phases when the application is running.  The first phase is downloading the application or applications that need to be installed.  The second phase is installing the downloaded application.

    The progress bar in the first phase is the one not working.  The progress bar in the second phase works, it just needs a little tweaking to have it properly represent the current actions.

    Form Build

    #region Build Form
    # Start Form Build
    Add-Type -AssemblyName System.Windows.Forms
    Add-Type -AssemblyName System.Drawing
    
    $icon = "C:\Program Files\Application\imgs\logo_icon.ico"
    $image = "C:\Program Files\Application\imgs\logo_b.jpg"
    
    # Form Layout Variables
    $form = New-Object system.Windows.Forms.Form
    $form.Text = "Application"
    $form.Icon = $icon
    
    $image = [system.drawing.image]::FromFile("$image")
    
    $form.BackColor = "White"
    $form.BackgroundImage = $image
    $form.BackgroundImageLayout = "none"
    
    $form.Width = 700
    $form.Height = 400
    $form.FormBorderStyle = "FixedDialog"
    
    $form.MinimizeBox = $false
    $form.MaximizeBox = $false
    $form.WindowState = "Normal"
    
    $form.StartPosition = "CenterScreen"
    
    # Buttons
    $installButton = New-Object System.Windows.Forms.Button
    
    # Progress Bar
    $pb = New-Object System.Windows.Forms.ProgressBar
    $pb.Name = "PowerShellProgressBar"
    $pb.Value = 0
    $pb.Style = "Continuous"
    
    $width = 500 - 40
    $height = 20
    $pb.Size = New-Object System.Drawing.Size($width, $height)
    $pb.Left = 110
    $pb.Top = 175
    
    # Install Button
    $installButton.Name = "installButton"
    $installButton.Text = "Install Updates"
    $installButton.Location = New-Object System.Drawing.Size(300, 200)
    $installButton.Width = 100
    $installButton.add_Click($install)
    
    # Progress Bar Text
    $pblabel = New-Object System.Windows.Forms.Label
    $pblabel.Left = 110
    $pblabel.Top = 150
    $pblabel.Width = 500 - 20
    $pblabel.Height = 15
    $pblabel.Font = "Tahoma"
    
    # Add Form Controls
    $form.Controls.Add($pblabel)
    $form.Controls.Add($pb)
    $form.Controls.Add($installButton)
    
    # Show Overall Form
    $form.ShowDialog()
    #endregion

    First Phase - Downloading

    This phase should have a marquee progress bar.  This was supposed to be easier than a continuous as sometimes multiple applications will be downloaded at one time. I didn't feel like writing the math that would make this work.

    #region Start Install
    $install = {
    	$installButton.Text = "Downloading"
    	$installButton.Enabled = $false
    	$installButton.Refresh()
    	
    	$pb.Style = "Marquee"
    	$pblabel.Text = "Downloading Updates"
    	$pblabel.Refresh()
    	$pb.Refresh()
    	
    	#region Get Installs to Download
    	$ftpfile = $ftpuri + "/" + $patch + "/" + $version + "/contents.txt"
            ...
            ...
            ...
            ...
            #region Download Installs	
    	foreach ($file in $files) {
    		$pb.Refresh()
    		$ftpfile = $ftpuri + "/" + $patch + "/" + $version + "/" + $file
    		$localfile = $tempdir + "\" + $file
    		"$(Get-TimeStamp) | Informa | Downloading $ftpfile" | Out-File -FilePath $logpath -Append -Encoding $encoding
            ...
            ...
            ...
            ...
            }
            $pb.Refresh()
    	Start-Sleep -Seconds 2
    # End First Phase

    The second phase - Installing

    This phase should have a continuous progress bar.  The progress bar is working as it should in the phase.  All I need to do is tweak it a little bit to better represent where the application is in the install process.

    #region Install Items $installButton.Text = "Installing Updates" $installButton.Enabled = $false $installButton.Refresh() $pb.Style = "Continuous" $pb.Refresh() $filecount = Get-ChildItem -Path $tempdir -File -Include *.exe, *.msi -Recurse -Force $counter = 0 foreach ($item in $installfiles) { $counter++ [Int]$percentage = ($counter/$filecount.Count) * 100 $pb.Value = $percentage $item = $item.Path $pblabel.Text = "Installing " + $item $pblabel.Refresh() $pb.Refresh() ... ... ... ... } #region Set Registry Properties $pblabel.Text = "Setting Registry Properties" $pblabel.Refresh() [Int]$percentage = 0 $pb.Value = $percentage $pb.Refresh() ... ... ... ... #region Install Complete $pblabel.Text = "Install Complete" $pblabel.Refresh() [Int]$percentage = 100 $pb.Value = $percentage $pb.Refresh() $installButton.Text = "Install Complete" $installButton.Enabled = $false $installButton.Refresh()

    ...

    ...

    ...

    ...

    } # This ends the $install = {


    Please, do not answer that I need a Powershell Form Creator software.  I have a particular style that I write with.  Any Form Creator software does not match this style.  All forms I have created, I have hand-crammed and will continue to do so.  You do not have to have any type of software to create a form.


    Wednesday, March 7, 2018 7:52 PM

All replies

  • Your arithmetic looks a bit odd.

    percent = (num/total) * 100

    If num is 1 and total is a very large number then percent will be ".nnn" which will not increment you pbar.

    (1/1000) * 100 = .1

    To get 1 percent we need:

    (10/1000) * 100


    \_(ツ)_/

    Wednesday, March 7, 2018 8:06 PM
  • As I showed you before you never  need "$installButton.Location = New-Object System.Drawing.Size(300, 200)"

    $installButton.Location = '300, 200'

    Never a need to add System.Drawing as it is loaded by the forms assembly.

    It is also a bad programming practice in PowerShell to use double quotes on everything. Use single quotes unless you specifically want expansion to occur.


    \_(ツ)_/


    • Edited by jrv Wednesday, March 7, 2018 8:11 PM
    Wednesday, March 7, 2018 8:10 PM
  • My numbers are always going to be on the small size.  The absolute max that will ever be installed is 5 applications.

    So let's say we are doing the max number, would this be correct?

    (1 / 5) * 100 = 20

    (2 / 5) * 100 = 40

    and so on.

    Wednesday, March 7, 2018 8:28 PM
  • Here is how to do this:

    $installButton_Click={
        $installButton.Enabled = $false
        $installfiles = Get-ChildItem -Path c:\Windows\* -File  -ea 0
        $pb.Maximum = $installfiles.Count
        $pb.Step = 1
        foreach ($item in $installfiles) {
        	$pblabel.Text = "Installing " + $item #set label at beginning
            # ... other code
        	$pb.PerformStep() # update elapsed at end of each processed file.
    } }

    There is no need for all of the refreshes and we don't need percent because the pbar does all of that math for you.

    There is also no need for a counter.  That is what the pbar is designed for.  It is a counter that can be decremented while the display is incremented.


    \_(ツ)_/



     
    • Edited by jrv Wednesday, March 7, 2018 8:33 PM
    Wednesday, March 7, 2018 8:31 PM
  • Oh, wait ... I see my issue.  Here lately the number of applications being installed is usually 1.  Which would automatically set me 100.  That explains the progress bar getting to 100% so quickly.
    Wednesday, March 7, 2018 8:31 PM
  • I went through and thought I had removed them all.  Seems like I didn't.  I'll do another check just to make sure.
    Wednesday, March 7, 2018 8:33 PM
  • Here is a complete working example. Copy and paste at a prompt:

    function Show-pbtest_psf {
    
    	#region Import the Assemblies
    	Add-Type -AssemblyName System.Windows.Forms
    	#endregion Import Assemblies
    
    	#region Generated Form Objects
    	[System.Windows.Forms.Application]::EnableVisualStyles()
    	$form1 = New-Object System.Windows.Forms.Form
    	$pblabel = New-Object System.Windows.Forms.Label
    	$installButton = New-Object System.Windows.Forms.Button
    	$pb = New-Object System.Windows.Forms.ProgressBar
    	$buttonOK = New-Object System.Windows.Forms.Button
    	$InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
    	#endregion Generated Form Objects
    
    	# User Generated Script	
    	$installButton_Click={
    	    $installButton.Enabled = $false
    	    $installfiles = Get-ChildItem -Path c:\Windows\* -File  -ea 0
    	    $pb.Maximum = $installfiles.Count
    	    $pb.Step = 1
    	    foreach ($item in $installfiles) {
    	    	$pb.PerformStep()
    	    	$pblabel.Text = "Installing " + $item.Fullname
                [System.Windows.Forms.Application]::DoEvents()
                sleep -Milliseconds 250
    	        # ... other code
    	    }
    	    $installButton.Enabled = $true
    	}
    	
    	$Form_StateCorrection_Load = {
    		#Correct the initial state of the form to prevent the .Net maximized form issue
    		$form1.WindowState = $InitialFormWindowState
    	}
    	
    	$Form_Cleanup_FormClosed = {
    		#Remove all event handlers from the controls
    		try
    		{
    			$installButton.remove_Click($installButton_Click)
    			$form1.remove_Load($Form_StateCorrection_Load)
    			$form1.remove_FormClosed($Form_Cleanup_FormClosed)
    		}
    		catch { Out-Null <# Prevent PSScriptAnalyzer warning #> }
    	}
    	#endregion Generated Events
    
    	#region Generated Form Code
    	$form1.SuspendLayout()
    
        # form1
    	$form1.Controls.Add($pblabel)
    	$form1.Controls.Add($installButton)
    	$form1.Controls.Add($pb)
    	$form1.Controls.Add($buttonOK)
    	$form1.AcceptButton = $buttonOK
    	$form1.AutoScaleDimensions = '8, 17'
    	$form1.AutoScaleMode = 'Font'
    	$form1.ClientSize = '379, 343'
    	$form1.FormBorderStyle = 'FixedDialog'
    	$form1.Margin = '5, 5, 5, 5'
    	$form1.MaximizeBox = $False
    	$form1.MinimizeBox = $False
    	$form1.Name = 'form1'
    	$form1.StartPosition = 'CenterScreen'
    	$form1.Text = 'Form'
    	
    	# pblabel
    	$pblabel.AutoSize = $True
    	$pblabel.Location = '30, 9'
    	$pblabel.Margin = '4, 0, 4, 0'
    	$pblabel.Name = 'pblabel'
    	$pblabel.Size = '51, 21'
    	$pblabel.TabIndex = 3
    	$pblabel.Text = 'pblabel'
    	$pblabel.TextAlign = 'BottomRight'
    	$pblabel.UseCompatibleTextRendering = $True
    	
    	# installButton
    	$installButton.Location = '73, 103'
    	$installButton.Margin = '4, 4, 4, 4'
    	$installButton.Name = 'installButton'
    	$installButton.Size = '100, 30'
    	$installButton.TabIndex = 2
    	$installButton.Text = 'button1'
    	$installButton.UseCompatibleTextRendering = $True
    	$installButton.UseVisualStyleBackColor = $True
    	$installButton.add_Click($installButton_Click)
    	
    	# pb
    	$pb.Location = '30, 42'
    	$pb.Margin = '4, 4, 4, 4'
    	$pb.Name = 'pb'
    	$pb.Size = '333, 30'
        $pb.Style = 'Continuous'
    	
    	# buttonOK
    	$buttonOK.Anchor = 'Bottom, Right'
    	$buttonOK.DialogResult = 'OK'
    	$buttonOK.Location = '263, 297'
    	$buttonOK.Margin = '4, 4, 4, 4'
    	$buttonOK.Name = 'buttonOK'
    	$buttonOK.Size = '100, 30'
    	$buttonOK.TabIndex = 0
    	$buttonOK.Text = '&OK'
    	$buttonOK.UseCompatibleTextRendering = $True
    	$buttonOK.UseVisualStyleBackColor = $True
    	$form1.ResumeLayout()
    	#endregion Generated Form Code
    
    	#Save the initial state of the form
    	$InitialFormWindowState = $form1.WindowState
    	#Init the OnLoad event to correct the initial state of the form
    	$form1.add_Load($Form_StateCorrection_Load)
    	#Clean up the control events
    	$form1.add_FormClosed($Form_Cleanup_FormClosed)
    	#Show the Form
    	return $form1.ShowDialog()
    
    } #End Function
    
    Show-pbtest_psf 
    



    \_(ツ)_/


    • Edited by jrv Wednesday, March 7, 2018 8:45 PM
    Wednesday, March 7, 2018 8:42 PM
  • I updated the last code post because I forgot one line.

    Be sure you have the updated version.


    \_(ツ)_/

    Wednesday, March 7, 2018 8:45 PM
  • I will try that.  I will let you know the results tomorrow.  I have remote support calls starting in 10 minutes and through the end of the day.
    Wednesday, March 7, 2018 8:51 PM