3

Having spent about 8hrs trying different configurations, I've run out of ideas. (I think it's to do with the "single thread" nature of the Powershell; in PERL you could do a 'fork' which may solve the problem)

In short, the user clicks "Start" This executes an external program that takes about 20 seconds to run, (represented by the "do" loop at the top) At this point, the GUI appears 'frozen' ... so I decided to add a progress bar. But of course, whilst it's processing the "do" loop / external program, the "main" program is halted until the former terminates, (which is defeating the whole object)

I even tried a second 'form', placing the progress bar in that, and running it via "Show" (as apparently, that should run as in background as it doesn't accept user interaction ... except it still 'freezes' progressbar)

I thought about using an animation aka the busy pointer ... but seems you can't included GIF animations without even more problems!

Maybe it involves "background jobs" ... but that left me even more confused!

This is the premise:

Press Start button Change label to "Processing" / remove start button --> Calls dialogues (within function) to locate a file / location to save / Program runs silently for 15 - 30 seconds whilst showing marquee progressbar (or animation) Change label to "Complete" Display "OK" button to terminate

NB: I found I had to include the ProgressBar within the function as adding it via AddRange, and then setting it to "Visible" within function meant it didn't show at all

Add-Type -AssemblyName PresentationFramework
Add-Type -AssemblyName System.Drawing
[System.Windows.Forms.Application]::EnableVisualStyles()

function Extract(){
$ProgressBar              = New-Object System.Windows.Forms.ProgressBar
$ProgressBar.Location     = New-Object System.Drawing.Point(10,35)
$ProgressBar.Size         = New-Object System.Drawing.Size(460,40)
$ProgressBar.Style        = "Marquee"
$ProgressBar.MarqueeAnimationSpeed = 20
$main_form.Controls.Add($ProgressBar);

$Label.Font             = $procFont
$Label.ForeColor        ='red'
$Label.Text             ="Processing ..."
$ProgressBar.visible

$a=0;
    do{
    start-sleep(1)
    write-host $a
    $a++
    }while($a -lt 10)
$Label.Text               = "Process Complete"
$ProgressBar.Hide()
$StartButton.Hide()
$EndButton.Visible
}

$main_form                = New-Object System.Windows.Forms.Form
$main_form.Text           ='Subtitle Software Suite'
$main_form.BackColor      ='cyan'
$main_form.Width          = 520
$main_form.Height         = 180

$header                   = New-Object System.Drawing.Font("Verdana",13,[System.Drawing.FontStyle]([System.Drawing.FontStyle]::Bold))
$procFont                 = New-Object System.Drawing.Font("Verdana",20,[System.Drawing.FontStyle]([System.Drawing.FontStyle]::Bold))

$Label                    = New-Object System.Windows.Forms.Label
$Label.Font               = $header
$Label.ForeColor          ='blue'
$Label.Text               = "Audio extraction can take a long time"
$Label.Location           = New-Object System.Drawing.Point(10,10)
$Label.Width              = 480
$Label.Height             = 50

$StartButton              = New-Object System.Windows.Forms.Button
$StartButton.Location     = New-Object System.Drawing.Size(350,75)
$StartButton.Size         = New-Object System.Drawing.Size(120,50)
$StartButton.Text         = "Start"
$StartButton.height       = 40
$StartButton.BackColor    ='red'
$StartButton.ForeColor    ='white'
$StartButton.Add_click({EXTRACT});

$EndButton              = New-Object System.Windows.Forms.Button
$EndButton.Location     = New-Object System.Drawing.Size(350,75)
$EndButton.Size         = New-Object System.Drawing.Size(120,50)
$EndButton.Text         = "OK"
$EndButton.height       = 40
$EndButton.BackColor    ='red'
$EndButton.ForeColor    ='white'
$EndButton.DialogResult = [System.Windows.Forms.DialogResult]::OK

$main_form.Controls.AddRange(($Label,$StartButton,$EndButton))

$main_form.StartPosition = "manual"
$main_form.Location = New-Object System.Drawing.Size(500, 300)
$result=$main_form.ShowDialog() 

if ($result -eq [System.Windows.Forms.DialogResult]::OK){
$main_form.Close()
}

1 Answer 1

2

Here is an example of using a Job that takes 20 seconds to complete. Its uses DoEvents() to prevent the GUI freezing which is not without issues but might be OK for your needs.

Add-Type -AssemblyName PresentationFramework
Add-Type -AssemblyName System.Drawing
[System.Windows.Forms.Application]::EnableVisualStyles()

$jobScript =
{
    Start-Sleep -Seconds 20
}


function Extract() {
    $ProgressBar = New-Object System.Windows.Forms.ProgressBar
    $ProgressBar.Location = New-Object System.Drawing.Point(10, 35)
    $ProgressBar.Size = New-Object System.Drawing.Size(460, 40)
    $ProgressBar.Style = "Marquee"
    $ProgressBar.MarqueeAnimationSpeed = 20

    $main_form.Controls.Add($ProgressBar);

    $Label.Font = $procFont
    $Label.ForeColor = 'red'
    $Label.Text = "Processing ..."
    $ProgressBar.visible

    $job = Start-Job -ScriptBlock $jobScript
    do { [System.Windows.Forms.Application]::DoEvents() } until ($job.State -eq "Completed")
    Remove-Job -Job $job -Force


    $Label.Text = "Process Complete"
    $ProgressBar.Hide()
    $StartButton.Hide()
    $EndButton.Visible
}

$main_form = New-Object System.Windows.Forms.Form
$main_form.Text = 'Subtitle Software Suite'
$main_form.BackColor = 'cyan'
$main_form.Width = 520
$main_form.Height = 180

$header = New-Object System.Drawing.Font("Verdana", 13, [System.Drawing.FontStyle]([System.Drawing.FontStyle]::Bold))
$procFont = New-Object System.Drawing.Font("Verdana", 20, [System.Drawing.FontStyle]([System.Drawing.FontStyle]::Bold))

$Label = New-Object System.Windows.Forms.Label
$Label.Font = $header
$Label.ForeColor = 'blue'
$Label.Text = "Audio extraction can take a long time"
$Label.Location = New-Object System.Drawing.Point(10, 10)
$Label.Width = 480
$Label.Height = 50

$StartButton = New-Object System.Windows.Forms.Button
$StartButton.Location = New-Object System.Drawing.Size(350, 75)
$StartButton.Size = New-Object System.Drawing.Size(120, 50)
$StartButton.Text = "Start"
$StartButton.height = 40
$StartButton.BackColor = 'red'
$StartButton.ForeColor = 'white'
$StartButton.Add_click( { EXTRACT });

$EndButton = New-Object System.Windows.Forms.Button
$EndButton.Location = New-Object System.Drawing.Size(350, 75)
$EndButton.Size = New-Object System.Drawing.Size(120, 50)
$EndButton.Text = "OK"
$EndButton.height = 40
$EndButton.BackColor = 'red'
$EndButton.ForeColor = 'white'
$EndButton.DialogResult = [System.Windows.Forms.DialogResult]::OK

$main_form.Controls.AddRange(($Label, $StartButton, $EndButton))

$main_form.StartPosition = "manual"
$main_form.Location = New-Object System.Drawing.Size(500, 300)
$result = $main_form.ShowDialog()

if ($result -eq [System.Windows.Forms.DialogResult]::OK) {
    $main_form.Close()
}
3
  • Thanks for this. Will 'analyse' it in the ISE to see what it's doing. I'd have thought it should be simple to do, and did find "DoEvents", but again, it didn't make a lot of sense. Commented Jul 11, 2020 at 7:59
  • Hmm ... not just DoEvents, but Start-Job and a couple of other flags to research! Commented Jul 11, 2020 at 8:02
  • @ChrisBrown If you've not seen it poshgui.com can he helpful when creating GUIs in PowerShell.
    – jfrmilner
    Commented Jul 11, 2020 at 10:50

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .