イメージビューワー(2)

VB SampleImageViewer 2 : Thumbnail
 画像ビューワーの2回目です。今回は、メインフォームのパネルに表示するサムネール・クラスを作成します。
 このクラスはユーザーコントロールを利用してつくられています。右図のように、上側に縮小画像、下側にファイル名を表示します。また、画像上にマウスポインタを移動させると、ツールチップが画像のファイル名、元のサイズ、バイト容量を表示するようにします。
 さらに最後に、このクラスを使ってメインフォームに画像を一覧表示します。
【INDEX】
Page 1 [本編] プロジェクトの概観 / メインフォームの設計 / フォルダツリーの作成
»Page2 [本編] サムネールの設計 / サムネールの作成 / 画像サイズの設定 / 画像一覧の表示
Page 3 [本編] サブフォームの設計 / 元画像の表示 / 画像の拡大・縮小 / 画像の回転・反転
Page 4 [拡張編] 画像の保存 / 画像への枠入れ・文字入れ / 画像のトリミング
Page 5 [番外編] スライドショー / マニュアル・スライド / フィットモード / オート・スライド
(作成環境 : Visual Basic .net 2002 / Framework SDK 1.0)

●サムネールの設計
 サムネールクラスは、メインフォームにサムネールを提供します。このクラスは、縮小画像を表示する部分とファイル名を表示する部分とに分けられ、また、付随機能として画像情報を表示するツールチップを保持します。クラスのデザインは以下の通り、ユーザーコントロール上に二つの Label と ToolTip を配置します。

コントロール(クラス)機能
・ LB1(Label)縮小画像の表示
・ LL1(LinkLabel)ファイル名の表示
・ TIP1(ToolTip)画像情報の表示用

 ここでは画像の表示にラベルを使用しますが、ユーザーコントロール上に直接描画したり、PictureBox を配置して描画する方法など様々考えられます。以下は、各コントロールのプロパティのうち、変更を加えた箇所です。

ImageTile ... BackColor : White
LB1 ... Dock : Fill / Text : ""
LL1 ... Dock : Bottom / Text : "" / TextAlign : TopCenter
| ▲TOP |

●サムネールの作成
 ImageTile クラスで定義する変数はひとつ、ファイル名を格納する m_path のみです。また、記述する関数は以下の三つです。
関数種類機能
・ Newコンストラクタ(オーバーロード)ファイル名とサムネールサイズから初期化
・ SetImageユーザー定義イメージやテキストを取得して配置
・ LL1_Clickイベント元画像を表示するサブフォームを起動
 LL1_Click 関数内には 元画像を表示する SubForm クラスの記述が含まれます。SubForm クラスの未定義の内容については次回に扱います。
ImageTile.vb (フォームデザイナのコードは省略しています)
' 内部変数
Private m_path As String      ' ファイル名

' コンストラクタ(パス名を指定)
Public Sub New(ByVal path As String, ByVal size As Integer)
    MyBase.New()
    InitializeComponent()
    SetImage(path, size)        ' 画像の取得
End Sub

' イメージの設定(引数 : ファイルパス、サムネールサイズ) Public Sub SetImage(ByVal path As String, ByVal size As Integer) m_path = path ' ファイルのパスを変数に格納 Dim fRate As Double ' 縮尺 Dim nWidth, nHeight As Integer ' 画像サイズ Dim oImage As Image = Bitmap.FromFile(m_path) ' イメージリソース ' コントロールのサイズの設定 Me.Size = New Size(size, size + LL1.Height) ' 画像サイズの取得 With oImage If .Width <= size AndAlso .Height <= size Then ' 画像が表示領域よりも小さい時 nWidth = .Width nHeight = .Height ElseIf .Width >= .Height Then ' 幅 >= 高さ の時 fRate = .Height / .Width nWidth = size nHeight = CInt(size * fRate) Else ' 幅 < 高さ の時 fRate = .Width / .Height nWidth = CInt(size * fRate) nHeight = size End If End With ' サムネールの設定 Dim oThumbnail As Image _ = oImage.GetThumbnailImage(nWidth, nHeight, Nothing, IntPtr.Zero) If Not IsNothing(LB1.Image) Then LB1.Image.Dispose() LB1.Image = oThumbnail ' ファイル名の設定 LL1.Text = IO.Path.GetFileNameWithoutExtension(m_path) ' ツールチップの設定 Dim strTip As String = IO.Path.GetFileName(m_path) & vbCrLf _ & "W" & oImage.Width & "×H" & oImage.Height & vbCrLf _ & Format(FileLen(m_path), "#,#") & " バイト" TIP1.SetToolTip(LB1, strTip) ' リソースの開放 oImage.Dispose() End Sub
' リンクラベルのクリック Private Sub LL1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles LL1.Click If IO.File.Exists(m_path) Then ' 別フォームに元画像を表示 Dim oForm As New SubForm(m_path) oForm.Show() End If End Sub
| ▲TOP |

