Search code examples
delphitobjectlist

objectlist not retrieving data


I load some images into an object list , and then try to recall them. But its not showing the image?

procedure TForm1.LoadImages(const Dir: string);
var
  i: Integer;
  CurFileName: string;
  JpgIn: TJPEGImage;
  BmpOut: TBitmap;
begin
//sets index for object list
  CurIdx := -1;
  i := 0;
  while True do
  begin
//gets current folder 
    CurFileName := Format('%s%d.jpg',
                          [IncludeTrailingPathDelimiter(Dir), i]);
    if not FileExists(CurFileName) then
      Break;
//creates jpgin
    JpgIn := TJPEGImage.Create;
    try
//loads jpgin 
      JpgIn.LoadFromFile(CurFileName);
//creates TBitmap and sets width to same as jpgs
      BmpOut := TBitmap.Create;
      bmpout.Width := jpgin.Width;
      bmpout.Height := jpgin.Height;
     try
         BmpOut.Assign(JpgIn);
//if i assign it here it works, showing last image of course
         //zimage1.Bitmap.Width := bmpout.Width;
        //zimage1.Bitmap.Height := bmpout.Height;
         //ZImage1.Bitmap.Assign(bmpout);
//adds 1 to index for object list. thus starting at 0
         curIdx := curIdx+1;
//add bitmap to objectlist
         CurIdx:= mylist.Add(TBitmap(bmpout));
      finally
//free bitmap and jpg
        BmpOut.Free;
      end;
    finally
      JpgIn.Free;
    end;
    Inc(i);
  end;
//makes sure cout is above 0  
  if mylist.Count > 0 then
  begin
//create bitmap
    BmpOut := TBitmap.Create;
      try
//sets width and heigh of bitmap before getting image
      bmpout.Height := TBitmap(mylist[curidx]).Height;
      bmpout.Width := TBitmap(mylist[curidx]).Width;
      bmpout.Assign(TBitmap(mylist[CurIdx]));
//sets zimage width height before getting image.
      zimage1.Bitmap.Width := bmpout.Width;
      zimage1.Bitmap.Height := bmpout.Height;
      ZImage1.Bitmap.Assign(bmpout);
    finally
      BmpOut.Free;
    end;
  end;
  page:= '0';
end;

if you notice i had this part in there to see if loading the iamge into the zimage1 was an issue.

     //zimage1.Bitmap.Width := bmpout.Width;
    //zimage1.Bitmap.Height := bmpout.Height;
     //ZImage1.Bitmap.Assign(bmpout);

when i did that, it loaded bmpout into the zimage1 which leads me to think its something with the object list that iam doing wrong?


Solution

  • You have this code:

      CurIdx:= mylist.Add(TBitmap(bmpout));
    finally
      //free bitmap and jpg
      BmpOut.Free;
    end;
    

    You add an item to the list, and then you immediately free that very same item. TList and its descendants like TObjectList do not make a "deep copy" of the objects they hold.

    When you later read the contents of the list, what you're getting are stale references. They no longer refer to the objects they originally referred to, and they probably don't refer to any object at all. The memory at those locations might still contain data structured to look like those former objects, but there's no guarantee of that. There's no guarantee your program won't crash, either. A crash is typical, but the next most common behavior is for your program to exhibit subtle errors, such as continuing to run but not displaying the expected data.


    If you want a list of objects, then don't free them; get rid of the finally block I quoted above. To be exception-safe, you'll want to carefully transfer ownership from the current code block to the list, like this:

    BmpOut := TBitmap.Create;
    try
      BmpOut.Assign(JpgIn);
      CurIdx := mylist.Add(bmpout);
    except
      BmpOut.Free;
      raise;
    end;
    

    If an exception occurs during the Assign or Add calls, then the local procedure should free the bitmap. Otherwise, the list acquires ownership of the object, and freeing the list will implicitly free all its objects (assuming the list's OwnsObjects property is True).

    Once you've loaded all the bitmaps and stored them in the list, there's no real need to create another bitmap just to have something to assign to your image control. You can just use the one you've stored in the list:

    if mylist.Count > 0 then
    begin
      ZImage1.Bitmap.Assign(mylist[mylist.Count - 1]);
    end;
    

    From that code, you can see that you don't even need to keep track of CurIdx. Its value will always be the index of the last added object, and that index will always be one less than the total number of objects in the list.

    You also don't have to set a bitmap's height and width prior to assigning it a value from another graphic object. It will automatically acquire the dimensions of the source object.