在运行时{J}创建和释放TPanel中的FMX组件

时间:2017-03-24 10:27:03

标签: delphi firemonkey

以下错误仅在MacOS下进行测试时发生。在Windows下它似乎工作。我正在尝试将一个动态的字符串列表显示到TPanel中,每个都在它自己的TPanel中。字符串列表保存在TStringList对象中,每次添加或删除新字符串时,我都会通过清除存在的内容来调用显示更新显示的方法,然后重新构建可视组件。更新面板显示方法如下所示:

procedure TTestsScreen.UpdatePanelDisplay3;
var
  i : Integer;
  myPanel : TPanel;
  myLabel : TLabel;
  myImage : TImage;
begin
  //dispose of existig entities
  for i := (Length(search_entities_labels) - 1) downto 0 do
  begin
    search_entities_labels[i].Free;
    search_entities_labels[i]:= nil;
  end;
  for i := (Length(search_entities_images) - 1) downto 0 do
  begin
    search_entities_images[i].Free;
    search_entities_images[i]:= nil;
  end;
  for i := (Length(search_entities_panels) - 1) downto 0 do
  begin
    search_entities_panels[i].Free;
    search_entities_panels[i]:= nil;
  end;
  //adjust dynamic arrays
  SetLength(search_entities_images,main_search_entities_string_list.Count);
  SetLength(search_entities_labels,main_search_entities_string_list.Count);
  SetLength(search_entities_panels,main_search_entities_string_list.Count);
  //rebuild
  for i := 0 to main_search_entities_string_list.Count-1 do
  begin
    myPanel:= TPanel.Create(Self);
    myPanel.Parent := Panel1;
    myPanel.Height:= 30;
    myPanel.Width:= Panel1.Width;
    myPanel.Position.X:= 0;
    myPanel.Position.Y:= i*30;
    search_entities_panels[i]:= myPanel;
    //
    myLabel:= TLabel.Create(Self);
    myLabel.Parent:= myPanel;
    myLabel.Text:= main_search_entities_string_list[i];
    myLabel.Width:= (3*myPanel.Width) / 4;//display left
    search_entities_labels[i]:= myLabel;
    //
    myImage:= TImage.Create(Self);
    myImage.Parent:= myPanel;
    myImage.Tag:= i;
    myImage.Width:= 15;
    myImage.Height:= 15;
    myImage.Position.X:= myPanel.Width - myImage.Width;//display right
    myImage.MultiResBitmap.Assign(AppResources.delete_white_image.MultiResBitmap);
    myImage.OnClick:= DeleteSearchEntity;
    search_entities_images[i]:= myImage;
  end;
  //
  Panel1.Height:= 30 * main_search_entities_string_list.Count;
end;

我在面板中添加了新元素,如下所示:

procedure TTestsScreen.AddClick(Sender: TObject);
begin
  main_search_entities_string_list.Add(DateTimeToStr(now));
  UpdatePanelDisplay3;
end;

添加过程正常,没有错误。问题是当我尝试删除像这样的元素时

procedure TTestsScreen.DeleteSearchEntity(Sender: TObject);
begin
  main_search_entities_string_list.Delete((Sender as TImage).Tag);
  UpdatePanelDisplay3;
end;

我随机获得

Runtime error 231 

Exception EAccessViolation in module TestApp at 00039F33.
Access violation at address 00E7BBBC, accessing address 00000158.
Runtime error   0 at 00039F33 

在我正在做的FormCreate事件中

procedure TTestsScreen.FormCreate(Sender: TObject);
begin
  SetLength(search_entities_labels,0);
  SetLength(search_entities_images,0);
  SetLength(search_entities_panels,0);
  main_search_entities_string_list:= TStringList.Create;
end;

数组声明为

search_entities_labels : array of TLabel;
search_entities_images : array of TImage;
search_entities_panels : array of TPanel;

2 个答案:

答案 0 :(得分:4)

您不应该从组件本身调用的事件处理程序中释放组件。在这种情况下,您可以从其OnClick事件处理程序中释放TImage。

您必须分两个阶段分割此操作。

阶段1

在事件处理程序中,您要么为表单排队消息,要么只将组件集(图像,标签和面板)标记为"待删除" 。您可以通过多种方式执行此操作...将要删除的组件列表或索引保存到包含它们的数组或TObjectList中。

第2阶段

在表单中,当你有时间时,你最终释放不需要的组件。您可以在收到排队的消息时执行此操作(如果您选择了该技术),或者您可以使用Application.OnIdle(如果您只是标记它们以进行删除)。

另一个通知......我谈到了排队的消息,这是恕我直言的最佳解决方案。请注意标准FireMonkey消息不是以异步方式排队,而是以同步方式立即分派。所以他们无法解决你的问题......你必须使用TThread.Queue来消除这个问题。

答案 1 :(得分:0)

使用以下方法创建这些控件时

myPanel:= TPanel.Create(Self)

self表示该表单拥有该控件,因此您无法对其进行免费调用,因为父母(面板)并不知道它已消失。 / p>

您想要将其更改为面板。