【C#】TreeViewとListViewにシステムイメージ(アイコン)を表示する
おはようございます。
昨日に引き続き、Windows Forms で、エクスプローラーのような表示をするために、
今回はファイル・フォルダの横にアイコンを表示してみます。
プログラムは前回のものを流用します。
【C#】TreeView と ListView でエクスプローラーのような画面を作成してみた
スポンサーリンク
目次
プログラムの修正
DLL関数の呼び出し宣言を追加
システムイメージを利用するには「Shll32.dll」、「user32.dll」の関数を呼び出す必要があるため、関数呼び出しの宣言を追加します。
// DllImportに必要 using System.Runtime.InteropServices; /// <summary> /// ファイル情報を取得 /// </summary> /// <param name="pszPath"></param> /// <param name="dwFileAttributes"></param> /// <param name="psfi"></param> /// <param name="cbFileInfo"></param> /// <param name="uFlags"></param> /// <returns></returns> [DllImport("shell32.dll", CharSet = CharSet.Auto)] private static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, out SHFILEINFO psfi, uint cbFileInfo, uint uFlags); /// <summary> /// イメージリストを登録 /// </summary> /// <param name="hWnd"></param> /// <param name="Msg"></param> /// <param name="wParam"></param> /// <param name="lParam"></param> /// <returns></returns> [DllImport("user32.dll", CharSet = CharSet.Auto)] private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
構造体や定数の定義
DLL関数で利用する構造体や定数の定義を追加します。
/// <summary> /// SHGetFileInfo関数で使用する構造体 /// </summary> [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] private struct SHFILEINFO { public IntPtr hIcon; public int iIcon; public uint dwAttributes; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string szDisplayName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)] public string szTypeName; }; // ファイル情報用 private const int SHGFI_LARGEICON = 0x00000000; private const int SHGFI_SMALLICON = 0x00000001; private const int SHGFI_USEFILEATTRIBUTES = 0x00000010; private const int SHGFI_OVERLAYINDEX = 0x00000040; private const int SHGFI_ICON = 0x00000100; private const int SHGFI_SYSICONINDEX = 0x00004000; private const int SHGFI_TYPENAME = 0x000000400; // TreeView用 private const int TVSIL_NORMAL = 0x0000; private const int TVSIL_STATE = 0x0002; private const int TVM_SETIMAGELIST = 0x1109; // ListView用 private const int LVSIL_NORMAL = 0; private const int LVSIL_SMALL = 1; private const int LVM_SETIMAGELIST = 0x1003; // 選択された項目を保持 private String selectedItem = "";
起動時にシステムイメージを登録
起動時の処理で、TreeView、ListViewにイメージのリストを登録します。
/// <summary> /// 起動時の処理 /// </summary> public Form1() { InitializeComponent(); // イメージリストの設定 SHFILEINFO shFileInfo = new SHFILEINFO(); IntPtr imageListHandle = SHGetFileInfo(String.Empty, 0, out shFileInfo, (uint)Marshal.SizeOf(shFileInfo), SHGFI_SMALLICON | SHGFI_SYSICONINDEX); // TreeView SendMessage(treeView1.Handle, TVM_SETIMAGELIST, new IntPtr(TVSIL_NORMAL), imageListHandle); // ListView SendMessage(listView1.Handle, LVM_SETIMAGELIST, new IntPtr(LVSIL_SMALL), imageListHandle); // ドライブ一覧を走査してツリーに追加 foreach (String drive in Environment.GetLogicalDrives()) { // アイコンの取得 int iconIndex = 0; IntPtr hSuccess = SHGetFileInfo(drive, 0, out shFileInfo, (uint)Marshal.SizeOf(shFileInfo), SHGFI_SYSICONINDEX ); if (hSuccess != IntPtr.Zero) { iconIndex = shFileInfo.iIcon; } // 新規ノード作成 // プラスボタンを表示するため空のノードを追加しておく TreeNode node = new TreeNode(drive, iconIndex, iconIndex); node.Nodes.Add(new TreeNode()); treeView1.Nodes.Add(node); } // 初期選択ドライブの内容を表示 setListItem(Environment.GetLogicalDrives().First()); }
ListViewの内容更新時の処理を修正
TreeViewが選択された際にListViewの内容を更新する処理で、
表示するファイル、フォルダ―のイメージを取得して設定します。
/// <summary> /// リストビューの項目を設定します. /// </summary> private void setListItem(String filePath) { // リストビューのヘッダーを設定 listView1.View = View.Details; listView1.Clear(); listView1.Columns.Add("名前"); listView1.Columns.Add("種類"); listView1.Columns.Add("更新日時"); listView1.Columns.Add("サイズ"); try { // フォルダ一覧 DirectoryInfo dirList = new DirectoryInfo(filePath); foreach (DirectoryInfo di in dirList.GetDirectories()) { ListViewItem item = new ListViewItem(di.Name); // フォルダ種類、アイコンの取得 String type = ""; int iconIndex = 0; SHFILEINFO shFileInfo = new SHFILEINFO(); IntPtr hSuccess = SHGetFileInfo(di.FullName, 0, out shFileInfo, (uint)Marshal.SizeOf(shFileInfo), SHGFI_ICON | SHGFI_LARGEICON | SHGFI_SMALLICON | SHGFI_SYSICONINDEX | SHGFI_TYPENAME); if (hSuccess != IntPtr.Zero) { type = shFileInfo.szTypeName; iconIndex = shFileInfo.iIcon; } // 各列の内容を設定 item.ImageIndex = iconIndex; item.SubItems.Add(type); item.SubItems.Add(String.Format("{0:yyyy/MM/dd HH:mm:ss}", di.LastAccessTime)); item.SubItems.Add(""); // リストに追加 listView1.Items.Add(item); } // ファイル一覧 List<String> files = Directory.GetFiles(filePath).ToList<String>(); foreach (String file in files) { FileInfo info = new FileInfo(file); ListViewItem item = new ListViewItem(info.Name); // ファイル種類、アイコンの取得 String type = ""; int iconIndex = 0; SHFILEINFO shinfo = new SHFILEINFO(); IntPtr hSuccess = SHGetFileInfo(info.FullName, 0, out shinfo, (uint)Marshal.SizeOf(shinfo), SHGFI_ICON | SHGFI_LARGEICON | SHGFI_SMALLICON | SHGFI_SYSICONINDEX | SHGFI_TYPENAME); if (hSuccess != IntPtr.Zero) { type = shinfo.szTypeName; iconIndex = shinfo.iIcon; } // 各列の内容を設定 item.ImageIndex = iconIndex; item.SubItems.Add(type); item.SubItems.Add(String.Format("{0:yyyy/MM/dd HH:mm:ss}", info.LastAccessTime)); item.SubItems.Add(getFileSize(info.Length)); listView1.Items.Add(item); } } catch (IOException ie) { MessageBox.Show(ie.Message, "選択エラー"); } // 列幅を自動調整 listView1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize); }
TreeView展開時の処理を修正
同様に TreeView を展開する際の処理で、
フォルダ―のアイコンを取得して設定するように修正します。
/// <summary> /// ツリービュー項目展開時(前)のイベントハンドラ. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void treeView1_BeforeExpand(object sender, TreeViewCancelEventArgs e) { TreeNode node = e.Node; node.Nodes.Clear(); try { DirectoryInfo dirList = new DirectoryInfo(node.FullPath); foreach (DirectoryInfo di in dirList.GetDirectories()) { // フォルダのアイコンを取得 SHFILEINFO shinfo = new SHFILEINFO(); int iconIndex = 0; IntPtr hSuccess = SHGetFileInfo(di.FullName, 0, out shinfo, (uint)Marshal.SizeOf(shinfo), SHGFI_ICON | SHGFI_LARGEICON | SHGFI_SMALLICON | SHGFI_SYSICONINDEX | SHGFI_TYPENAME); if (hSuccess != IntPtr.Zero) { iconIndex = shinfo.iIcon; } // 子を追加してノードを展開 TreeNode child = new TreeNode(di.Name, shinfo.iIcon, shinfo.iIcon); child.ImageIndex = iconIndex; child.Nodes.Add(new TreeNode()); node.Nodes.Add(child); } } catch (IOException ie) { MessageBox.Show(ie.Message, "選択エラー"); } }
起動してみる
無事に TreeView、ListViewにアイコンを表示することができ、
更にエクスプローラーのようなUIになりました。
まとめ
プログラムについては共通化したり、別クラスに処理をまとめたりできるので整理が必要ですが、
ひとまずアイコンを表示する方法を試してみました。
ディスカッション
コメント一覧
お初にお目にかかります.
上記のコードを実装したところ,treeViewの方にはアイコンが表示されたのですが,
listViewの方にはアイコンが表示されませんでした.
item.ImageIndex=iconIndex;
のタイミングでitem.ImageIndexにはー1でない値が入っているのですが,GUI上に反映がされませんでした.
何か記述しなければならないことがあるのでしょうか…?
初歩的なこととは思いますが,ご回答いただけると幸いです.
いしづか様
いつもブログを見ていただきありがとうございます。
ご質問の件、
結構前の記事なので少々お時間をいただければお調べします。
ちなみに環境についてもう少し詳しく教えていただけますか?
よろしくお願いします。
I don’t know how to speak Japanese but I came across your blog and it helped me the most.
I have two questions and it will be a great help if you can answer me.
1. How do I make the Desktop to be the first node of Tree View?
2. Can you show me how to list files in list view when you double click the folder/item?
Thank you very much!
(Google 翻訳)
日本語が話せませんが、あなたのブログに出会い、一番役に立ちました。
2つ質問があるのですが、お答えいただけると大変助かります。
1. デスクトップをツリー ビューの最初のノードにする方法を教えてください。
2. フォルダー/アイテムをダブルクリックしたときにリスト ビューでファイルを一覧表示する方法を教えてください。
どうもありがとうございました!
justWonderWoman 様
ブログを見ていただきありがとうございます。
ご質問の回答ですが、
1の回答は
ドライブを走査する箇所を変更し、
“System.Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory)”
でデスクトップのパスを取得、起点とすればいいと思います。
2の回答は
ダブルクリックイベントを追加し、選択されたファイルを”setListItem” メソッドに渡すことで出来ませんか?
よろしくお願いします。
(Google 翻訳)
justWonderWoman
Thank you for visiting our blog.
The answer to your question,
Answer 1 is
Change where the drive is scanned,
“System.Environment.GetFolderPath (Environment.SpecialFolder.DesktopDirectory)”
Get the desktop path with and use it as the starting point.
Answer 2 is
Is it possible to add a double click event and pass the selected file to the “setListItem” method?
Thank you.