Webセミナー「アンドキュメンテッド(?) VCL 〜逆引きVCL新機能〜」自己フォロー
QAで指摘があった件を試してみました。
TListViewのグルーピングがうまくいかなかった件
本当は、こんな感じに表示されるはずでした。
テストは、64bit版のWindows 7でテーマ有効。実機はWindows 7の32bit版。この辺の差異かな…。
TDirectory.GetFilesでファイル属性を取得する
TDirectory.GetFilesはファイル名だけかと思いきや、無名メソッドを使用するバージョンで属性とか取れるという指摘があったので試してみました。
結果をフィルタリングするために使われる TFilterPredicate オプションがあって、そこで属性を取得。
Delphiのサンプルはこんな感じ。
procedure TForm1.Button1Click(Sender: TObject); var Dir : String; Root: WideString; Files: TStringDynArray; FilterPredicate: TDirectory.TFilterPredicate; begin Dir := GetMyDocumentsPath(CSIDL_PERSONAL); if SelectDirectory('フォルダを選択してください。', Root, Dir, [sdNewUI]) then Edit1.Text := Dir; with Memo1 do begin Clear; Lines.BeginUpdate; // ファイルを検索 Files := TDirectory.GetFiles(Edit1.Text, '*.pas', TSearchOption.soAllDirectories, function(const Path: string; const SearchRec: TSearchRec): Boolean begin Lines.Add(Format('Path = %s Size = %d', [Path + SearchRec.Name, SearchRec.Size])); Result := true; end ); Lines.EndUpdate; end; end;
引数に無名メソッドを渡し、その中でファイルの属性を取得する。
C++Builderの場合は無名メソッドをコンパイラがサポートしていないので、TCppInterfacedObject
class Filter : public TCppInterfacedObject<TDirectory::TFilterPredicate> { public: bool __fastcall Invoke(const System::UnicodeString Path, const Sysutils::TSearchRec &SearchRec) { UnicodeString s = Format("Path = %s Size = %d", ARRAYOFCONST((Path + SearchRec.Name, SearchRec.Size))); Form1->Memo1->Lines->Append(s); return true; } }; //--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { wchar_t DirPath[MAX_PATH]; ::SecureZeroMemory(DirPath, sizeof(DirPath)); ::SHGetFolderPath(0, CSIDL_PERSONAL, 0, 0, DirPath); UnicodeString Dir(DirPath); if (::SelectDirectory(L"フォルダを選択してください。", "//", Dir, TSelectDirExtOpts() << sdNewUI)) { Edit1->Text = Dir; Memo1->Clear(); Memo1->Lines->BeginUpdate(); // ファイルを検索 Filter* filter = new Filter(); TDirectory::GetFiles(Edit1->Text, "*.cpp", TSearchOption::soAllDirectories, filter); // delete filter; // deleteは不要 Memo1->Lines->EndUpdate(); } }
フィルタリングを行うクラスのインスタンスはnewで初期化する必要があるが、明示的にdeleteする必要が無い。
ちなみに、C++11のラムダ式*1がC++Builderに実装されたら、こんな感じになるのかな…。
TDirectory::GetFiles(Edit1->Text, "*.cpp", TSearchOption::soAllDirectories, [this](const System::UnicodeString Path, const Sysutils::TSearchRec &SearchRec) { UnicodeString s = Format("Path = %s Size = %d", ARRAYOFCONST((Path + SearchRec.Name, SearchRec.Size))); Memo1->Lines->Append(s); return true; });
ああ、滅茶苦茶便利。
*1:C++Builder XE3(?)でC++11のラムダ式サポートまだぁ?(AA略