Thumbnail browser based on TListView: DoubleClick event

I did this component.
Now I want this listview derivat to react on my mouseclicks and give me the possibilitie to
getselected file
select all files
=>

unit ThumbListView;

interface

uses
  SysUtils, Classes, Controls, Graphics, jpeg, ComCtrls;

type
  TThumbListView = class(TListView)
  private
    { Private declarations }
    sl:tstringlist;
    FSelFile:string;
    IL:TImagelist;
    procedure LoadAndConvert(B: TBitmap; FileName: string);
    procedure ListFiles(F: string);
    procedure ListView1DblClick(Sender: TObject);
    function getSelFile: String;
    procedure setSelFile(const Value: String);
    procedure ListView1Change(Sender: TObject; Item: TListItem;
      Change: TItemChange);
  protected
    { Protected declarations }
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;

    { Public declarations }

  published
    { Published declarations }
    property OnClick;
    property OnDblClick;
    property SelectedFile:String  read getSelFile write setSelFile;
    procedure ListThumbItems(Dir:String);
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Hushpage', [TThumbListView]);
end;

{ tlistview1 }

constructor TThumbListView.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  IL:=TImagelist.create(self);
  SL:=TStringlist.create;
  LargeImages:=IL;
  il.Width:=96;
  il.height:=96;
end;

destructor TThumbListView.Destroy;
begin

 // sl.free;
  //IL.Free;

  inherited;
end;
procedure TThumbListView.ListView1DblClick(Sender: TObject);
begin



end;
procedure TThumbListView.ListView1Change(Sender: TObject; Item: TListItem;
  Change: TItemChange);
begin  inherited;
 if SelCount>0 then
FSelFile:=Selected.SubItems[0];
setSelFile(FSelFile);
end;
procedure TThumbListView.ListFiles(F: string);
var
    sr: TSearchRec;
    path, fullpath: string;
begin
    path :=includetrailingbackslash(f);
    fullpath := path + '*.*';
    if findfirst(fullpath, faAnyFile, sr) = 0 then
        repeat
            begin
                if (lowercase(extractfileext(path + '\' + sr.Name)) =
                '.jpg') or
                (lowercase(extractfileext(path + '\' + sr.Name)) =
                '.bmp')
                 then

                sl.add(path  + sr.Name);
            end;
        until FindNext(sr) <> 0;
    FindClose(sr);

end;

procedure TThumbListView.ListThumbItems(Dir: String);
var x: integer; s: string;
    b, k: string; BM, TBM: TBitmap; LI: TListitem;
begin

    bm := tbitmap.create;
    Tbm := tbitmap.create;
    sl := TStringlist.create;
    Items.BeginUpdate;
   
    try
    Clear;
    il.Clear;
    ListFiles(Dir);
        for x := 0 to sl.count - 1 do
        begin
           k:=sl.strings[x];
            if fileexists(k) then
            begin
                LoadAndConvert(bm, k);
                tbm.Width := 96;
                tbm.Height := 96;
                tbm.Canvas.StretchDraw(rect(0, 0, tbm.Width, tbm.height), bm);
                il.Add(Tbm, nil);
            //add to listview
                li := items.add;
                li.caption:=extractfilename(k);
                LI.SubItems.Add(k);
                LI.ImageIndex := x;
            end;
        end;
    finally
        sl.free;
        bm.free; tbm.free;
        Items.EndUpdate;
    end;
end;

procedure TThumbListView.LoadAndConvert(B: TBitmap; FileName: string);
var ex: string; J: TJPEGImage;
//load file and if jpge then convert to bitmap
begin
    ex := uppercase(extractfileext(filename));
    if ex = '.BMP' then
        B.LoadFromFile(filename) else
        if ex = '.JPG' then
        begin
            j := TJpegimage.Create;
            try
                j.LoadFromFile(filename);
                B.Assign(j);
            finally
                j.Free;
            end;
        end;

end;

function TThumbListView.getSelFile: String;
begin
result:=FselFile;
end;

procedure TThumbListView.setSelFile(const Value: String);
begin
fSelFile:=Value;
end;

end.
LVL 1
hush021299Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

DragonSlayerCommented:
And how would you like it to be done? As in, how would you like the results returned? a TStringList? or something else?

And to select all, well, all you need to do is to ensure that MultiSelect is True, and then:

procedure TThumbListView.SelectAll;
var
  i: Integer;
begin
  MultiSelect := True; // better put in constructor
  for i := 0 to Items.Count - 1 do
    Items[i].Selected := True;
end;

and similarly:

procedure TThumbListView.DeSelectAll;
var
  i: Integer;
begin
  for i := 0 to Items.Count - 1 do
    Items[i].Selected := False;
end;
0
hush021299Author Commented:
The thing is
I put the thumblistview on the form and give him a directory and it shows the images.
Now I want to click on an image and get the loacation of the selected image in the form.
Therefore I store the full path in listitem.subitems[0] and I have a property named selectedFile.

I would think I select ondbclck of the component when on the form and should be able to write
showmessage(thumblist.selectedfile);

The problems i have here is related to the events. With the component I have it now I dont get anything back. I get the ondblclick but no processing of the commands there.
0
DragonSlayerCommented:
You don't need to do processing at those event handlers.

Remove the OnDblClick and OnChange handlers from your above code, you do not need 'em. Instead, what you do is, modify the getSelFile function to be as follows:

function TThumbListView.getSelFile: string;
begin
  Result := '';
  if Assigned(Selected) then
    Result := Selected.SubItems[0];
end;
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Cloud Class® Course: Ruby Fundamentals

This course will introduce you to Ruby, as well as teach you about classes, methods, variables, data structures, loops, enumerable methods, and finishing touches.

hush021299Author Commented:
Thank you that works fine. I'll give you the points.
Before please help me to understand better how this component acts.

What does it mean:
if tthumblistview.assigned(thumblistview.selected) ?!
is it the same like if selectedcount=1 then..

When will the getSelFile procedure be called!!!?
In on create? or activate? Sometimes I had a problem when assigning values in oncreate. When usually do I assign those values in a component?

I have not freed up the sl and the IL in destroy. If I do this a failure happens. Why is that so?

and finally
I have deleted the ondblclick property. What does this property do in this code?
0
DragonSlayerCommented:
Wow, that's a lot of questions to ask ;-)

1. Well, I used Assigned in this case because if you are enabling MultiSelect, then SelectedCount = 1 doesn't work if the user has selected more than 1 item. Of course, you can also use  if SelectedCount > 0

2. getSelFile will be called whenever the user reads the value of your SelectedFile property.

3. a quick look at your code seems to show no reason why freeing up sl and IL would raise an exception. What exactly is the error message when you free them?

4. OnDblClick property is not necessary in your case because it is already published by the ancestor, TListView.


DragonSlayer.
0
hush021299Author Commented:
Thanks
I've got it all so far.
Unless the error when freeing up sl and iL
If I do not comment out this commands, I 've got an address error when executing a program running this component on destroy.
Why!?
0
DragonSlayerCommented:
A few things to try:

1. change to IL := TImageList.Create(nil);
2. try to comment out IL.Free; then test and see if the problem still occurs with sl.Free, if it does, reverse the process, comment out sl.Free and uncomment IL.Free so that we can find out the culprit?
3. If you installed this component in the Component Tab and you put this control onto your Form manually, then you do not need to Free this ListView in your form's OnDestroy.
0
DragonSlayerCommented:
> and you put this control onto your Form manually

I meant to say, "and you put this control onto your Form visually"
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.