在Powershell中在GUI窗口中创建一个进度条。

huangapple go评论81阅读模式
英文:

Create a progress bar in a GUI window in Powershell

问题

我使用下面显示在我的PowerShell脚本中显示进度条的代码。它能够工作,但进度条是显示在PowerShell 控制台中。

然而,我想要创建一个在单独的窗口中以GUI方式显示的进度条,就像这个视频中展示的一样:链接

有人可以提供一个示例吗?

这是我基于这个答案调整的基于控制台的进度条的代码:

Write-Progress -Activity $activity -PercentComplete 0

$totalMinutes = 0.15           # How long to display the progress bar for?
$timerIntervalSecs = 0.1      # The timer event triggering interval
$global:continueWhile = $true  # Global variable to continue or stop the loading bar
$timer = [System.Timers.Timer]::new($timerIntervalSecs * 1000)

$eventJob = Register-ObjectEvent -InputObject $timer -EventName Elapsed -Action {

  $endTime, $totalMinutes, $activity = $Event.MessageData.EndTime, $Event.MessageData.TotalMinutes, $Event.MessageData.Activity
  $timeLeft = $endTime - (Get-Date)
  $percent = (1 - $timeLeft.TotalSeconds / ($totalMinutes * 60)) * 100
  if ($timeLeft -lt 0) { $percent = 100; $timeLeft = [timespan] 0; $global:continueWhile = $false } # Once fully elapsed, set $continueWhile = $false
  Write-Progress -Activity $activity -Status "$([math]::Floor($percent))% complete, $([math]::Ceiling($timeLeft.TotalSeconds)) seconds remaining..." -PercentComplete $percent
} -MessageData (@{ EndTime = (Get-Date).AddMinutes($totalMinutes); TotalMinutes = $totalMinutes; Activity = $activity })

$timer.Start() # Start the timer.

try {
    Write-Output "test output"
    while ($continueWhile) {
        Start-Sleep -Seconds 0.5
    }

} finally {
   $timer.Stop()
   Remove-Job $eventJob -Force
   Write-Progress -Activity $activity -Completed
}
英文:

I use the code shown below to display a progress bar in my PowerShell script. It works, but it progress bar is displayed it in the PowerShell console.

However, I would like to create a GUI progress bar in a separate window when I click somewhere, as shown in this video: link.

Can someone help please with an example?

Here is the code of my console-based progress bar, adapted from this answer:

Write-Progress -Activity $activity -PercentComplete 0

$totalMinutes = 0.15           # Combien de temps faut-il afficher la barre de progression ?
$timerIntervalSecs = 0.1      # L'intervalle de déclenchement des événements de la minuterie 
$global:continueWhile = $true  # Variable globale qui permet de continuer ou d'arrêter la barre de chargement 
$timer = [System.Timers.Timer]::new($timerIntervalSecs * 1000) 

$eventJob = Register-ObjectEvent -InputObject $timer -EventName Elapsed -Action { 
    
  $endTime, $totalMinutes, $activity = $Event.MessageData.EndTime, $Event.MessageData.TotalMinutes, $Event.MessageData.Activity
  $timeLeft = $endTime - (Get-Date)
  $percent = (1 - $timeLeft.TotalSeconds / ($totalMinutes * 60)) * 100
  if ($timeLeft -lt 0) { $percent = 100; $timeLeft = [timespan] 0; $global:continueWhile = $false } # une fois entièrement écoulée, passe $continueWhile = $false
  Write-Progress -Activity $activity -Status "$([math]::Floor($percent))% complete, $([math]::Ceiling($timeLeft.TotalSeconds)) seconds remaining..." -PercentComplete $percent
} -MessageData (@{ EndTime = (Get-Date).AddMinutes($totalMinutes); TotalMinutes = $totalMinutes; Activity = $activity }) 

$timer.Start() # Démarre la minuterie.

try { 
    Write-Output "test output"
    while ($continueWhile) {
        Start-Sleep -Seconds 0.5
    }

} finally {
   $timer.Stop()
   Remove-Job $eventJob -Force
   Write-Progress -Activity $activity -Completed
}

答案1

得分: 2

这段代码描述了如何创建一个Windows窗体应用程序,其中包含一个进度条,用于显示操作的进度。以下是其中文翻译:

