Jump to content
limelect

Listview data problem

Recommended Posts

I hope I explained my problem  with the listview

I have 2 pictures and 2 text

Adding text ,the text items is OK, but

Adding 2 pictures is the problem

 

  PListItemData = ^TListItemData;

  TListItemData = record
    theString: string;
    ThePicture: TBitmap;
  end;
b: Tbitmap; <<<< is created at oncreat.

var
  ClipItem: TListItem;

ListItemData: PListItemData;

 

 while not FDQuery2.Eof do
  begin
------ process Query

ClipItem := lvClip.Items.Insert(0);

  New(ListItemData);

    try
      ListItemData.theString := s.Text;  <<< OK
     if ContainsText(s.Text, 'Picture') then
       begin
         b.Assign(nil);
        BlobField := FDQuery2.FieldByName('Image') as TBlobField;
            Stream := FDQuery2.CreateBlobStream(BlobField, bmRead);<<< read the picture

        b.LoadFromStream(Stream);
        ListItemData.ThePicture := TBitmap(b); <<<< get also the picture
        FreeAndNil(Stream);
      end;
      ClipItem.Data := ListItemData;

    except
      Dispose(ListItemData);
    end;
    FDQuery2.Next;
  end;

No problem, no leak BUT !!!! Now to the problem of looping twice

 

PListItemData(lvClip.Items[0].data).ThePicture <<<< first picture
PListItemData(lvClip.Items[0].data).TheString <<< first text OK

Second time in the loop

PListItemData(lvClip.Items[1].data).ThePicture <<< got second picture
PListItemData(lvClip.Items[1].data).TheString <<< second text OK

But now PListItemData(lvClip.Items[0].data).ThePicture got the second picture

 

SO, more explanation. The first item got the second picture!!! But the text is OK it has 2 texts no problem

 

On the breakpoint, I see the watch list as

PListItemData(lvClip.Items[0].data).ThePicture
PListItemData(lvClip.Items[0].data).TheString

PListItemData(lvClip.Items[1].data).ThePicture
PListItemData(lvClip.Items[1].data).TheString



         

Share this post


Link to post

All of your list items are pointing at a single TBitmap object in memory, so all of them will show the last image that was loaded from the DB.  If you want to show a separate image for each list item, they each need their own TBitmap object, eg:

type
  PListItemData = ^TListItemData;
  TListItemData = record
    theString: string;
    ThePicture: TBitmap;
  end;

...

procedure TMyForm.RunQueryAndFillListView;
var
  ClipItem: TListItem;
  ListItemData: PListItemData;
begin
  ...
  while not FDQuery2.Eof do
  begin
    ...
    ClipItem := lvClip.Items.Insert(0);
    New(ListItemData);
    try
      ListItemData.theString := s.Text;
      ListItemData.ThePicture := nil;
      if ContainsText(s.Text, 'Picture') then
      begin
        BlobField := FDQuery2.FieldByName('Image') as TBlobField;
        Stream := FDQuery2.CreateBlobStream(BlobField, bmRead);
        try
          ListItemData.ThePicture := TBitmap.Create;
          ListItemData.ThePicture.LoadFromStream(Stream);
        finally
          Stream.Free;
        end;
      end;
      ClipItem.Data := ListItemData;
    except
      ListItemData.ThePicture.Free;
      Dispose(ListItemData);
    end;
    FDQuery2.Next;
  end;
  ...
end;

...

// TListView.OnDeletion event handler
procedure TMyForm.lvClipDeletion(Sender: TObject; Item: TListItem);
var
  ListItemData: PListItemData;
begin
  ListItemData := PListItemData(Item.Data);
  if ListItemData <> nill then
  begin
    ListItemData.ThePicture.Free;
    Dispose(ListItemData);
  end;
end;

 

Edited by Remy Lebeau

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×