2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

image.png

前回の記事では、PowerShellの標準コマンド Write-Progress を使用してプログレスバーを表示する方法を紹介しました。今回は、Windows Formsを使用してより柔軟でカスタマイズ可能なプログレスバーを作成してみたいと思います。

標準のプログレスバーの制約

PowerShellの Write-Progress コマンドは手軽に使える反面、以下のような制約があります:

  • デザインのカスタマイズが困難
  • 複数のプログレスバーを同時に表示するのが複雑
  • 詳細な制御が難しい

Windows Formsを使用したカスタムプログレスバー

image.png

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()

image.png

より詳細なカスタマイズ例

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()

image.png

実際の処理での応用例

ファイル処理などの実際の作業でプログレスバーを使用する例:

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

image.png

複数プログレスバーの同時表示

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()

image.png

カスタムプログレスバーの利点

柔軟なデザインに対応
 色やサイズ、表示位置を自由にカスタマイズできます。

詳細な情報の表示が可能
 ラベルや補足情報などをあわせて表示することができます。

複数の進行状況を同時に管理
 複数の処理を並行して監視・表示することができます。

ユーザーとのインタラクションに対応
 ボタンなどのコントロール要素を追加して、操作性を高めることができます。

注意点

[System.Windows.Forms.Application]::DoEvents() を使用することで、UIの更新を確実に反映させることができます。

長時間の処理ではフォームが応答しなくなることがあるため、適切なタイミングでUIを更新する工夫が必要です。

また、エラーが発生した場合に備えて、適切なエラーハンドリングを実装しておくことも重要です。

まとめ

image.png

Windows Formsを使用することで、PowerShellでも本格的なプログレスバーを作成できます。標準の Write-Progress では実現できない柔軟な表示や複雑な進捗管理が可能になり、ユーザーエクスペリエンスの向上に大きく貢献します。

長時間の処理を行うスクリプトでは、ぜひこのようなカスタムプログレスバーの実装を検討してみてください。

参考情報

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?