这是您基于控制台的进度条的GUI等效物,使用WinForms ProgressBar控件。

注意:
* 不再使用全局变量将值从事件脚本块传递给调用方,而是将条目添加到传递给-MessageData参数的哈希表中,该参数现在充当双向数据传输对象(DTO)。
* 窗体可以手动关闭,此时将向调用方传达已达到的百分比。
* 具有进度条的窗体将显示在最上层,即使切换到其他应用程序也会保持可见。如果不需要这样的行为,请删除TopMost = $true的哈希表条目。
* 您的方法有点不同寻常,因为您允许固定的时间驱动进度显示,而不是在主线程中执行实际任务。但是,您可以通过DTO报告实际进度,但请注意基本限制(同样适用于您的基于控制台的进度条):
  * 您可以在脚本的主要部分的while循环中执行的操作必须具有短的运行时间,因为定时器事件仅在命令之间触发。例如,如果循环中的命令运行2分钟,那么在此时间内将阻止更新进度条。

这部分是代码,无需翻译。

英文:

<!-- language-all: sh -->

Here's the GUI equivalent of your console-based progress bar, using the WinForms ProgressBar control.

Note:

  • Instead of using a global variable to communicate a value to the caller from the event script block, I've added entries to the hashtable that is passed to the -MessageData parameter, which now acts as a bidirectional DTO (data-transfer object).

  • The form can be closed manually, in which case the percentage reached is communicated to the caller.

  • The form with the progress bar will appear topmost, i.e. it will stay visible even if you switch to other applications. Remove the TopMost = $true hashtable entry, if that is undesired.

  • Your approach is somewhat unusual in that you're letting a fixed amount of time drive the progress display rather than an actual task being performed in the main thread. However, you could adapt it to report actual progress via the DTO instead, but note the fundamental limitation (which equally applies to your console-based progress bar):

    • The operation(s) you can perform in the while loop in the main part of your script - where Start-Sleep -Seconds 0.5 is currently used as a stand-in for such operations - must have a short runtime, because the timer event only fires between commands. For instance, if a command in that loop runs for 2 minutes, updates to the progress bar are blocked during that time.
Add-Type -AssemblyName System.Windows.Forms

# Parameters
$activity = &#39;Running...&#39;
$totalMinutes = 0.15      # How many minutes to run in total
$timerIntervalSecs = 0.1  # The timer-event firing interval
$timer = [System.Timers.Timer]::new($timerIntervalSecs * 1000) # create the timer

# A data-transfer object used for communicating with 
# the -Action script block below.
$dto = @{ 
  Activity = $activity
  EndTime = (Get-Date).AddMinutes($totalMinutes)
  TotalMinutes = $totalMinutes
  Done = $false # will be set to $true when the progress bar has reached 100% or the form was closed manually.
  AbortedAt = $null # if the form was closed manually, will be set to the percent-complete value at that time.
  Form = $null # will be filled in the -Action script block to store the form object between invocations.
}

