【问题标题】:Why do I get an access violation when assigning a JPEG to an array of TJPEGImages?为什么将 JPEG 分配给 TJPEGImages 数组时会出现访问冲突?
【发布时间】:2017-04-07 14:58:57
【问题描述】:
  Formulae: array [1..6] of TJPEGImage;

我有一个数组,我想将图像分配到其中,以便将它们显示到表单上。我使用了来自JPEG data-stream to TImage 问题的类似代码,但我在 if 语句中收到了访问冲突错误消息

procedure Tfrm_calc2.ChangeDisplay(ImgNo: Integer; NewImage: Boolean);
var
  TempImg: TJPEGImage;
begin
  TempImg:= TJPEGImage.Create;
  TempImg.LoadFromFile('C2F'+inttostr(ImgNo)+'.jpg');
  img_Formulae.Picture.Assign(TempImg);

 // assigning each picture to an element in array if it is the first time. This will be used to save the pictures later on
  If NewImage = True then Formulae[ImgNo].Assign(TempImg);


  TempImg.Free;
  ImgDisplayed:= ImgNo;

  lbl_FormulaDisplay.Caption:= 'Formula ' + inttostr(ImgNo); //user can see which formula can be seen
end;

谢谢。

【问题讨论】:

  • Formulae 数组是否包含初始化的TJpegImage 对象?
  • Assign 方法将信息从一个实例传输到另一个实例。它不会创建新实例。公式数组的元素需要在某处实例化。
  • 不,它没有,我该怎么做?
  • 除了提出的解决方案之外,我建议您研究泛型的使用...在大多数情况下,TObjectList 可能是比数组更好的解决方案。这并不能避免在调用它们的 Assign 方法之前初始化对象;)

标签: delphi jpeg access-violation assign timage


【解决方案1】:

在调用Assign 之前,您是否使用分配的对象填充了数组?可能不是。尝试更多类似的方法:

procedure Tfrm_calc2.ChangeDisplay(ImgNo: Integer);
var
  TempImg: TJPEGImage;
begin
  TempImg := TJPEGImage.Create;
  try
    TempImg.LoadFromFile('C2F'+IntToStr(ImgNo)+'.jpg');
    img_Formulae.Picture.Assign(TempImg);

    if Formulae[ImgNo] = nil then
    begin
      Formulae[ImgNo] := TempImg;
      TempImg := nil;
    end else
      Formulae[ImgNo].Assign(TempImg);
  finally
    TempImg.Free;
  end;
  ImgDisplayed := ImgNo;
  lbl_FormulaDisplay.Caption := 'Formula ' + IntToStr(ImgNo);
end;

或者:

procedure Tfrm_calc2.ChangeDisplay(ImgNo: Integer);
var
  TempImg: TJPEGImage;
begin
  TempImg := TJPEGImage.Create;
  try
    TempImg.LoadFromFile('C2F'+IntToStr(ImgNo)+'.jpg');
    img_Formulae.Picture.Assign(TempImg);

    FreeAndNil(Formulae[ImgNo]);
    Formulae[ImgNo] := TempImg;
  except
    TempImg.Free;
    raise;
  end;
  ImgDisplayed := ImgNo;
  lbl_FormulaDisplay.Caption := 'Formula ' + IntToStr(ImgNo);
end;

【讨论】:

  • 请问第二个代码中的“FreeAndNil”和“raise”行是做什么的?
  • @astudent 这两个都是琐碎的事情,在文档中有详细的解释。
【解决方案2】:

Formulae[ImgNo].Assign(TempImg);

这是试图将图片分配给一个已经创建的对象。但是,您的对象很可能尚未创建,因为我看不到在上面的代码中初始化它们的方法。 Assign 要求对象已经创建

在您的情况下,理想的做法是在启动时,确保提前在数组中创建所有这些对象。然后,还要确保在关闭时销毁它们。

你的整个代码可以简单到...

procedure Tfrm_calc2.FormCreate(Sender: TObject);
var
  I: Integer;
begin
  for I := Low(Formulae) to High(Formulae) do begin
    Formulae[I] := TJpegImage.Create;
  end;
end;

procedure Tfrm_calc2.FormDestroy(Sender: TObject);
var
  I: Integer;
begin
  for I := Low(Formulae) to High(Formulae) do begin
    FreeAndNil(Formulae[I]);
  end;
end;

procedure Tfrm_calc2.ChangeDisplay(ImgNo: Integer);
begin
  Formulae[ImgNo].LoadFromFile('C2F'+IntToStr(ImgNo)+'.jpg');
  ImgDisplayed:= ImgNo;
  lbl_FormulaDisplay.Caption:= 'Formula ' + IntToStr(ImgNo);
end;

无需加载另一个实例并分配它。直接加载文件即可。

【讨论】:

  • 我明白了。谢谢 我是怎么初始化的呢?我只做 Formulae[i].Create 吗?
  • @astudent 不,这是不正确的。 Formulae[i] := TJPEGImage.Create; 是您需要在循环中执行的操作,例如在表单的构造函数中。析构函数中的完全相反以释放它们。
  • @student no,请改用Formulae[i] := TJpegImage.Create;
【解决方案3】:

来自 Embarcadero VCL 参考

调用Assign复制一个对象的属性或其他属性 来自另一个。

所以必须在调用Assign之前创建目标类

另一个建议是先创建一个 TJpegImage 类的实例,然后将其分配给您的临时 TJpegImage,如下所示:

var
 JPegArray : array[0..10] of TJPEGImage;

...

var
 JPeg : TJPEGImage;
begin
 JPeg := TJPEGImage.Create;
 JPeg.LoadFromFile('C:/M.jpg');

 JPegArray[1] := TJPEGImage.Create;
 JPegArray[1].Assign(JPeg);

 JPeg.Free;

 Image1.Picture.Assign(JPegArray[1]);

 ...

end;

【讨论】:

  • 这是一个糟糕的解决方案,因为如果数组元素中已经有一个对象实例化,它会泄漏内存。特别是对于像图像这样的内存密集型的东西,内存泄漏是一个关键问题。
  • 这是一个例子,知道你要分配的对象,必须先创建。您提到的问题将在为数组项创建 TJPEGImage 之前使用 IF 语句解决
  • 如果它们只是在启动时创建的,那么就无需担心这些。就像JPegArray[i].LoadFromFile('C:\M.jpg'); 一样简单,而且您的代码将JPegArray 直接放在本地过程的范围内。
猜你喜欢
  • 2023-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多