●画像サイズの設定
 サムネールのサイズは、メインフォームのメニューで選択できるようにします。ここでは、大中小、三つのサイズを設定していますが、コード上では Enum列挙体で定義を行っています。
 また、サイズの値の保持は、内部変数 m_size を定義して保持し、値の設定とメニュー項目へのチェックの管理は SetImageSize関数を設置して行います。
MainForm.vb
' 内部変数/定数
Private m_size As Integer         ' イメージのサイズ

' 列挙体 : イメージ一辺の長さ(単位:ピクセル)
Enum ImageSize As Integer
    Large = 128   ' 大きいサイズ
    Medium = 96  ' 普通サイズ
    Small = 64     ' 小さいサイズ
End Enum

' イメージサイズの選択
Private Sub SetImageSize(ByVal size As ImageSize)
    ' 現在チェックの付いているサイズメニュー : Static で値を保持
    Static CheckedItem As MenuItem = Nothing

    ' 現在チェック中のメニューのチェックをはずす
    If Not IsNothing(CheckedItem) Then CheckedItem.Checked = False

    ' チェックを付けるメニューを格納
    Select Case size
        Case ImageSize.Large : CheckedItem = mnSizeL
        Case ImageSize.Medium : CheckedItem = mnSizeM
        Case ImageSize.Small : CheckedItem = mnSizeS
    End Select

    CheckedItem.Checked = True    ' メニューにチェックを付ける
    m_size = size                            ' サイズを変数に格納
End Sub   

' 表示メニュー : サイズメニューのクリック Private Sub mnSizeL_Click(ByVal sender As Object, ByVal e As EventArgs) _ Handles mnSizeL.Click SetImageSize(ImageSize.Large) ' 大きいサイズ End Sub Private Sub mnSizeM_Click(ByVal sender As Object, ByVal e As EventArgs) _ Handles mnSizeM.Click SetImageSize(ImageSize.Medium) ' 普通のサイズ End Sub Private Sub mnSizeS_Click(ByVal sender As Object, ByVal e As EventArgs) _ Handles mnSizeS.Click SetImageSize(ImageSize.Small) ' 小さいサイズ End Sub
| ▲TOP |

●画像一覧の表示
 メインフォーム側のパネルに関するコードを記述していきます。流れは、

 @ ツリービューのダブルクリック (TV1_DoubleClick関数) で、フォルダが選択された後、
 A フォルダ内の画像ファイルの配列を取得 (GetImageFiles関数) し、
 B サムネールを取得してパネルに追加 (SetImageTiles関数)、
 この時発生するパネルのレイアウトイベント (PN1_Layout関数) で、
 C 列数を算出して、サムネールを配置する、

という手順となります。以下が、今回追加する関数です。
関数種類機能
・ SetImageTilesユーザー定義パネルにサムネールを一覧表示
・ GetImageFilesユーザー定義フォルダ内の画像ファイルの配列の取得
・ PN1_Layoutイベント列数の算出 / サムネールの再配置
 なお、今回のレイアウトは、可変レイアウトとなります。パネルのサイズが変更されるたびに列数が計算され、自動的にサムネールが再配置されます。Layout イベントは、サイズの変更時だけでなく、子コントロールが追加・削除された時などにも発生します。
