访问冲突异常的问题是由于Destroy
在已经销毁的对象上调用方法引起的。让我解释一下情况。
想象一下,您有 3 个带有下一个索引的选项卡和Browsers
带有以下浏览器实例的数组:
ChromeTabs.Tabs Browsers
---------------------- ----------------------
Index Tab name Index Browser
---------- ---------- ---------- ----------
0 Tab 1 0 Browser 1
1 Tab 2 1 Browser 2
2 Tab 3 2 Browser 3
现在单击中间选项卡的关闭按钮(索引为 1 的选项卡)并在其中OnButtonCloseTabClick
运行:
procedure TForm1.ChromeTabsButtonCloseTabClick(Sender: TObject;
ATab: TChromeTab; var Close: Boolean);
begin
// the ATab.Index equals 1
Browsers[ATab.Index].Destroy;
Close := True;
end;
Browser 2
这将破坏从上表调用的浏览器实例。Tabs
当数组像集合一样被重新索引时,这不会是问题。让我们看看选项卡和您的数组会发生什么:
ChromeTabs.Tabs Browsers
---------------------- ----------------------
Index Tab name Index Browser
---------- ---------- ---------- ----------
0 Tab 1 0 Browser 1
1 Tab 3 1 --- <-- dangling pointer
2 Browser 3
如您所见,Tabs
关闭第二个选项卡后,集合已被重新索引,但您的数组没有。您刚刚销毁了对象实例,但来自该被销毁对象的悬空指针仍然存在,在同一个索引上。
现在,如果您再次单击第二个选项卡(名为 的选项卡Tab 3
)的关闭按钮,您将在事件处理程序中运行与以前完全相同的代码:
procedure TForm1.ChromeTabsButtonCloseTabClick(Sender: TObject;
ATab: TChromeTab; var Close: Boolean);
begin
// as before, the ATab.Index equals 1, but this time you'll get AV
// since object from element Browsers[1] has been destroyed before
// and now that element contains just dangling pointer
Browsers[ATab.Index].Destroy; // <--
Close := True;
end;
但是这次你会遇到访问冲突,因为Browsers[1]
元素中的对象之前已经被销毁了。
对于您的目的不是数组正确的集合类型。我建议您使用TObjectList<T>
泛型对象列表集合。使用该集合,我会以这种方式重写您的代码:
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
System.Generics.Collections, ChromeTabs, ChromeTabsClasses, cefvcl;
type
TForm1 = class(TForm)
ChromeTabs1: TChromeTabs;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure ChromeTabs1ButtonAddClick(Sender: TObject;
var Handled: Boolean);
procedure ChromeTabs1ButtonCloseTabClick(Sender: TObject;
ATab: TChromeTab; var Close: Boolean);
procedure ChromeTabs1ActiveTabChanging(Sender: TObject; AOldTab,
ANewTab: TChromeTab; var Allow: Boolean);
private
FBrowsers: TObjectList<TChromium>;
public
{ Public declarations }
end;
var
Form1: TForm1;
Tab_Closed:Boolean=False;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
// create instance of the object list and let it manage
// lifetime of the inserted objects
FBrowsers := TObjectList<TChromium>.Create;
FBrowsers.OwnsObjects := True;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
// release the object list
FBrowsers.Free;
end;
procedure TForm1.ChromeTabs1ButtonAddClick(Sender: TObject;
var Handled: Boolean);
var
ChromiumInstance: TChromium;
begin
// create an instance of the browser component and
// initiliaze its properties - here it's simplified
ChromiumInstance := TChromium.Create(nil);
ChromiumInstance.Parent := Self;
ChromiumInstance.SetBounds(8, 8, 150, 150);
// now add the new browser instance to the collection
FBrowsers.Add(ChromiumInstance);
end;
procedure TForm1.ChromeTabs1ButtonCloseTabClick(Sender: TObject;
ATab: TChromeTab; var Close: Boolean);
begin
// delete the browser instance from the collection; since we've
// assigned True to the OwnsObjects property of the collection,
// we don't need to care of freeing the browser instance
FBrowsers.Delete(ATab.Index);
// allow the tab to close
Close := True;
//and fix tab close
Tab_Closed:=True;
end;
procedure TForm1.ChromeTabs1ActiveTabChanging(Sender: TObject; AOldTab,
ANewTab: TChromeTab; var Allow: Boolean);
begin
// check if there's an "old tab" and if so, check also if we have its
// index in the range of our collection; if so, then hide the browser
if Assigned(AOldTab) and (AOldTab.Index < FBrowsers.Count) then
FBrowsers[AOldTab.Index].Visible := False;
// and show the activated tab browser
If((ChromeTabs.Tabs.Count<>1)) Then
Begin
If((ANewTab.Index=(ChromeTabs.Tabs.Count-1)) AND Tab_Closed=True) Then
FBrowsers[AOldTab.Index].Visible := True
Else
FBrowsers[ANewTab.Index].Visible := True;
End
Else FBrowsers[ANewTab.Index].Visible := True;
//Now Tab is not closed
Tab_Closed:=False;
end;
end.