以下错误仅在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;
答案 0 :(得分:4)
您不应该从组件本身调用的事件处理程序中释放组件。在这种情况下,您可以从其OnClick事件处理程序中释放TImage。
您必须分两个阶段分割此操作。
阶段1
在事件处理程序中,您要么为表单排队消息,要么只将组件集(图像,标签和面板)标记为"待删除" 。您可以通过多种方式执行此操作...将要删除的组件列表或索引保存到包含它们的数组或TObjectList中。
第2阶段
在表单中,当你有时间时,你最终释放不需要的组件。您可以在收到排队的消息时执行此操作(如果您选择了该技术),或者您可以使用Application.OnIdle(如果您只是标记它们以进行删除)。
另一个通知......我谈到了排队的消息,这是恕我直言的最佳解决方案。请注意标准FireMonkey消息不是以异步方式排队,而是以同步方式立即分派。所以他们无法解决你的问题......你必须使用TThread.Queue来消除这个问题。
答案 1 :(得分:0)
使用以下方法创建这些控件时
myPanel:= TPanel.Create(Self)
self
表示该表单拥有该控件,因此您无法对其进行免费调用,因为父母(面板)并不知道它已消失。 / p>
您想要将其更改为面板。