MainForm.vb
' 内部変数/定数
Private m_col As Integer          ' 列数
Private m_path As String          ' 現在のパス名
Const nSpaceX As Integer = 8  ' イメージ同士の間隔(よこ)
Const nSpaceY As Integer = 4  ' イメージ同士の間隔(たて)

' SetImageTiles : 画像の一覧表示 Private Sub SetImageTiles(ByVal folder As String) ' ファイルが存在しない時は処理を中止 If IO.Directory.Exists(folder) = False Then Exit Sub m_path = folder ' フォルダ名を変数に格納 ' パネル内のコントロールをクリア PN1.Controls.Clear() ' 画像ファイルの配列を取得 Dim aFiles As String() = GetImageFiles(folder) If IsNothing(aFiles) Then Exit Sub ' イメージ(サムネール)を取得してパネルに追加 Dim i As Integer For i = 0 To aFiles.Length - 1 Cursor.Current = Cursors.WaitCursor Dim oTile As New ImageTile(aFiles(i), m_size) PN1.Controls.Add(oTile) SBP2.Text = (i + 1).ToString & "/" & aFiles.Length & " 読込中" ' 読込状況の表示 Application.DoEvents() ' 待機中のイベントを処理 Next ' ステータスバーパネルに情報を表示 SBP1.Text = "[" & IO.Path.GetFullPath(folder) & "]" ' パス名 SBP2.Text = "画像数 : " & i.ToString ' 画像数 Cursor.Current = Cursors.Default End Sub
' GetImageFiles : イメージファイルの取得 Public Shared Function GetImageFiles(ByVal folder As String) As String() Dim aExt As String() = {".bmp", ".jpg", ".jpeg", ".gif", ".png", ".ico"} ' 拡張子の配列 Dim sFile As String ' ファイル名 Dim aFile As String() ' ファイルの配列 Dim n As Integer = -1 ' 配列のサイズ Dim i As Integer For Each sFile In IO.Directory.GetFiles(folder) For i = 0 To aExt.Length - 1 ' 画像の拡張子とファイル属性をチェックして配列に加える ' ここでは隠し属性 (Hidden) のファイルを除いています If StrComp(IO.Path.GetExtension(sFile), aExt(i), CompareMethod.Text) = 0 _ AndAlso (GetAttr(sFile) And FileAttribute.Hidden) <> FileAttribute.Hidden Then n += 1 ReDim Preserve aFile(n) aFile(n) = sFile End If Next Next ' ファイルの並び替え If Not IsNothing(aFile) Then Array.Sort(aFile) Return aFile End Function
' パネルのレイアウトイベント Private Sub PN1_Layout(ByVal sender As Object, ByVal e As LayoutEventArgs) _ Handles PN1.Layout ' 列数の算出 (小数点を切り捨てて Integer型にキャスト) m_col = CInt(Fix(PN1.ClientSize.Width / (m_size + nSpaceX))) If m_col < 1 Then m_col = 1 ' 1未満の時は1列に設定 ' コントロールの再配置 Dim i As Integer For i = 0 To PN1.Controls.Count - 1 ' 位置の設定 (現在のスクロール位置も考慮) With PN1.Controls(i) .Left = (i Mod m_col) * (.Width + nSpaceX) + PN1.AutoScrollPosition.X .Top = (i \ m_col) * (.Height + nSpaceY) + PN1.AutoScrollPosition.Y End With Next End Sub

 表示メニューの [再読み込み] とロードメニューを以下のように記述した上で、画像のあるフォルダをダブルクリックして、画像一覧が上図のように表示されれば今回は成功です。(ImageTile.vb の LL1_Click 関数はコメントアウトしておく)
' 表示メニュー : 「再読み込み」
Private Sub mnReload_Click(ByVal sender As Object, ByVal e As EventArgs) _
            Handles mnReload.Click
    SetImageTiles(m_path)        ' 一覧画像の再表示
End Sub

' フォームのロード
Protected Overrides Sub OnLoad(ByVal e As EventArgs)
    GetDrives()                                   ' ツリービューの表示
    SetImageSize(ImageSize.Medium)    ' サイズメニューの選択
End Sub

| ■HOME | ◆プログラムTop | ▲ページの先頭 |