【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.