はじめに
前回の記事では、PowerShellの標準コマンド Write-Progress
を使用してプログレスバーを表示する方法を紹介しました。今回は、Windows Formsを使用してより柔軟でカスタマイズ可能なプログレスバーを作成してみたいと思います。
標準のプログレスバーの制約
PowerShellの Write-Progress
コマンドは手軽に使える反面、以下のような制約があります:
- デザインのカスタマイズが困難
- 複数のプログレスバーを同時に表示するのが複雑
- 詳細な制御が難しい
Windows Formsを使用したカスタムプログレスバー
Windows Formsを使用することで、これらの制約を解決できます。
基本的な実装
Add-Type -AssemblyName System.Windows.Forms
# フォームの作成
$form = New-Object Windows.Forms.Form
$form.Text = "カスタムプログレスバー"
$form.Size = New-Object Drawing.Size(400, 100)
$form.StartPosition = "CenterScreen"
# プログレスバーの作成
$progressBar = New-Object Windows.Forms.ProgressBar
$progressBar.Minimum = 0
$progressBar.Maximum = 100
$progressBar.Value = 0
$progressBar.Dock = "Fill"
# フォームにプログレスバーを追加
$form.Controls.Add($progressBar)
$form.Show()
# プログレス処理のシミュレーション
for ($i = 1; $i -le 100; $i++) {
$progressBar.Value = $i
[System.Windows.Forms.Application]::DoEvents()
Start-Sleep -Milliseconds 50
}
$form.Close()
より詳細なカスタマイズ例
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
# フォームの詳細設定
$form = New-Object Windows.Forms.Form
$form.Text = "高度なプログレスバー"
$form.Size = New-Object Drawing.Size(500, 150)
$form.StartPosition = "CenterScreen"
$form.BackColor = [System.Drawing.Color]::LightGray
# ラベルの追加
$label = New-Object Windows.Forms.Label
$label.Text = "処理中..."
$label.Location = New-Object Drawing.Point(20, 20)
$label.Size = New-Object Drawing.Size(460, 30)
$label.Font = New-Object Drawing.Font("Arial", 12, [System.Drawing.FontStyle]::Bold)
$form.Controls.Add($label)
# プログレスバーの詳細設定
$progressBar = New-Object Windows.Forms.ProgressBar
$progressBar.Location = New-Object Drawing.Point(20, 60)
$progressBar.Size = New-Object Drawing.Size(460, 30)
$progressBar.Minimum = 0
$progressBar.Maximum = 100
$progressBar.Value = 0
$progressBar.Style = "Continuous"
$form.Controls.Add($progressBar)
# パーセンテージラベル
$percentLabel = New-Object Windows.Forms.Label
$percentLabel.Location = New-Object Drawing.Point(20, 95)
$percentLabel.Size = New-Object Drawing.Size(100, 20)
$percentLabel.Text = "0%"
$form.Controls.Add($percentLabel)
$form.Show()
# 処理のシミュレーション
for ($i = 1; $i -le 100; $i++) {
$progressBar.Value = $i
$percentLabel.Text = "$i%"
$label.Text = "処理中... ステップ $i/100"
[System.Windows.Forms.Application]::DoEvents()
Start-Sleep -Milliseconds 100
}
$label.Text = "完了!"
Start-Sleep -Seconds 2
$form.Close()
実際の処理での応用例
ファイル処理などの実際の作業でプログレスバーを使用する例:
function Show-FileProcessProgress {
param(
[string[]]$FilePaths
)
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
$form = New-Object Windows.Forms.Form
$form.Text = "ファイル処理進捗"
$form.Size = New-Object Drawing.Size(500, 200)
$form.StartPosition = "CenterScreen"
# 現在のファイル名表示
$fileLabel = New-Object Windows.Forms.Label
$fileLabel.Location = New-Object Drawing.Point(20, 20)
$fileLabel.Size = New-Object Drawing.Size(460, 30)
$fileLabel.Text = "準備中..."
$form.Controls.Add($fileLabel)
# プログレスバー
$progressBar = New-Object Windows.Forms.ProgressBar
$progressBar.Location = New-Object Drawing.Point(20, 60)
$progressBar.Size = New-Object Drawing.Size(460, 30)
$progressBar.Maximum = $FilePaths.Count
$progressBar.Value = 0
$form.Controls.Add($progressBar)
# 進捗情報
$infoLabel = New-Object Windows.Forms.Label
$infoLabel.Location = New-Object Drawing.Point(20, 100)
$infoLabel.Size = New-Object Drawing.Size(460, 60)
$infoLabel.Text = ""
$form.Controls.Add($infoLabel)
$form.Show()
for ($i = 0; $i -lt $FilePaths.Count; $i++) {
$currentFile = $FilePaths[$i]
$fileName = Split-Path $currentFile -Leaf
$fileLabel.Text = "処理中: $fileName"
$progressBar.Value = $i + 1
$infoLabel.Text = "進捗: $($i + 1)/$($FilePaths.Count) ファイル`n完了率: $([math]::Round((($i + 1) / $FilePaths.Count) * 100, 1))%"
[System.Windows.Forms.Application]::DoEvents()
# 実際のファイル処理をここに記述
# 例: Copy-Item, Move-Item, 等
Start-Sleep -Milliseconds 500 # 処理時間のシミュレーション
}
$fileLabel.Text = "処理完了!"
$infoLabel.Text = "すべてのファイルの処理が完了しました。"
Start-Sleep -Seconds 3
$form.Close()
}
# 使用例
# $files = Get-ChildItem "C:\temp\*.txt"
# Show-FileProcessProgress -FilePaths $files.FullName
複数プログレスバーの同時表示
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
$form = New-Object Windows.Forms.Form
$form.Text = "複数プログレスバー"
$form.Size = New-Object Drawing.Size(500, 300)
$form.StartPosition = "CenterScreen"
# 1つ目のプログレスバー
$label1 = New-Object Windows.Forms.Label
$label1.Text = "タスク1"
$label1.Location = New-Object Drawing.Point(20, 20)
$label1.Size = New-Object Drawing.Size(460, 20)
$form.Controls.Add($label1)
$progressBar1 = New-Object Windows.Forms.ProgressBar
$progressBar1.Location = New-Object Drawing.Point(20, 45)
$progressBar1.Size = New-Object Drawing.Size(460, 25)
$progressBar1.Maximum = 50
$form.Controls.Add($progressBar1)
# 2つ目のプログレスバー
$label2 = New-Object Windows.Forms.Label
$label2.Text = "タスク2"
$label2.Location = New-Object Drawing.Point(20, 90)
$label2.Size = New-Object Drawing.Size(460, 20)
$form.Controls.Add($label2)
$progressBar2 = New-Object Windows.Forms.ProgressBar
$progressBar2.Location = New-Object Drawing.Point(20, 115)
$progressBar2.Size = New-Object Drawing.Size(460, 25)
$progressBar2.Maximum = 75
$form.Controls.Add($progressBar2)
# 全体プログレスバー
$labelTotal = New-Object Windows.Forms.Label
$labelTotal.Text = "全体進捗"
$labelTotal.Location = New-Object Drawing.Point(20, 160)
$labelTotal.Size = New-Object Drawing.Size(460, 20)
$form.Controls.Add($labelTotal)
$progressBarTotal = New-Object Windows.Forms.ProgressBar
$progressBarTotal.Location = New-Object Drawing.Point(20, 185)
$progressBarTotal.Size = New-Object Drawing.Size(460, 25)
$progressBarTotal.Maximum = 125 # 50 + 75
$form.Controls.Add($progressBarTotal)
$form.Show()
# 並行処理のシミュレーション
$task1Complete = $false
$task2Complete = $false
while (-not ($task1Complete -and $task2Complete)) {
if (-not $task1Complete -and $progressBar1.Value -lt $progressBar1.Maximum) {
$progressBar1.Value++
$progressBarTotal.Value++
if ($progressBar1.Value -eq $progressBar1.Maximum) {
$task1Complete = $true
$label1.Text = "タスク1 - 完了"
}
}
if (-not $task2Complete -and $progressBar2.Value -lt $progressBar2.Maximum) {
$progressBar2.Value++
$progressBarTotal.Value++
if ($progressBar2.Value -eq $progressBar2.Maximum) {
$task2Complete = $true
$label2.Text = "タスク2 - 完了"
}
}
[System.Windows.Forms.Application]::DoEvents()
Start-Sleep -Milliseconds 100
}
$labelTotal.Text = "全体進捗 - 完了"
Start-Sleep -Seconds 2
$form.Close()
カスタムプログレスバーの利点
柔軟なデザインに対応
色やサイズ、表示位置を自由にカスタマイズできます。
詳細な情報の表示が可能
ラベルや補足情報などをあわせて表示することができます。
複数の進行状況を同時に管理
複数の処理を並行して監視・表示することができます。
ユーザーとのインタラクションに対応
ボタンなどのコントロール要素を追加して、操作性を高めることができます。
注意点
[System.Windows.Forms.Application]::DoEvents() を使用することで、UIの更新を確実に反映させることができます。
長時間の処理ではフォームが応答しなくなることがあるため、適切なタイミングでUIを更新する工夫が必要です。
また、エラーが発生した場合に備えて、適切なエラーハンドリングを実装しておくことも重要です。
まとめ
Windows Formsを使用することで、PowerShellでも本格的なプログレスバーを作成できます。標準の Write-Progress
では実現できない柔軟な表示や複雑な進捗管理が可能になり、ユーザーエクスペリエンスの向上に大きく貢献します。
長時間の処理を行うスクリプトでは、ぜひこのようなカスタムプログレスバーの実装を検討してみてください。
参考情報