【PowerShellでGUI 7】DataGridView 応用編2 画像表示列
前回に引き続き、、PowerShellで作成するWindwos Formアプリの部品データグリッドビューの応用編で、今回はデータグリッドビューの中に
・画像を表示する列
を設定する方法です。
DataGridViewImageColumn
今回のサンプルアプリの画面イメージはこちら。
今回も、前々回作成した簡易なエクスプローラーライクなものをベースにしています。

そして上記画面のソースコードがこちら
using namespace System.Windows.Forms Add-Type -AssemblyName System.Windows.Forms Add-Type -AssemblyName System.Drawing [Application]::EnableVisualStyles() # フォーム $frame = New-Object Form -Property @{ Text = 'Sample App' Size = New-Object Drawing.Size(650, 600) MaximizeBox = $false FormBorderStyle = 'FixedDialog' Font = New-Object Drawing.Font('Meiryo UI', 8.5) } # 表示対象フォルダー設定用テキストボックス $tbxFolder = New-Object TextBox -Property @{ Location = New-Object Drawing.Point(20, 20) Width = 400 ReadOnly = $True } $frame.Controls.Add($tbxFolder) # フォルダー選択ダイアログ表示ボタン $btnRef = New-Object Button -Property @{ Location = New-Object Drawing.Point(425, 20) Text = '...' Width = 30 } $frame.Controls.Add($btnRef) $fbdRef = New-Object FolderBrowserDialog -Property @{ ShowNewFolderButton = $false } # データグリッドビュー $DataGridV = New-Object DataGridView -Property @{ Location = New-Object Drawing.Point(20, 50) Size = New-Object Drawing.Size(600, 500) AutoSizeColumnsMode = "AllCells" ReadOnly = $True AllowUserToAddRows = $false ColumnCount = 3 RowHeadersVisible = $false MultiSelect = $false SelectionMode = 'FullRowSelect' } $DataGridV.ColumnHeadersDefaultCellStyle.Alignment = 'MiddleCenter' $DataGridV.RowTemplate.Height = 150 # 各列の情報設定 $DataGridV.Columns[0].Name = "名前" $DataGridV.Columns[1].Name = "更新日時" $DataGridV.Columns[1].DefaultCellStyle.Format = 'yyyy/MM/dd HH:mm:ss' $DataGridV.Columns[2].Name = "サイズ" $DataGridV.Columns[2].DefaultCellStyle.Format = '#,##0 KB' $DataGridV.Columns[2].DefaultCellStyle.Alignment = 'MiddleRight' # 画像イメージ列 $colImage = New-Object DataGridViewImageColumn -Property @{ Name = "Image" ImageLayout = 'Zoom' Width = 250 AutoSizeMode = 'Fill' } $colImage.DefaultCellStyle.NullValue = $null $colImage.DefaultCellStyle.Padding = New-Object Padding(3) $colImage.DefaultCellStyle.Alignment = 'MiddleCenter' [void]$DataGridV.Columns.Add($colImage) # 表示可能な画像形式の拡張子一覧を配列に格納 $ImageExts = @() foreach ($exts in ([System.Drawing.Imaging.ImageCodecInfo]::GetImageDecoders()).FilenameExtension){ $ImageExts += ($exts.Replace('*','') -split ';') } # DataGridViewに値を設定する処理 $scrbSetGrid = { $DataGridV.Rows.Clear() $files = (Get-ChildItem $tbxFolder.Text | Where-Object { $_.Extension -in $ImageExts }) foreach ($fi in $files){ switch ($fi.Length) { {$_ -lt 1024} { $size = 1 } Default {$size = ($_ / 1024)} } # 画像の回転情報を取得 $bmporg = New-Object System.Drawing.Bitmap($fi.FullName) $rpi = ($bmporg.PropertyItems | Where-Object { $_.ID -eq 0x0112 }) $rft = [System.Drawing.RotateFlipType]::RotateNoneFlipNone if (($rpi | Measure-Object).Count -gt 0){ switch ($rpi.Value[0]) { 3 { $rft = [System.Drawing.RotateFlipType]::Rotate180FlipNone } 6 { $rft = [System.Drawing.RotateFlipType]::Rotate90FlipNone } 8 { $rft = [System.Drawing.RotateFlipType]::Rotate270FlipNone } } } $bmporg.Dispose() # 開いたセッションを残さないために、FileStreamで読み込んで最後にClose $fs = New-Object System.IO.FileStream($fi.FullName, 'Open', 'Read') $bmpclone = New-Object System.Drawing.Bitmap($fs) $bmpclone.RotateFlip($rft) $fs.Close() $DataGridV.Rows.Add($fi.Name, $fi.LastWriteTime, $size, $bmpclone) } } $btnRef.Add_Click({ if ($fbdRef.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK){ $tbxFolder.Text = $fbdRef.SelectedPath . $scrbSetGrid } }) # ダブルクリック時の処理 $DataGridV.Add_CellDoubleClick({ if ($_.RowIndex -ge 0){ Start-Process -FilePath (Join-Path $tbxFolder.Text $DataGridV.Rows[$_.RowIndex].Cells[0].Value) } }) $frame.Controls.Add($DataGridV) $frame.ShowDialog()
解説
60~69行目が画像を表示する列の定義をしている部分になります。
$colImage = New-Object DataGridViewImageColumn -Property @{ Name = "Image" ImageLayout = 'Zoom' Width = 250 AutoSizeMode = 'Fill' } $colImage.DefaultCellStyle.NullValue = $null $colImage.DefaultCellStyle.Padding = New-Object Padding(3) $colImage.DefaultCellStyle.Alignment = 'MiddleCenter' [void]$DataGridV.Columns.Add($colImage)
列のオブジェクトをDataGridViewImageColumnクラスとして定義し、定義したオブジェクトをデータグリッドビューに追加するという流れになります。
設定しているプロパティについて、特徴的なものを以下に記載しておきます。
ImageLayout | 画像の表示の仕方の設定で、既定値(Nomal)だと等倍表示されてしまうため、セルの大きさに合わせて自動的に拡大/縮小されて表示されるようにZoomを設定しています。 |
AutoSizeMode | 列幅について、他のセルの幅は表示内容によって自動調整ように、DataGridViewのプロパティで設定していますが、画像表示をする列幅は、DataGridViewの幅いっぱいいっぱいを使って表示できるように、Fillで設定しています。 |
DefaultCellStyle.Padding | 画像を表示したときに、上下のセルとの間に多少は余白が欲しかったので、設定しています。 |
72~75行目では、DataGridViewImageColumnに表示可能なフォーマット(拡張子)の一覧を取得しています。
GetImageDecodersでは、FilenameExtensionが
*.BMP;*.DIB;*.RLE *.JPG;*.JPEG;*.JPE;*.JFIF *.GIF *.EMF *.WMF *.TIF;*.TIFF *.PNG *.ICO
といった形式で取得されてきますが、 Get-ChildItem の結果の Extension の項目に対して、-in 演算子で絞り込みを行いたいので、取得結果から’*’は削除(Replace('*','')
)し、’;’で配列に分割(-split ';'
)したものを配列に格納しています。
86行目~102行目がグリッドビューに画像を表示させるための処理になってて、まずは前半の86~96行目が、EXIFのOrientationタグの情報を取得し、後半でRotateFlipにより画像を回転させるための設定値を設定している部分です。
$bmporg = New-Object System.Drawing.Bitmap($fi.FullName) $rpi = ($bmporg.PropertyItems | Where-Object { $_.ID -eq 0x0112 }) $rft = [System.Drawing.RotateFlipType]::RotateNoneFlipNone if (($rpi | Measure-Object).Count -gt 0){ switch ($rpi.Value[0]) { 3 { $rft = [System.Drawing.RotateFlipType]::Rotate180FlipNone } 6 { $rft = [System.Drawing.RotateFlipType]::Rotate90FlipNone } 8 { $rft = [System.Drawing.RotateFlipType]::Rotate270FlipNone } } } $bmporg.Dispose()
後半の99行目~102行目がDataGridViewImageColumnに表示する画像を設定している部分になります。
$fs = New-Object System.IO.FileStream($fi.FullName, 'Open', 'Read') $bmpclone = New-Object System.Drawing.Bitmap($fs) $bmpclone.RotateFlip($rft) $fs.Close()
DataGridViewImageColumnに紐づけるSystem.Drawing.Bitmapオブジェクトの定義の仕方の部分がポイントです。
前半と同じようにファイル名を指定してSystem.Drawing.Bitmapオブジェクトを定義すると、Disposeで破棄するまで、対象の画像ファイルをロックしてしまうのですが、System.Drawing.BitmapオブジェクトをDisposeしてしまうと、データグリッドビューで画像が表示できなくなってしまいます。
そこで、画像ファイルを一旦FileStreamに読み込んで、読み込んだFileStreamを使ってSystem.Drawing.Bitmapオブジェクトを定義し、その後、FileStreamはCloseすることで、画像ファイルへのロックが残らずにデータグリッドビューに画像が表示されることになります。
今回はここまで。
次回何を記載しようかはちょっと悩み中です。。。
以上、参考になれば幸いです。