# Register a script block as the delegate for the timer&#39;s &quot;Elapsed&quot; event
# (-Action parameter).
# The data-transfer object is passed via the -MessageData parameter.
$eventJob = Register-ObjectEvent -InputObject $timer -EventName Elapsed -Action { 
  $endTime, $totalMinutes, $activity, $form = $Event.MessageData.EndTime, $Event.MessageData.TotalMinutes, $Event.MessageData.Activity, $Event.MessageData.Form
  # Create the form on demand.
  if (-not $form) {
    $form = $Event.MessageData.Form = [System.Windows.Forms.Form] @{ TopMost = $true; Text = $activity; MinimizeBox = $false; MaximizeBox = $false; Width = 290; Height = 100; StartPosition = &#39;CenterScreen&#39; }
    $form.Controls.AddRange(@(
      [System.Windows.Forms.Label] @{ Name = &#39;lbl&#39;; Left = 10; Width = 250 }
      [System.Windows.Forms.ProgressBar] @{ Name = &#39;pb&#39;; Minimum = 0; Maximum = 100; Top = 30; Left = 10; Width = 250 }
    ))
    $form.Show()
  }
  # Calculate the progress... 
  $timeLeft = $endTime - (Get-Date)
  if ($timeLeft -lt 0) { $timeLeft = [timespan] 0 }
  $completed = $timeLeft -eq 0
  $percent = (1 - $timeLeft.TotalSeconds / ($totalMinutes * 60)) * 100
  # ... and update the status label and progress bar
  # Write-Progress -Activity $activity -Status &quot;$([math]::Floor($percent))% complete, $([math]::Ceiling($timeLeft.TotalSeconds)) seconds remaining...&quot; -PercentComplete $percent
  $form.Controls[&#39;lbl&#39;].Text = &quot;$([math]::Floor($percent))% complete, $([math]::Ceiling($timeLeft.TotalSeconds)) seconds remaining...&quot;
  $form.Controls[&#39;pb&#39;].Value = $percent 
  # NOTE: This is crucial to make the form paint and to to keep it responsive.
  #       If the timer interval is too long, the form will be sluggish to respond to attempts to move or close it.
  [System.Windows.Forms.Application]::DoEvents()
  # If the time has elapsed or the form has been closed, close the form (if it isn&#39;t already closed),
  # and signal that fact to the calling thread.
  if ($completed -or -not $form.Visible) { $Event.MessageData.AbortedAt = if (-not $form.Visible) { $percent }; $form.Dispose(); $Event.MessageData.Done = $true }
} -MessageData $dto

# Start the timer, which displays the form with the progress bar.
$timer.Start()

try { 
    &quot;Test output&quot;
    # Wait until the timer has elapsed or the form has been closed.
    while (-not $dto.Done) {
        Start-Sleep -Seconds 0.5
    }
    if ($dto.AbortedAt) {
      Write-Warning &quot;Progress-bar window as manually closed at $($dto.AbortedAt.ToString(&#39;N2&#39;))% complete.&quot;
    } else {
      &quot;Progress-bar window auto-closed on completion.&quot;
    }

} finally {
   # Clean up.
   $timer.Stop()
   Remove-Job $eventJob -Force
}

答案2

得分: 0

添加一个基于表单的进度条

    Add-Type -AssemblyName System.Windows.Forms
    
    $objForm = New-Object System.Windows.Forms.Form
    $objForm.Text = "测试"
    $objForm.Size = New-Object System.Drawing.Size(400,200)
    $objForm.FormBorderStyle = 'Fixed3D'
    $objForm.MaximizeBox = $false
    $objForm.MinimizeBox = $false
    $objForm.StartPosition = "CenterScreen"
    
    $amount = 1500
    
    $ProgressBar = New-Object System.Windows.Forms.ProgressBar
    $ProgressBar.Minimum = 0
    $ProgressBar.Maximum = $amount
    $ProgressBar.Location = New-Object System.Drawing.Size(10,80)
    $ProgressBar.Size = New-Object System.Drawing.Size(300,20)
    $objForm.Controls.Add($ProgressBar)
    $i = 1
    
    # 显示进度
    while ($i -le $amount) {
        $ProgressBar.Value = $i
        $i++
    }
    for ($i = 1; $i -le $amount; $i++) {}
    $objForm.ShowDialog() | Out-Null
    $objForm.Dispose()
英文:

Add a forms-based progress bar:

Add-Type -AssemblyName System.Windows.Forms

$objForm = New-Object System.Windows.Forms.Form
$objForm.Text = &quot;Test&quot;
$objForm.Size = New-Object System.Drawing.Size(400,200)
$objForm.FormBorderStyle = &#39;Fixed3D&#39;
$objForm.MaximizeBox = $false
$objForm.MinimizeBox = $false
$objForm.StartPosition = &quot;CenterScreen&quot;

$amount = 1500

$ProgressBar = New-Object System.Windows.Forms.ProgressBar
$ProgressBar.Minimum = 0
$ProgressBar.Maximum = $amount
$ProgressBar.Location = new-object System.Drawing.Size(10,80)
$ProgressBar.size = new-object System.Drawing.Size(300,20)
$objForm.Controls.Add($ProgressBar)
$i=1

#Display progress
while($i -le $amount){
$ProgressBar.Value = $i
$i++
}
for($i = 1; $i -le $amount;$i++){}
$objForm.ShowDialog() | Out-Null
$objForm.Dispose()

huangapple
  • 本文由 发表于 2023年3月15日 18:15:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/75743311.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定