Link to home
Start Free TrialLog in
Avatar of hush021299
hush021299

asked on

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.
Avatar of DragonSlayer
DragonSlayer
Flag of Malaysia image

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;
Avatar of hush021299
hush021299

ASKER

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.
ASKER CERTIFIED SOLUTION
Avatar of DragonSlayer
DragonSlayer
Flag of Malaysia image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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?
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.
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!?
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.
> and you put this control onto your Form manually

I meant to say, "and you put this control onto your Form visually"