alancc
alancc

Reputation: 811

Implement Windows Thumbnail via TListView

I am using Delphi XE3 and want to implement Windows Thumbnail style to show a list of images via TListView control.

What I need is like below:

enter image description here

The images are displayed as thumbnail style, there is a caption below each image. And when I click the image, the image together with the caption will be shown as selected...

To improve the performance, I do not want to load all the images into an image list beforehand, instead, I want to load the image when it is to be displayed. Therefore, I am thinking of using OnCustomDrawItem and OnAdvancedCustomDrawItem.

Below is a very simple version of my plan(I set the style of the list view to vsIcon):

    procedure TForm1.FormCreate(Sender: TObject);
    var
      ListItem1: TListItem;
    begin
      ListItem1 := ListView1.Items.Add;

      ListItem1.Caption := 'Chrysanthemum';
    end;

    procedure TForm1.ListView1AdvancedCustomDrawItem(Sender: TCustomListView;
      Item: TListItem; State: TCustomDrawState; Stage: TCustomDrawStage;
      var DefaultDraw: Boolean);
    var
      JPEG: TJPEGImage;
      R: TRect;
    begin
    {
      R := Item.DisplayRect(drBounds);

      JPEG := TJPEGImage.Create;

      JPEG.LoadFromFile('C:\Users\Public\Pictures\Sample Pictures\Chrysanthemum (2).jpg');

      Sender.Canvas.StretchDraw(R, JPEG);
    }
    end;

    procedure TForm1.ListView1CustomDrawItem(Sender: TCustomListView;
      Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
    var
      JPEG: TJPEGImage;
      R: TRect;
    begin
      R := Item.DisplayRect(drBounds);

      JPEG := TJPEGImage.Create;

      JPEG.LoadFromFile('C:\Users\Public\Pictures\Sample Pictures\Chrysanthemum (2).jpg');

      Sender.Canvas.StretchDraw(R, JPEG);
    end;

But the result is not satisfactory, as follows:

  1. I cannot find a way to set the size of each icon. (All icon will have the same size).

  2. I try to put the codes in OnCustomDrawItem and OnAdvancedCustomDrawItem. I cannot figure out much differences between these twos. The only main difference that in Advancedxxx version, the caption is editable. I cannot understand why.

  3. The caption is not displayed under the image, instead, it is in the middle of the image, that is not desired. How to fix that?

Thanks

Upvotes: 1

Views: 1102

Answers (1)

Olaf Hess
Olaf Hess

Reputation: 1483

The attached code loads the images (in this case icons) into the TImageList that is assigned to the LargeImages property of the TListView only when the associated icon actually gets displayed in the listview. The main thing is to set the OwnerData property of the listview to TRUE and to create an event handler for OnData events. Parallel to the items in the listview the program maintains a list of the items in the listview that is in sync with the actual list in the listview, in this case a TStringList. In its Objects property I store the index of the associated icon resource if that has already been loaded and added to the TImageList. If the icon resource has not been loaded, this happens in the LoadIconFromFile function and the index of the icon in the TImageList gets stored in the TStringList.

The actual drawing of the icons and the text in the TListView is fully handled by the control itself, the code does neither handle OnDraw nor any OnCustomDraw* events. Just set the image size in the TImageList to the size of the bitmaps you want to display and create them accordingly.

Older Delphi versions contain a sample project called "VirtualListView.dpr" that is quite helpful to understand when the various OnData* events get fired and how to properly use them.

unit MainFormU;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ImgList, StdCtrls, ComCtrls;

type
  TForm1 = class(TForm)
    Icons_LV: TListView;
    Label1: TLabel;
    Large_IL: TImageList;
    procedure Icons_LVData(Sender: TObject; Item: TListItem);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    FileList : TStringList;

    procedure FillListView;
    function LoadIconFromFile (const sFileName: String;
                               out iIndex: Integer) : Boolean;
  end;

var Form1 : TForm1;

implementation

{$R *.dfm}

uses ShellApi;

const
  cWinSysDir = 'c:\windows\system32\';

procedure TForm1.FormCreate (Sender: TObject);
begin
  FileList := TStringList.Create;
  FillListView;
end;

procedure TForm1.FormDestroy (Sender: TObject);
begin
  FileList.Free;
end;

procedure TForm1.Icons_LVData (Sender: TObject; Item: TListItem);

var iIndex : Integer;

begin
  if (Item.Index >= FileList.Count) then
    exit;

  Item.Caption := FileList [Item.Index];

  if (FileList.Objects [Item.Index] = TObject (-1)) then
  begin
    if not (LoadIconFromFile (cWinSysDir + Item.Caption, iIndex)) then
      iIndex := 0;

    FileList.Objects [Item.Index] := TObject (iIndex);
  end { if }
  else iIndex := Integer (FileList.Objects [Item.Index]);

  Item.ImageIndex := iIndex
end;

procedure TForm1.FillListView;

var SR : TSearchRec;

begin
  FillChar (SR, SizeOf (TSearchRec), #0);

  if (FindFirst (cWinSysDir + '*.exe', faAnyFile, SR) = 0) then
    repeat
      FileList.AddObject (SR.Name, TObject ((-1)));
    until (FindNext (SR) <> 0);

  FindClose (SR);
  Icons_LV.Items.Count := FileList.Count;
end;

function TForm1.LoadIconFromFile (const sFileName: String;
                                  out iIndex: Integer) : Boolean;

var
  hIcon : Windows.HICON;
  Icon : TIcon;

begin
  Result := false;

  if (ExtractIcon (MainInstance, PChar (sFileName), UInt ((-1))) > 0) then
  begin
{$IFDEF DEBUG}
    OutputDebugString (PChar (Format ('LoadIconFromFile "%s"', [sFileName])));
{$ENDIF}
    hIcon := ExtractIcon (MainInstance, PChar (sFileName), 0);

    if (hIcon <> 0) then
    begin
      Icon := TIcon.Create;
      Icon.Handle := hIcon;
      iIndex := Large_IL.AddIcon (Icon);
      Icon.Free;
      Result := true;
    end; { if }
  end { if }
end;

end.

The full example is available for download here.

Upvotes: 5

Related Questions