|
ファイルの検索、列挙1
今回は、あるディレクトリの中のファイルやディレクトリを1つずつ取得(列挙)していく方法を見ていきます。エクスプローラのようなアプリを作る場合はこれが要になります。
今回はちょっとだけ手の込んだ次のようなものを作ってみます。

リストコントロールにファイルとディレクトリ一覧を表示し、ディレクトリがダブルクリックされたらそのディレクトリに移動します。「上へ」ボタンが押されたら親ディレクトリに移動します。ファイルやディレクトリにはアイコンも表示させます。エディットボックスにはカレントディレクトリを表示します。
エクスプローラの原型のようなものですね。これだけでCドライブの中を自由に移動できます。
今回のメインテーマはファイル列挙の部分ですが、他の章で解説している知識も動員していきます。「ボタンの基本」「エディットボックスの基本」「リストコントロールの基本」「アイテムにユーザデータを付加する」「アイテムにアイコンをつける」を見ていない方はまずそちらを先に見てください。
では、ダイアログを作りましょう。リストコントロールは「View」を「レポート」に、「Sort」を「昇順」に、カレントディレクトリ表示用のエディットボックスは「Read Only」を「True」にしておきます。

次はDDX変数を追加します。エディットボックスはValue型の変数を、リストコントロールはControl型の変数を追加しましょう。
CString m_xvEditPath;
CListCtrl m_xcList;
|
次はアイコン用のイメージリストをダイアログのメンバ変数に追加しておきます。
次はイベントハンドラです。「上へ」ボタンは「BN_CLICKED」のハンドラを、リストコントロールは「NM_DBLCLK」のハンドラを追加します。このハンドラはリストアイテムがダブルクリックされたときに呼び出されます。
これで下準備が整いました。では、コードの方を実装していきましょう。まずはOnInitDialog()での初期化処理です。
BOOL CFileFindDlg::OnInitDialog()
{
CDialog::OnInitDialog();
SetIcon(m_hIcon, TRUE); // 大きいアイコンの設定
SetIcon(m_hIcon, FALSE); // 小さいアイコンの設定
// TODO: 初期化をここに追加します。
{
ListInit();
m_xvEditPath = _T("C:\\");
Refresh();
UpdateData(FALSE);
}
return TRUE;
}
|
ListInit()、Refresh()は後述する自作関数です。ListInit()はリストコントロールの初期化、Refresh()はリストの内容を最新の状態に更新します。カレントディレクトリの初期値はCドライブのルートに設定しています。
では、リストコントロール初期化関数です。
// リストコントロール初期化
int CFileFindDlg::ListInit(void)
{
LVCOLUMN lvc;
TCHAR caption[32] = _T("名前");
int err = 0;
// イメージリストの初期化
if (!err) if (!m_imageList.Create(16, 16, ILC_COLOR24, 2, 1)) err = 1;
// イメージリストをリストコントロールにセット
if (!err) m_xcList.SetImageList(&m_imageList, LVSIL_SMALL);
// カラム作成
if (!err)
{
lvc.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; // 有効フラグ
lvc.iSubItem = 0; // サブアイテム番号
lvc.pszText = caption; // 見出しテキスト
lvc.cx = 300; // 横幅
if (m_xcList.InsertColumn(0, &lvc) == -1) err = 1;
}
return err;
}
|
今回はカラムを一つだけ作成しています。CImageList::Create()関数でイメージリストを初期化します。レポートビューなので、アイコンの大きさは16x16になります。色数は規定のILC_COLORだと16色までしか表示できないので、ILC_COLOR24を指定します。
では、次は表示を更新するRefresh()関数を見てみましょう。
// 表示更新
int CFileFindDlg::Refresh()
{
CFileFind finder;
BOOL bWorking = finder.FindFile(m_xvEditPath +_T("*"));
CString str;
int err = 0;
ListDeleteItem();
// カレントディレクトリのファイルを検索
while (bWorking)
{
bWorking = finder.FindNextFile();
if (finder.IsDots()) continue;
err = ListInsertItem(finder.GetFilePath(),
finder.GetFileName(), finder.IsDirectory());
}
finder.Close();
return err;
}
|
ここが今回のメインであるディレクトリの中のファイルを列挙する部分です。ListDeleteItem()、ListInsertItem()は後述する自作の関数です。ListDeleteItem()はリストアイテムの全削除、ListInsertItem()はリストアイテムを1つ追加します。
ファイルの列挙にはCFileFindクラスを使います。最初にCFileFind::FindFile()関数で検索するパスを指定します。これはワイルドカードを使って指定します。
| virtual BOOL CFileFind::FindFile(LPCTSTR pstrName = NULL, DWORD dwUnused = 0); |
| 説明: |
ファイル検索を開始 |
| 引数: |
pstrName:検索するファイル名 |
| 戻り値: |
正常終了した場合は0以外。それ以外の場合は0 |
次にCFileFind::FindNextFile()関数を呼び出すごとに1つずつファイルが取得されます。FindNextFile()関数は最後のファイルを取得したときに0を返します。
| virtual BOOL CFileFind::FindNextFile(); |
| 説明: |
次のファイル検索する |
| 引数: |
なし |
| 戻り値: |
まだファイルがある場合は0以外。ディレクトリ内の最後のファイルを取得した場合やエラーが発生した場合は0 |
取得できるファイルには"."(カレントディレクトリ)と".."(親ディレクトリ)が含まれます。今回の場合はこの2つは必要ありません。取得したファイルがこの2つかどうかは、CFileFind::IsDots()関数で判断できます。
| virtual BOOL CFileFind::IsDots() const; |
| 説明: |
取得したファイルが"."または".."であるかどうかを判断する |
| 引数: |
なし |
| 戻り値: |
取得したファイルが"."または".."である場合は0以外。それ以外の場合は0 |
取得したファイルのパスはCFileFind::GetFilePath()関数で、ファイル名はCFileFind::GetFileName()関数で、ディレクトリかどうかはCFileFind::IsDirectory()関数でそれぞれ取得できます。
| virtual CString CFileFind::GetFilePath() const; |
| 説明: |
取得したファイルのファイルパスを取得 |
| 引数: |
なし |
| 戻り値: |
ファイルパス |
| virtual CString CFileFind::GetFileName() const; |
| 説明: |
取得したファイルのファイル名を取得 |
| 引数: |
なし |
| 戻り値: |
ファイル名 |
| BOOL CFileFind::IsDirectory() const; |
| 説明: |
取得したファイルがディレクトリであるかどうかを判断する |
| 引数: |
なし |
| 戻り値: |
取得したファイルがディレクトリである場合は0以外。それ以外の場合は0 |
ということで、今回はここで一区切りにしましょう。次回はリストアイテムの追加関数から解説していきます。
|