2006. március 1., szerda

Fill a TListView with all files of a given directory along with the system icons


Problem/Question/Abstract:

How to fill a TListView with all files of a given directory along with the system icons

Answer:

Here's some code from a recent project. FileList is a TListView. ScanDir() is a function from our product - it's basically a procedure that fills a TStrings object with a list of files matching a mask. You can ignore the TDirInfo(Node.Data) stuff - it's a small class that holds info on each folder as displayed in a TTreeView.TTreeNode.

This routine builds a TListView that's pretty much like the right pane in Windows Explorer, in that it supports both the list and report view, and displays the file type, size, and modified date in columns in report view.

{Gets files in a folder and displays them in the ListView}

procedure TExplorer.GetFilesInFolder(Node: TTreeNode);
var
  SL: TStringList;
  i: Integer;
  Dat: TDirInfo;
  AllSel: Boolean;
  NewItem: TListItem;
  FI: TSHFileInfo;
  Dt: TDateTime;
  TypeDesc: string;
begin
  if not Assigned(Node) then
    Exit;
  SL := TStringList.Create;
  if Screen.Cursor <> crHourglass then
    Screen.Cursor := crHourglass;
  try
    {Need easier access to Node.Data than TDirInfo(Node.Data) typecasts}
                {Grab a local reference to the pointer}
                Dat := TDirInfo(Node.Data);
    {Get files in this folder, but don't include subfolder files}
    ScanDir(Dat.FullPath, '*.*', SL, False);
    SL.Sorted := True;
    {See if this folder has already been fully selected.
                If so, we don't need to add it to the Folders list or increment selection count
                or bytes}
    AllSel := (Folders.IndexOf(Dat.FullPath) > -1) or (Dat.Status = dsFull);
    {Remove stuff that was previously displayed}
    FileList.Items.BeginUpdate;
    FileList.Items.Clear;
    {Is this an empty folder?}
    if SL.Count = 0 then
    begin
      FileList.SmallImages := StateImages;
      NewItem := FileList.Items.Add;
      NewItem.Caption := ' No files ';
      NewItem.ImageIndex := NoFilesIndex;
      FileList.Enabled := False;
      Exit;
    end;
    FileList.SmallImages := SysImages;
    {We have files. Add each one to the ListView}
    for i := 0 to SL.Count - 1 do
    begin
      {Create a new TListItem}
      NewItem := FileList.Items.Add;
      {Assign the filename portion}
      NewItem.Caption := ExtractFileName(SL[i]);
      FillChar(FI, SizeOf(TSHFileInfo), #0);
      {Get the icon for display, as well as the file type, with one function call.        
                        Note the flags:
      SHGFI_SMALLICON - we want the small icon
      SHGFI_SYSICONINDEX - we want the index into the system imagelist
      SHGFI_TYPENAME - we want the file type description if there is one}
      SHGetFileInfo(PChar(SL[i]), 0, FI, SizeOf(FI), SHGFI_ICON or SHGFI_SMALLICON
        or SHGFI_SYSICONINDEX or SHGFI_TYPENAME);
      {The subitems are only displayed in the 'detail' view, but they have
                  to be there all the time. See if Windows knows what type file this is}
      TypeDesc := FI.szTypeName;
      if TypeDesc = '' then
        {Windows doesn't know - handle like Explorer does}
        TypeDesc := Upper(ExtractFileExt(SL[i])) + ' file';
      {Delete the period if we need to}
      if Length(TypeDesc) > 1 then
      begin
        if TypeDesc[1] = '.' then
          Delete(TypeDesc, 1, 1);
      end;
      {Display the file type description}
      NewItem.SubItems.Add(TypeDesc);
      {Here's the 'Size' column ...}
      NewItem.SubItems.Add(Comma([GetFileSize(SL[i])], False));
      {Assign the system imagelist index to this item}
      NewItem.ImageIndex := FI.iIcon;
      {Grab the file's time and date stamp and convert to Delphi TDateTime}
      Dt := FileDateToDateTime(FileAge(SL[i]));
      {Add the date column}
      NewItem.SubItems.Add(DateToStr(Dt));
      {Add the time column}
      NewItem.SubItems.Add(FormatDateTime('hh:nn:ss ampm', Dt));
      {If folder was fully selected, or this file was selected in a
                        previous visit to this folder, check it}
      if AllSel or (Files.IndexOf(SL[i]) > -1) then
        NewItem.Checked := True;
    end;
    FileList.Enabled := True;
  finally
    SL.Free;
    FileList.Items.EndUpdate;
    if Screen.Cursor <> crDefault then
      Screen.Cursor := crDefault;
  end;
end;

Nincsenek megjegyzések:

Megjegyzés küldése